1/* This file excercises the ELF loader.
2 */
3
4#include "common.h"
5
6char __license[] __section("license") = "MIT";
7
8#if __clang_major__ >= 9
9// Clang < 9 doesn't emit the necessary BTF for this to work.
10struct {
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
18struct {
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
25struct {
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.
34struct 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.
42struct {
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.
50struct {
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
63struct {
64 __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
65 __uint(max_entries, 4096);
66} perf_event_array __section(".maps");
67#else
68struct 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
76struct 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
83struct bpf_map_def perf_event_array __section("maps") = {
84 .type = BPF_MAP_TYPE_PERF_EVENT_ARRAY,
85 .max_entries = 4096,
86};
87#endif
88
89struct 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
95static int __attribute__((noinline)) __section("static") static_fn(uint32_t arg) {
96 return arg - 1;
97}
98
99int __attribute__((noinline)) global_fn2(uint32_t arg) {
100 return arg + 2;
101}
102
103int __attribute__((noinline)) __section("other") global_fn3(uint32_t arg) {
104 return arg + 1;
105}
106
107int __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
112static volatile unsigned int key1 = 0; // .bss
113static volatile unsigned int key2 = 1; // .data
114volatile const unsigned int key3 = 2; // .rodata
115static volatile const uint32_t arg; // .rodata, populated by loader
116// custom .rodata section, populated by loader
117static 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
147volatile const unsigned int uneg = -1;
148volatile const int neg = -2;
149static volatile const unsigned int static_uneg = -3;
150static 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[]) { 0x0, 0x1, 0x2, 0x3 }
185
186 int i;
187 for (i = 0; i < 3; i++) {
188 if (ctx == values[i]) {
189 return values[i];
190 }
191 }
192
193 return 0;
194}
View as plain text