Skip to content

Commit 48cca7e

Browse files
4astborkmann
authored andcommitted
libbpf: add support for bpf_call
- recognize relocation emitted by llvm - since all regular function will be kept in .text section and llvm takes care of pc-relative offsets in bpf_call instruction simply copy all of .text to relevant program section while adjusting bpf_call instructions in program section to point to newly copied body of instructions from .text - do so for all programs in the elf file - set all programs types to the one passed to bpf_prog_load() Note for elf files with multiple programs that use different functions in .text section we need to do 'linker' style logic. This work is still TBD Signed-off-by: Alexei Starovoitov <[email protected]> Acked-by: Daniel Borkmann <[email protected]> Signed-off-by: Daniel Borkmann <[email protected]>
1 parent d98588c commit 48cca7e

File tree

3 files changed

+134
-44
lines changed

3 files changed

+134
-44
lines changed

tools/include/uapi/linux/bpf.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,8 +197,14 @@ enum bpf_attach_type {
197197
*/
198198
#define BPF_F_STRICT_ALIGNMENT (1U << 0)
199199

200+
/* when bpf_ldimm64->src_reg == BPF_PSEUDO_MAP_FD, bpf_ldimm64->imm == fd */
200201
#define BPF_PSEUDO_MAP_FD 1
201202

203+
/* when bpf_call->src_reg == BPF_PSEUDO_CALL, bpf_call->imm == pc-relative
204+
* offset to another bpf function
205+
*/
206+
#define BPF_PSEUDO_CALL 1
207+
202208
/* flags for BPF_MAP_UPDATE_ELEM command */
203209
#define BPF_ANY 0 /* create new element or update existing */
204210
#define BPF_NOEXIST 1 /* create new element if it didn't exist */

tools/lib/bpf/bpf.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ int bpf_create_map_in_map(enum bpf_map_type map_type, const char *name,
4040
__u32 map_flags);
4141

4242
/* Recommend log buffer size */
43-
#define BPF_LOG_BUF_SIZE 65536
43+
#define BPF_LOG_BUF_SIZE (256 * 1024)
4444
int bpf_load_program_name(enum bpf_prog_type type, const char *name,
4545
const struct bpf_insn *insns,
4646
size_t insns_cnt, const char *license,

tools/lib/bpf/libbpf.c

Lines changed: 127 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -174,12 +174,19 @@ struct bpf_program {
174174
char *name;
175175
char *section_name;
176176
struct bpf_insn *insns;
177-
size_t insns_cnt;
177+
size_t insns_cnt, main_prog_cnt;
178178
enum bpf_prog_type type;
179179

180-
struct {
180+
struct reloc_desc {
181+
enum {
182+
RELO_LD64,
183+
RELO_CALL,
184+
} type;
181185
int insn_idx;
182-
int map_idx;
186+
union {
187+
int map_idx;
188+
int text_off;
189+
};
183190
} *reloc_desc;
184191
int nr_reloc;
185192

@@ -234,6 +241,7 @@ struct bpf_object {
234241
} *reloc;
235242
int nr_reloc;
236243
int maps_shndx;
244+
int text_shndx;
237245
} efile;
238246
/*
239247
* All loaded bpf_object is linked in a list, which is
@@ -375,9 +383,13 @@ bpf_object__init_prog_names(struct bpf_object *obj)
375383
size_t pi, si;
376384

377385
for (pi = 0; pi < obj->nr_programs; pi++) {
378-
char *name = NULL;
386+
const char *name = NULL;
379387

380388
prog = &obj->programs[pi];
389+
if (prog->idx == obj->efile.text_shndx) {
390+
name = ".text";
391+
goto skip_search;
392+
}
381393

382394
for (si = 0; si < symbols->d_size / sizeof(GElf_Sym) && !name;
383395
si++) {
@@ -405,7 +417,7 @@ bpf_object__init_prog_names(struct bpf_object *obj)
405417
prog->section_name);
406418
return -EINVAL;
407419
}
408-
420+
skip_search:
409421
prog->name = strdup(name);
410422
if (!prog->name) {
411423
pr_warning("failed to allocate memory for prog sym %s\n",
@@ -795,6 +807,8 @@ static int bpf_object__elf_collect(struct bpf_object *obj)
795807
} else if ((sh.sh_type == SHT_PROGBITS) &&
796808
(sh.sh_flags & SHF_EXECINSTR) &&
797809
(data->d_size > 0)) {
810+
if (strcmp(name, ".text") == 0)
811+
obj->efile.text_shndx = idx;
798812
err = bpf_object__add_program(obj, data->d_buf,
799813
data->d_size, name, idx);
800814
if (err) {
@@ -856,11 +870,14 @@ bpf_object__find_prog_by_idx(struct bpf_object *obj, int idx)
856870
}
857871

858872
static int
859-
bpf_program__collect_reloc(struct bpf_program *prog,
860-
size_t nr_maps, GElf_Shdr *shdr,
861-
Elf_Data *data, Elf_Data *symbols,
862-
int maps_shndx, struct bpf_map *maps)
873+
bpf_program__collect_reloc(struct bpf_program *prog, GElf_Shdr *shdr,
874+
Elf_Data *data, struct bpf_object *obj)
863875
{
876+
Elf_Data *symbols = obj->efile.symbols;
877+
int text_shndx = obj->efile.text_shndx;
878+
int maps_shndx = obj->efile.maps_shndx;
879+
struct bpf_map *maps = obj->maps;
880+
size_t nr_maps = obj->nr_maps;
864881
int i, nrels;
865882

866883
pr_debug("collecting relocating info for: '%s'\n",
@@ -893,8 +910,10 @@ bpf_program__collect_reloc(struct bpf_program *prog,
893910
GELF_R_SYM(rel.r_info));
894911
return -LIBBPF_ERRNO__FORMAT;
895912
}
913+
pr_debug("relo for %ld value %ld name %d\n",
914+
rel.r_info >> 32, sym.st_value, sym.st_name);
896915

897-
if (sym.st_shndx != maps_shndx) {
916+
if (sym.st_shndx != maps_shndx && sym.st_shndx != text_shndx) {
898917
pr_warning("Program '%s' contains non-map related relo data pointing to section %u\n",
899918
prog->section_name, sym.st_shndx);
900919
return -LIBBPF_ERRNO__RELOC;
@@ -903,6 +922,17 @@ bpf_program__collect_reloc(struct bpf_program *prog,
903922
insn_idx = rel.r_offset / sizeof(struct bpf_insn);
904923
pr_debug("relocation: insn_idx=%u\n", insn_idx);
905924

925+
if (insns[insn_idx].code == (BPF_JMP | BPF_CALL)) {
926+
if (insns[insn_idx].src_reg != BPF_PSEUDO_CALL) {
927+
pr_warning("incorrect bpf_call opcode\n");
928+
return -LIBBPF_ERRNO__RELOC;
929+
}
930+
prog->reloc_desc[i].type = RELO_CALL;
931+
prog->reloc_desc[i].insn_idx = insn_idx;
932+
prog->reloc_desc[i].text_off = sym.st_value;
933+
continue;
934+
}
935+
906936
if (insns[insn_idx].code != (BPF_LD | BPF_IMM | BPF_DW)) {
907937
pr_warning("bpf: relocation: invalid relo for insns[%d].code 0x%x\n",
908938
insn_idx, insns[insn_idx].code);
@@ -924,6 +954,7 @@ bpf_program__collect_reloc(struct bpf_program *prog,
924954
return -LIBBPF_ERRNO__RELOC;
925955
}
926956

957+
prog->reloc_desc[i].type = RELO_LD64;
927958
prog->reloc_desc[i].insn_idx = insn_idx;
928959
prog->reloc_desc[i].map_idx = map_idx;
929960
}
@@ -962,28 +993,77 @@ bpf_object__create_maps(struct bpf_object *obj)
962993
return 0;
963994
}
964995

996+
static int
997+
bpf_program__reloc_text(struct bpf_program *prog, struct bpf_object *obj,
998+
struct reloc_desc *relo)
999+
{
1000+
struct bpf_insn *insn, *new_insn;
1001+
struct bpf_program *text;
1002+
size_t new_cnt;
1003+
1004+
if (relo->type != RELO_CALL)
1005+
return -LIBBPF_ERRNO__RELOC;
1006+
1007+
if (prog->idx == obj->efile.text_shndx) {
1008+
pr_warning("relo in .text insn %d into off %d\n",
1009+
relo->insn_idx, relo->text_off);
1010+
return -LIBBPF_ERRNO__RELOC;
1011+
}
1012+
1013+
if (prog->main_prog_cnt == 0) {
1014+
text = bpf_object__find_prog_by_idx(obj, obj->efile.text_shndx);
1015+
if (!text) {
1016+
pr_warning("no .text section found yet relo into text exist\n");
1017+
return -LIBBPF_ERRNO__RELOC;
1018+
}
1019+
new_cnt = prog->insns_cnt + text->insns_cnt;
1020+
new_insn = realloc(prog->insns, new_cnt * sizeof(*insn));
1021+
if (!new_insn) {
1022+
pr_warning("oom in prog realloc\n");
1023+
return -ENOMEM;
1024+
}
1025+
memcpy(new_insn + prog->insns_cnt, text->insns,
1026+
text->insns_cnt * sizeof(*insn));
1027+
prog->insns = new_insn;
1028+
prog->main_prog_cnt = prog->insns_cnt;
1029+
prog->insns_cnt = new_cnt;
1030+
}
1031+
insn = &prog->insns[relo->insn_idx];
1032+
insn->imm += prog->main_prog_cnt - relo->insn_idx;
1033+
pr_debug("added %zd insn from %s to prog %s\n",
1034+
text->insns_cnt, text->section_name, prog->section_name);
1035+
return 0;
1036+
}
1037+
9651038
static int
9661039
bpf_program__relocate(struct bpf_program *prog, struct bpf_object *obj)
9671040
{
968-
int i;
1041+
int i, err;
9691042

9701043
if (!prog || !prog->reloc_desc)
9711044
return 0;
9721045

9731046
for (i = 0; i < prog->nr_reloc; i++) {
974-
int insn_idx, map_idx;
975-
struct bpf_insn *insns = prog->insns;
1047+
if (prog->reloc_desc[i].type == RELO_LD64) {
1048+
struct bpf_insn *insns = prog->insns;
1049+
int insn_idx, map_idx;
9761050

977-
insn_idx = prog->reloc_desc[i].insn_idx;
978-
map_idx = prog->reloc_desc[i].map_idx;
1051+
insn_idx = prog->reloc_desc[i].insn_idx;
1052+
map_idx = prog->reloc_desc[i].map_idx;
9791053

980-
if (insn_idx >= (int)prog->insns_cnt) {
981-
pr_warning("relocation out of range: '%s'\n",
982-
prog->section_name);
983-
return -LIBBPF_ERRNO__RELOC;
1054+
if (insn_idx >= (int)prog->insns_cnt) {
1055+
pr_warning("relocation out of range: '%s'\n",
1056+
prog->section_name);
1057+
return -LIBBPF_ERRNO__RELOC;
1058+
}
1059+
insns[insn_idx].src_reg = BPF_PSEUDO_MAP_FD;
1060+
insns[insn_idx].imm = obj->maps[map_idx].fd;
1061+
} else {
1062+
err = bpf_program__reloc_text(prog, obj,
1063+
&prog->reloc_desc[i]);
1064+
if (err)
1065+
return err;
9841066
}
985-
insns[insn_idx].src_reg = BPF_PSEUDO_MAP_FD;
986-
insns[insn_idx].imm = obj->maps[map_idx].fd;
9871067
}
9881068

9891069
zfree(&prog->reloc_desc);
@@ -1026,7 +1106,6 @@ static int bpf_object__collect_reloc(struct bpf_object *obj)
10261106
Elf_Data *data = obj->efile.reloc[i].data;
10271107
int idx = shdr->sh_info;
10281108
struct bpf_program *prog;
1029-
size_t nr_maps = obj->nr_maps;
10301109

10311110
if (shdr->sh_type != SHT_REL) {
10321111
pr_warning("internal error at %d\n", __LINE__);
@@ -1040,11 +1119,9 @@ static int bpf_object__collect_reloc(struct bpf_object *obj)
10401119
return -LIBBPF_ERRNO__RELOC;
10411120
}
10421121

1043-
err = bpf_program__collect_reloc(prog, nr_maps,
1122+
err = bpf_program__collect_reloc(prog,
10441123
shdr, data,
1045-
obj->efile.symbols,
1046-
obj->efile.maps_shndx,
1047-
obj->maps);
1124+
obj);
10481125
if (err)
10491126
return err;
10501127
}
@@ -1197,6 +1274,8 @@ bpf_object__load_progs(struct bpf_object *obj)
11971274
int err;
11981275

11991276
for (i = 0; i < obj->nr_programs; i++) {
1277+
if (obj->programs[i].idx == obj->efile.text_shndx)
1278+
continue;
12001279
err = bpf_program__load(&obj->programs[i],
12011280
obj->license,
12021281
obj->kern_version);
@@ -1859,40 +1938,45 @@ long libbpf_get_error(const void *ptr)
18591938
int bpf_prog_load(const char *file, enum bpf_prog_type type,
18601939
struct bpf_object **pobj, int *prog_fd)
18611940
{
1862-
struct bpf_program *prog;
1941+
struct bpf_program *prog, *first_prog = NULL;
18631942
struct bpf_object *obj;
18641943
int err;
18651944

18661945
obj = bpf_object__open(file);
18671946
if (IS_ERR(obj))
18681947
return -ENOENT;
18691948

1870-
prog = bpf_program__next(NULL, obj);
1871-
if (!prog) {
1872-
bpf_object__close(obj);
1873-
return -ENOENT;
1874-
}
1875-
1876-
/*
1877-
* If type is not specified, try to guess it based on
1878-
* section name.
1879-
*/
1880-
if (type == BPF_PROG_TYPE_UNSPEC) {
1881-
type = bpf_program__guess_type(prog);
1949+
bpf_object__for_each_program(prog, obj) {
1950+
/*
1951+
* If type is not specified, try to guess it based on
1952+
* section name.
1953+
*/
18821954
if (type == BPF_PROG_TYPE_UNSPEC) {
1883-
bpf_object__close(obj);
1884-
return -EINVAL;
1955+
type = bpf_program__guess_type(prog);
1956+
if (type == BPF_PROG_TYPE_UNSPEC) {
1957+
bpf_object__close(obj);
1958+
return -EINVAL;
1959+
}
18851960
}
1961+
1962+
bpf_program__set_type(prog, type);
1963+
if (prog->idx != obj->efile.text_shndx && !first_prog)
1964+
first_prog = prog;
1965+
}
1966+
1967+
if (!first_prog) {
1968+
pr_warning("object file doesn't contain bpf program\n");
1969+
bpf_object__close(obj);
1970+
return -ENOENT;
18861971
}
18871972

1888-
bpf_program__set_type(prog, type);
18891973
err = bpf_object__load(obj);
18901974
if (err) {
18911975
bpf_object__close(obj);
18921976
return -EINVAL;
18931977
}
18941978

18951979
*pobj = obj;
1896-
*prog_fd = bpf_program__fd(prog);
1980+
*prog_fd = bpf_program__fd(first_prog);
18971981
return 0;
18981982
}

0 commit comments

Comments
 (0)