/
loader.c
194 lines (164 loc) · 4.79 KB
/
loader.c
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
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
/* This file excercises the ELF loader.
*/
#include "common.h"
char __license[] __section("license") = "MIT";
#if __clang_major__ >= 9
// Clang < 9 doesn't emit the necessary BTF for this to work.
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 {
__uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
__uint(max_entries, 4096);
} perf_event_array __section(".maps");
#else
struct bpf_map_def hash_map __section("maps") = {
.type = BPF_MAP_TYPE_HASH,
.key_size = sizeof(uint32_t),
.value_size = sizeof(uint64_t),
.max_entries = 1,
.map_flags = BPF_F_NO_PREALLOC,
};
struct bpf_map_def hash_map2 __section("maps") = {
.type = BPF_MAP_TYPE_HASH,
.key_size = sizeof(uint32_t),
.value_size = sizeof(uint64_t),
.max_entries = 2,
};
struct bpf_map_def perf_event_array __section("maps") = {
.type = BPF_MAP_TYPE_PERF_EVENT_ARRAY,
.max_entries = 4096,
};
#endif
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,
};
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);
}
#if __clang_major__ >= 9
static volatile unsigned int key1 = 0; // .bss
static volatile unsigned int key2 = 1; // .data
volatile const unsigned int key3 = 2; // .rodata
static volatile const uint32_t arg; // .rodata, populated by loader
// custom .rodata section, populated by loader
static volatile const uint32_t arg2 __section(".rodata.test");
#endif
__section("xdp") int xdp_prog() {
#if __clang_major__ < 9
unsigned int key1 = 0;
unsigned int key2 = 1;
unsigned int key3 = 2;
uint32_t arg = 1;
uint32_t arg2 = 2;
#endif
map_lookup_elem(&hash_map, (void *)&key1);
map_lookup_elem(&hash_map2, (void *)&key2);
map_lookup_elem(&hash_map2, (void *)&key3);
return static_fn(arg) + global_fn(arg) + arg2;
}
// 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;
}
#if __clang_major__ >= 9
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;
}
#else
__section("socket/3") int data_sections() {
return 0;
}
#endif
/*
* 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;
}