github.com/cilium/ebpf@v0.10.0/testdata/loader.c (about) 1 /* This file excercises the ELF loader. 2 */ 3 4 #include "common.h" 5 6 char __license[] __section("license") = "MIT"; 7 8 #if __clang_major__ >= 9 9 // Clang < 9 doesn't emit the necessary BTF for this to work. 10 struct { 11 __uint(type, BPF_MAP_TYPE_HASH); 12 __type(key, uint32_t); 13 __type(value, uint64_t); 14 __uint(max_entries, 1); 15 __uint(map_flags, BPF_F_NO_PREALLOC); 16 } hash_map __section(".maps"); 17 18 struct { 19 __uint(type, BPF_MAP_TYPE_HASH); 20 __uint(key_size, sizeof(uint32_t)); 21 __uint(value_size, sizeof(uint64_t)); 22 __uint(max_entries, 2); 23 } hash_map2 __section(".maps"); 24 25 struct { 26 __uint(type, BPF_MAP_TYPE_HASH); 27 __type(key, uint32_t); 28 __type(value, uint64_t); 29 __uint(max_entries, 1); 30 __uint(pinning, 1 /* LIBBPF_PIN_BY_NAME */); 31 } btf_pin __section(".maps"); 32 33 // Named map type definition, without structure variable declaration. 34 struct inner_map_t { 35 __uint(type, BPF_MAP_TYPE_HASH); 36 __type(key, uint32_t); 37 __type(value, int); 38 __uint(max_entries, 1); 39 }; 40 41 // Anonymous map type definition with structure variable declaration. 42 struct { 43 __uint(type, BPF_MAP_TYPE_ARRAY_OF_MAPS); 44 __uint(key_size, sizeof(uint32_t)); 45 __uint(max_entries, 1); 46 __array(values, struct inner_map_t); 47 } btf_outer_map __section(".maps"); 48 49 // Array of maps with anonymous inner struct. 50 struct { 51 __uint(type, BPF_MAP_TYPE_ARRAY_OF_MAPS); 52 __uint(key_size, sizeof(uint32_t)); 53 __uint(max_entries, 1); 54 __array( 55 values, struct { 56 __uint(type, BPF_MAP_TYPE_HASH); 57 __uint(max_entries, 1); 58 __type(key, uint32_t); 59 __type(value, uint32_t); 60 }); 61 } btf_outer_map_anon __section(".maps"); 62 63 struct { 64 __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY); 65 __uint(max_entries, 4096); 66 } perf_event_array __section(".maps"); 67 #else 68 struct bpf_map_def hash_map __section("maps") = { 69 .type = BPF_MAP_TYPE_HASH, 70 .key_size = sizeof(uint32_t), 71 .value_size = sizeof(uint64_t), 72 .max_entries = 1, 73 .map_flags = BPF_F_NO_PREALLOC, 74 }; 75 76 struct bpf_map_def hash_map2 __section("maps") = { 77 .type = BPF_MAP_TYPE_HASH, 78 .key_size = sizeof(uint32_t), 79 .value_size = sizeof(uint64_t), 80 .max_entries = 2, 81 }; 82 83 struct bpf_map_def perf_event_array __section("maps") = { 84 .type = BPF_MAP_TYPE_PERF_EVENT_ARRAY, 85 .max_entries = 4096, 86 }; 87 #endif 88 89 struct bpf_map_def array_of_hash_map __section("maps") = { 90 .type = BPF_MAP_TYPE_ARRAY_OF_MAPS, 91 .key_size = sizeof(uint32_t), 92 .max_entries = 2, 93 }; 94 95 static int __attribute__((noinline)) __section("static") static_fn(uint32_t arg) { 96 return arg - 1; 97 } 98 99 int __attribute__((noinline)) global_fn2(uint32_t arg) { 100 return arg + 2; 101 } 102 103 int __attribute__((noinline)) __section("other") global_fn3(uint32_t arg) { 104 return arg + 1; 105 } 106 107 int __attribute__((noinline)) global_fn(uint32_t arg) { 108 return static_fn(arg) + global_fn2(arg) + global_fn3(arg); 109 } 110 111 #if __clang_major__ >= 9 112 static volatile unsigned int key1 = 0; // .bss 113 static volatile unsigned int key2 = 1; // .data 114 volatile const unsigned int key3 = 2; // .rodata 115 static volatile const uint32_t arg; // .rodata, populated by loader 116 // custom .rodata section, populated by loader 117 static volatile const uint32_t arg2 __section(".rodata.test"); 118 #endif 119 120 __section("xdp") int xdp_prog() { 121 #if __clang_major__ < 9 122 unsigned int key1 = 0; 123 unsigned int key2 = 1; 124 unsigned int key3 = 2; 125 uint32_t arg = 1; 126 uint32_t arg2 = 2; 127 #endif 128 map_lookup_elem(&hash_map, (void *)&key1); 129 map_lookup_elem(&hash_map2, (void *)&key2); 130 map_lookup_elem(&hash_map2, (void *)&key3); 131 return static_fn(arg) + global_fn(arg) + arg2; 132 } 133 134 // This function has no relocations, and is thus parsed differently. 135 __section("socket") int no_relocation() { 136 return 0; 137 } 138 139 // Make sure we allow relocations generated by inline assembly. 140 __section("socket/2") int asm_relocation() { 141 int my_const; 142 asm("%0 = MY_CONST ll" : "=r"(my_const)); 143 return my_const; 144 } 145 146 #if __clang_major__ >= 9 147 volatile const unsigned int uneg = -1; 148 volatile const int neg = -2; 149 static volatile const unsigned int static_uneg = -3; 150 static volatile const int static_neg = -4; 151 152 __section("socket/3") int data_sections() { 153 if (uneg != (unsigned int)-1) 154 return __LINE__; 155 156 if (neg != -2) 157 return __LINE__; 158 159 if (static_uneg != (unsigned int)-3) 160 return __LINE__; 161 162 if (static_neg != -4) 163 return __LINE__; 164 165 return 0; 166 } 167 #else 168 __section("socket/3") int data_sections() { 169 return 0; 170 } 171 #endif 172 173 /* 174 * Up until LLVM 14, this program results in an .rodata.cst32 section 175 * that is accessed by 'return values[i]'. For this section, no BTF is 176 * emitted. 'values' cannot be rewritten, since there is no BTF info 177 * describing the data section. 178 */ 179 __section("socket/4") int anon_const() { 180 volatile int ctx = 0; 181 182 // 32 bytes wide results in a .rodata.cst32 section. 183 #define values \ 184 (uint64_t[]) { \ 185 0x0, 0x1, 0x2, 0x3 \ 186 } 187 188 int i; 189 for (i = 0; i < 3; i++) { 190 if (ctx == values[i]) { 191 return values[i]; 192 } 193 } 194 195 return 0; 196 }