197 lines
4.8 KiB
C
197 lines
4.8 KiB
C
/* 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;
|
|
}
|