Re: [PATCH bpf-next 2/4] libbpf: Support 32-bit static data loads
From: Y Song <hidden>
Date: 2019-02-15 05:38:59
Also in:
bpf
On Mon, Feb 11, 2019 at 4:48 PM Joe Stringer [off-list ref] wrote:
Support loads of static 32-bit data when BPF writers make use of
convenience macros for accessing static global data variables. A later
patch in this series will demonstrate its usage in a selftest.
As of LLVM-7, this technique only works with 32-bit data, as LLVM will
complain if this technique is attempted with data of other sizes:
LLVM ERROR: Unsupported relocation: try to compile with -O2 or above,
or check your static variable usageA little bit clarification from compiler side. The above compiler error is to prevent people use static variables since current kernel/libbpf does not handle this. The compiler only warns if .bss or .data section has more than one definitions. The first definition always has section offset 0 and the compiler did not warn. The restriction is a little strange. To only work with 32-bit data is not a right statement. The following are some examples. The following static variable definitions will succeed: static int a; /* one in .bss */ static long b = 2; /* one in .data */ The following definitions will fail as both in .bss. static int a; static int b; The following definitions will fail as both in .data: static char a = 2; static int b = 3; Using global variables can prevent compiler errors. maps are defined as globals and the compiler does not check whether a particular global variable is defining a map or not. If you just use static variable like below static int a = 2; without potential assignment to a, the compiler will replace variable a with 2 at compile time. An alternative is to define like below static volatile int a = 2; You can get a "load" for variable "a" in the bpf load even if there is no assignment to a. Maybe now is the time to remove the compiler assertions as libbpf/kernel starts to handle static variables?
quoted hunk ↗ jump to hunk
Based on the proof of concept by Daniel Borkmann (presented at LPC 2018). Signed-off-by: Joe Stringer <redacted> --- tools/lib/bpf/libbpf.c | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-)diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 1ec28d5154dc..da35d5559b22 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c@@ -140,11 +140,13 @@ struct bpf_program { enum { RELO_LD64, RELO_CALL, + RELO_DATA, } type; int insn_idx; union { int map_idx; int text_off; + uint32_t data; }; } *reloc_desc; int nr_reloc;@@ -210,6 +212,7 @@ struct bpf_object { Elf *elf; GElf_Ehdr ehdr; Elf_Data *symbols; + Elf_Data *global_data; size_t strtabidx; struct { GElf_Shdr shdr;@@ -218,6 +221,7 @@ struct bpf_object { int nr_reloc; int maps_shndx; int text_shndx; + int data_shndx; } efile; /* * All loaded bpf_object is linked in a list, which is@@ -476,6 +480,7 @@ static void bpf_object__elf_finish(struct bpf_object *obj) obj->efile.elf = NULL; } obj->efile.symbols = NULL; + obj->efile.global_data = NULL; zfree(&obj->efile.reloc); obj->efile.nr_reloc = 0;@@ -866,6 +871,9 @@ static int bpf_object__elf_collect(struct bpf_object *obj, int flags) pr_warning("failed to alloc program %s (%s): %s", name, obj->path, cp); } + } else if (strcmp(name, ".data") == 0) { + obj->efile.global_data = data; + obj->efile.data_shndx = idx; } } else if (sh.sh_type == SHT_REL) { void *reloc = obj->efile.reloc;@@ -962,6 +970,7 @@ bpf_program__collect_reloc(struct bpf_program *prog, GElf_Shdr *shdr, Elf_Data *symbols = obj->efile.symbols; int text_shndx = obj->efile.text_shndx; int maps_shndx = obj->efile.maps_shndx; + int data_shndx = obj->efile.data_shndx; struct bpf_map *maps = obj->maps; size_t nr_maps = obj->nr_maps; int i, nrels;@@ -1000,8 +1009,9 @@ bpf_program__collect_reloc(struct bpf_program *prog, GElf_Shdr *shdr, (long long) (rel.r_info >> 32), (long long) sym.st_value, sym.st_name); - if (sym.st_shndx != maps_shndx && sym.st_shndx != text_shndx) { - pr_warning("Program '%s' contains non-map related relo data pointing to section %u\n", + if (sym.st_shndx != maps_shndx && sym.st_shndx != text_shndx && + sym.st_shndx != data_shndx) { + pr_warning("Program '%s' contains unrecognized relo data pointing to section %u\n", prog->section_name, sym.st_shndx); return -LIBBPF_ERRNO__RELOC; }@@ -1046,6 +1056,20 @@ bpf_program__collect_reloc(struct bpf_program *prog, GElf_Shdr *shdr, prog->reloc_desc[i].type = RELO_LD64; prog->reloc_desc[i].insn_idx = insn_idx; prog->reloc_desc[i].map_idx = map_idx; + } else if (sym.st_shndx == data_shndx) { + Elf_Data *global_data = obj->efile.global_data; + uint32_t *static_data; + + if (sym.st_value + sizeof(uint32_t) > (int)global_data->d_size) { + pr_warning("bpf relocation: static data load beyond data size %lu\n", + global_data->d_size); + return -LIBBPF_ERRNO__RELOC; + } + + static_data = global_data->d_buf + sym.st_value; + prog->reloc_desc[i].type = RELO_DATA; + prog->reloc_desc[i].insn_idx = insn_idx; + prog->reloc_desc[i].data = *static_data; } } return 0;@@ -1399,6 +1423,12 @@ bpf_program__relocate(struct bpf_program *prog, struct bpf_object *obj) &prog->reloc_desc[i]); if (err) return err; + } else if (prog->reloc_desc[i].type == RELO_DATA) { + struct bpf_insn *insns = prog->insns; + int insn_idx; + + insn_idx = prog->reloc_desc[i].insn_idx; + insns[insn_idx].imm = prog->reloc_desc[i].data; } } --2.19.1