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