Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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 <ast@kernel.org>
Acked-by: Daniel Borkmann <daniel@iogearbox.net>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>

authored by

Alexei Starovoitov and committed by
Daniel Borkmann
48cca7e4 d98588ce

+134 -44
+6
tools/include/uapi/linux/bpf.h
··· 197 197 */ 198 198 #define BPF_F_STRICT_ALIGNMENT (1U << 0) 199 199 200 + /* when bpf_ldimm64->src_reg == BPF_PSEUDO_MAP_FD, bpf_ldimm64->imm == fd */ 200 201 #define BPF_PSEUDO_MAP_FD 1 202 + 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 201 207 202 208 /* flags for BPF_MAP_UPDATE_ELEM command */ 203 209 #define BPF_ANY 0 /* create new element or update existing */
+1 -1
tools/lib/bpf/bpf.h
··· 40 40 __u32 map_flags); 41 41 42 42 /* Recommend log buffer size */ 43 - #define BPF_LOG_BUF_SIZE 65536 43 + #define BPF_LOG_BUF_SIZE (256 * 1024) 44 44 int bpf_load_program_name(enum bpf_prog_type type, const char *name, 45 45 const struct bpf_insn *insns, 46 46 size_t insns_cnt, const char *license,
+127 -43
tools/lib/bpf/libbpf.c
··· 174 174 char *name; 175 175 char *section_name; 176 176 struct bpf_insn *insns; 177 - size_t insns_cnt; 177 + size_t insns_cnt, main_prog_cnt; 178 178 enum bpf_prog_type type; 179 179 180 - struct { 180 + struct reloc_desc { 181 + enum { 182 + RELO_LD64, 183 + RELO_CALL, 184 + } type; 181 185 int insn_idx; 182 - int map_idx; 186 + union { 187 + int map_idx; 188 + int text_off; 189 + }; 183 190 } *reloc_desc; 184 191 int nr_reloc; 185 192 ··· 241 234 } *reloc; 242 235 int nr_reloc; 243 236 int maps_shndx; 237 + int text_shndx; 244 238 } efile; 245 239 /* 246 240 * All loaded bpf_object is linked in a list, which is ··· 383 375 size_t pi, si; 384 376 385 377 for (pi = 0; pi < obj->nr_programs; pi++) { 386 - char *name = NULL; 378 + const char *name = NULL; 387 379 388 380 prog = &obj->programs[pi]; 381 + if (prog->idx == obj->efile.text_shndx) { 382 + name = ".text"; 383 + goto skip_search; 384 + } 389 385 390 386 for (si = 0; si < symbols->d_size / sizeof(GElf_Sym) && !name; 391 387 si++) { ··· 417 405 prog->section_name); 418 406 return -EINVAL; 419 407 } 420 - 408 + skip_search: 421 409 prog->name = strdup(name); 422 410 if (!prog->name) { 423 411 pr_warning("failed to allocate memory for prog sym %s\n", ··· 807 795 } else if ((sh.sh_type == SHT_PROGBITS) && 808 796 (sh.sh_flags & SHF_EXECINSTR) && 809 797 (data->d_size > 0)) { 798 + if (strcmp(name, ".text") == 0) 799 + obj->efile.text_shndx = idx; 810 800 err = bpf_object__add_program(obj, data->d_buf, 811 801 data->d_size, name, idx); 812 802 if (err) { ··· 870 856 } 871 857 872 858 static int 873 - bpf_program__collect_reloc(struct bpf_program *prog, 874 - size_t nr_maps, GElf_Shdr *shdr, 875 - Elf_Data *data, Elf_Data *symbols, 876 - int maps_shndx, struct bpf_map *maps) 859 + bpf_program__collect_reloc(struct bpf_program *prog, GElf_Shdr *shdr, 860 + Elf_Data *data, struct bpf_object *obj) 877 861 { 862 + Elf_Data *symbols = obj->efile.symbols; 863 + int text_shndx = obj->efile.text_shndx; 864 + int maps_shndx = obj->efile.maps_shndx; 865 + struct bpf_map *maps = obj->maps; 866 + size_t nr_maps = obj->nr_maps; 878 867 int i, nrels; 879 868 880 869 pr_debug("collecting relocating info for: '%s'\n", ··· 910 893 GELF_R_SYM(rel.r_info)); 911 894 return -LIBBPF_ERRNO__FORMAT; 912 895 } 896 + pr_debug("relo for %ld value %ld name %d\n", 897 + rel.r_info >> 32, sym.st_value, sym.st_name); 913 898 914 - if (sym.st_shndx != maps_shndx) { 899 + if (sym.st_shndx != maps_shndx && sym.st_shndx != text_shndx) { 915 900 pr_warning("Program '%s' contains non-map related relo data pointing to section %u\n", 916 901 prog->section_name, sym.st_shndx); 917 902 return -LIBBPF_ERRNO__RELOC; ··· 921 902 922 903 insn_idx = rel.r_offset / sizeof(struct bpf_insn); 923 904 pr_debug("relocation: insn_idx=%u\n", insn_idx); 905 + 906 + if (insns[insn_idx].code == (BPF_JMP | BPF_CALL)) { 907 + if (insns[insn_idx].src_reg != BPF_PSEUDO_CALL) { 908 + pr_warning("incorrect bpf_call opcode\n"); 909 + return -LIBBPF_ERRNO__RELOC; 910 + } 911 + prog->reloc_desc[i].type = RELO_CALL; 912 + prog->reloc_desc[i].insn_idx = insn_idx; 913 + prog->reloc_desc[i].text_off = sym.st_value; 914 + continue; 915 + } 924 916 925 917 if (insns[insn_idx].code != (BPF_LD | BPF_IMM | BPF_DW)) { 926 918 pr_warning("bpf: relocation: invalid relo for insns[%d].code 0x%x\n", ··· 954 924 return -LIBBPF_ERRNO__RELOC; 955 925 } 956 926 927 + prog->reloc_desc[i].type = RELO_LD64; 957 928 prog->reloc_desc[i].insn_idx = insn_idx; 958 929 prog->reloc_desc[i].map_idx = map_idx; 959 930 } ··· 994 963 } 995 964 996 965 static int 966 + bpf_program__reloc_text(struct bpf_program *prog, struct bpf_object *obj, 967 + struct reloc_desc *relo) 968 + { 969 + struct bpf_insn *insn, *new_insn; 970 + struct bpf_program *text; 971 + size_t new_cnt; 972 + 973 + if (relo->type != RELO_CALL) 974 + return -LIBBPF_ERRNO__RELOC; 975 + 976 + if (prog->idx == obj->efile.text_shndx) { 977 + pr_warning("relo in .text insn %d into off %d\n", 978 + relo->insn_idx, relo->text_off); 979 + return -LIBBPF_ERRNO__RELOC; 980 + } 981 + 982 + if (prog->main_prog_cnt == 0) { 983 + text = bpf_object__find_prog_by_idx(obj, obj->efile.text_shndx); 984 + if (!text) { 985 + pr_warning("no .text section found yet relo into text exist\n"); 986 + return -LIBBPF_ERRNO__RELOC; 987 + } 988 + new_cnt = prog->insns_cnt + text->insns_cnt; 989 + new_insn = realloc(prog->insns, new_cnt * sizeof(*insn)); 990 + if (!new_insn) { 991 + pr_warning("oom in prog realloc\n"); 992 + return -ENOMEM; 993 + } 994 + memcpy(new_insn + prog->insns_cnt, text->insns, 995 + text->insns_cnt * sizeof(*insn)); 996 + prog->insns = new_insn; 997 + prog->main_prog_cnt = prog->insns_cnt; 998 + prog->insns_cnt = new_cnt; 999 + } 1000 + insn = &prog->insns[relo->insn_idx]; 1001 + insn->imm += prog->main_prog_cnt - relo->insn_idx; 1002 + pr_debug("added %zd insn from %s to prog %s\n", 1003 + text->insns_cnt, text->section_name, prog->section_name); 1004 + return 0; 1005 + } 1006 + 1007 + static int 997 1008 bpf_program__relocate(struct bpf_program *prog, struct bpf_object *obj) 998 1009 { 999 - int i; 1010 + int i, err; 1000 1011 1001 1012 if (!prog || !prog->reloc_desc) 1002 1013 return 0; 1003 1014 1004 1015 for (i = 0; i < prog->nr_reloc; i++) { 1005 - int insn_idx, map_idx; 1006 - struct bpf_insn *insns = prog->insns; 1016 + if (prog->reloc_desc[i].type == RELO_LD64) { 1017 + struct bpf_insn *insns = prog->insns; 1018 + int insn_idx, map_idx; 1007 1019 1008 - insn_idx = prog->reloc_desc[i].insn_idx; 1009 - map_idx = prog->reloc_desc[i].map_idx; 1020 + insn_idx = prog->reloc_desc[i].insn_idx; 1021 + map_idx = prog->reloc_desc[i].map_idx; 1010 1022 1011 - if (insn_idx >= (int)prog->insns_cnt) { 1012 - pr_warning("relocation out of range: '%s'\n", 1013 - prog->section_name); 1014 - return -LIBBPF_ERRNO__RELOC; 1023 + if (insn_idx >= (int)prog->insns_cnt) { 1024 + pr_warning("relocation out of range: '%s'\n", 1025 + prog->section_name); 1026 + return -LIBBPF_ERRNO__RELOC; 1027 + } 1028 + insns[insn_idx].src_reg = BPF_PSEUDO_MAP_FD; 1029 + insns[insn_idx].imm = obj->maps[map_idx].fd; 1030 + } else { 1031 + err = bpf_program__reloc_text(prog, obj, 1032 + &prog->reloc_desc[i]); 1033 + if (err) 1034 + return err; 1015 1035 } 1016 - insns[insn_idx].src_reg = BPF_PSEUDO_MAP_FD; 1017 - insns[insn_idx].imm = obj->maps[map_idx].fd; 1018 1036 } 1019 1037 1020 1038 zfree(&prog->reloc_desc); ··· 1106 1026 Elf_Data *data = obj->efile.reloc[i].data; 1107 1027 int idx = shdr->sh_info; 1108 1028 struct bpf_program *prog; 1109 - size_t nr_maps = obj->nr_maps; 1110 1029 1111 1030 if (shdr->sh_type != SHT_REL) { 1112 1031 pr_warning("internal error at %d\n", __LINE__); ··· 1119 1040 return -LIBBPF_ERRNO__RELOC; 1120 1041 } 1121 1042 1122 - err = bpf_program__collect_reloc(prog, nr_maps, 1043 + err = bpf_program__collect_reloc(prog, 1123 1044 shdr, data, 1124 - obj->efile.symbols, 1125 - obj->efile.maps_shndx, 1126 - obj->maps); 1045 + obj); 1127 1046 if (err) 1128 1047 return err; 1129 1048 } ··· 1274 1197 int err; 1275 1198 1276 1199 for (i = 0; i < obj->nr_programs; i++) { 1200 + if (obj->programs[i].idx == obj->efile.text_shndx) 1201 + continue; 1277 1202 err = bpf_program__load(&obj->programs[i], 1278 1203 obj->license, 1279 1204 obj->kern_version); ··· 1938 1859 int bpf_prog_load(const char *file, enum bpf_prog_type type, 1939 1860 struct bpf_object **pobj, int *prog_fd) 1940 1861 { 1941 - struct bpf_program *prog; 1862 + struct bpf_program *prog, *first_prog = NULL; 1942 1863 struct bpf_object *obj; 1943 1864 int err; 1944 1865 ··· 1946 1867 if (IS_ERR(obj)) 1947 1868 return -ENOENT; 1948 1869 1949 - prog = bpf_program__next(NULL, obj); 1950 - if (!prog) { 1870 + bpf_object__for_each_program(prog, obj) { 1871 + /* 1872 + * If type is not specified, try to guess it based on 1873 + * section name. 1874 + */ 1875 + if (type == BPF_PROG_TYPE_UNSPEC) { 1876 + type = bpf_program__guess_type(prog); 1877 + if (type == BPF_PROG_TYPE_UNSPEC) { 1878 + bpf_object__close(obj); 1879 + return -EINVAL; 1880 + } 1881 + } 1882 + 1883 + bpf_program__set_type(prog, type); 1884 + if (prog->idx != obj->efile.text_shndx && !first_prog) 1885 + first_prog = prog; 1886 + } 1887 + 1888 + if (!first_prog) { 1889 + pr_warning("object file doesn't contain bpf program\n"); 1951 1890 bpf_object__close(obj); 1952 1891 return -ENOENT; 1953 1892 } 1954 1893 1955 - /* 1956 - * If type is not specified, try to guess it based on 1957 - * section name. 1958 - */ 1959 - if (type == BPF_PROG_TYPE_UNSPEC) { 1960 - type = bpf_program__guess_type(prog); 1961 - if (type == BPF_PROG_TYPE_UNSPEC) { 1962 - bpf_object__close(obj); 1963 - return -EINVAL; 1964 - } 1965 - } 1966 - 1967 - bpf_program__set_type(prog, type); 1968 1894 err = bpf_object__load(obj); 1969 1895 if (err) { 1970 1896 bpf_object__close(obj); ··· 1977 1893 } 1978 1894 1979 1895 *pobj = obj; 1980 - *prog_fd = bpf_program__fd(prog); 1896 + *prog_fd = bpf_program__fd(first_prog); 1981 1897 return 0; 1982 1898 }