@@ -372,6 +372,7 @@ enum reloc_type {
372372 RELO_EXTERN_CALL ,
373373 RELO_SUBPROG_ADDR ,
374374 RELO_CORE ,
375+ RELO_INSN_ARRAY ,
375376};
376377
377378struct reloc_desc {
@@ -383,6 +384,7 @@ struct reloc_desc {
383384 int map_idx ;
384385 int sym_off ;
385386 int ext_idx ;
387+ int sym_size ;
386388 };
387389 };
388390};
@@ -664,6 +666,7 @@ struct elf_state {
664666 Elf_Data * symbols ;
665667 Elf_Data * arena_data ;
666668 Elf_Data * jt_sizes_data ;
669+ Elf_Data * jumptables_data ;
667670 size_t shstrndx ; /* section index for section name strings */
668671 size_t strtabidx ;
669672 struct elf_sec_desc * secs ;
@@ -675,6 +678,7 @@ struct elf_state {
675678 bool has_st_ops ;
676679 int arena_data_shndx ;
677680 int jt_sizes_data_shndx ;
681+ int jumptables_data_shndx ;
678682};
679683
680684struct usdt_manager ;
@@ -4064,6 +4068,11 @@ static int bpf_object__elf_collect(struct bpf_object *obj)
40644068 } else if (strcmp (name , ARENA_SEC ) == 0 ) {
40654069 obj -> efile .arena_data = data ;
40664070 obj -> efile .arena_data_shndx = idx ;
4071+ } else if (strcmp (name , ".jumptables" ) == 0 ) {
4072+ // XXX, do it properly, otherwise ->d_buf is eventually corrupted
4073+ obj -> efile .jumptables_data = calloc (1 , sizeof (* data ));
4074+ memcpy (obj -> efile .jumptables_data , data , sizeof (* data ));
4075+ obj -> efile .jumptables_data_shndx = idx ;
40674076 } else {
40684077 pr_info ("elf: skipping unrecognized data section(%d) %s\n" ,
40694078 idx , name );
@@ -4712,6 +4721,16 @@ static int bpf_program__record_reloc(struct bpf_program *prog,
47124721 return 0 ;
47134722 }
47144723
4724+ /* jump table data relocation */
4725+ if (shdr_idx == obj -> efile .jumptables_data_shndx ) {
4726+ reloc_desc -> type = RELO_INSN_ARRAY ;
4727+ reloc_desc -> insn_idx = insn_idx ;
4728+ reloc_desc -> map_idx = -1 ;
4729+ reloc_desc -> sym_off = sym -> st_value ; // XXX ?
4730+ reloc_desc -> sym_size = sym -> st_size ;
4731+ return 0 ;
4732+ }
4733+
47154734 /* generic map reference relocation */
47164735 if (type == LIBBPF_MAP_UNSPEC ) {
47174736 if (!bpf_object__shndx_is_maps (obj , shdr_idx )) {
@@ -6204,12 +6223,7 @@ static void poison_kfunc_call(struct bpf_program *prog, int relo_idx,
62046223 insn -> imm = POISON_CALL_KFUNC_BASE + ext_idx ;
62056224}
62066225
6207- static bool map_fd_is_rodata (struct bpf_object * obj , int map_fd )
6208- {
6209- return map_fd == obj -> rodata_map_fd ;
6210- }
6211-
6212- static int create_jt_map (const struct jt * jt , int adjust_off )
6226+ static int create_jt_map (struct bpf_object * obj , int off , int size , int adjust_off )
62136227{
62146228 static union bpf_attr attr = {
62156229 .map_type = BPF_MAP_TYPE_INSN_ARRAY ,
@@ -6221,15 +6235,20 @@ static int create_jt_map(const struct jt *jt, int adjust_off)
62216235 int map_fd ;
62226236 int err ;
62236237 __u32 i ;
6238+ __u32 * jt ;
62246239
6225- attr .max_entries = jt -> jump_target_cnt ;
6240+ attr .max_entries = size / 4 ;
62266241
62276242 map_fd = syscall (__NR_bpf , BPF_MAP_CREATE , & attr , sizeof (attr ));
62286243 if (map_fd < 0 )
62296244 return map_fd ;
62306245
6231- for (i = 0 ; i < jt -> jump_target_cnt ; i ++ ) {
6232- val .xlated_off = jt -> jump_target [i ] + adjust_off ;
6246+ jt = (__u32 * )(obj -> efile .jumptables_data -> d_buf + off );
6247+ if (!jt )
6248+ return - EINVAL ;
6249+
6250+ for (i = 0 ; i < attr .max_entries ; i ++ ) {
6251+ val .xlated_off = jt [2 * i ]/8 + adjust_off ;
62336252 err = bpf_map_update_elem (map_fd , & i , & val , 0 );
62346253 if (err ) {
62356254 close (map_fd );
@@ -6257,6 +6276,7 @@ static int subprog_insn_off(struct bpf_program *prog, int insn_idx)
62576276 return - prog -> sec_insn_off ;
62586277}
62596278
6279+
62606280/* Relocate data references within program code:
62616281 * - map references;
62626282 * - global variable references;
@@ -6294,31 +6314,8 @@ bpf_object__relocate_data(struct bpf_object *obj, struct bpf_program *prog)
62946314 insn [0 ].src_reg = BPF_PSEUDO_MAP_IDX_VALUE ;
62956315 insn [0 ].imm = relo -> map_idx ;
62966316 } else if (map -> autocreate ) {
6297- const struct jt * jt ;
6298- int ajdust_insn_off ;
6299- int map_fd = map -> fd ;
6300-
6301- /*
6302- * Set imm to proper map file descriptor. In normal case,
6303- * it is just map->fd. However, in case of a jump table,
6304- * a new map file descriptor should be created
6305- */
6306- jt = bpf_object__find_jt (obj , insn [1 ].imm / 8 );
6307- if (map_fd_is_rodata (obj , map_fd ) && !IS_ERR (jt )) {
6308- ajdust_insn_off = subprog_insn_off (prog , relo -> insn_idx );
6309- map_fd = create_jt_map (jt , ajdust_insn_off );
6310- if (map_fd < 0 ) {
6311- pr_warn ("prog '%s': relo #%d: failed to create a jt map for .rodata offset %u\n" ,
6312- prog -> name , i , insn [1 ].imm / 8 );
6313- return map_fd ;
6314- }
6315-
6316- /* a new map is created, so offset should be 0 */
6317- insn [1 ].imm = 0 ;
6318- }
6319-
63206317 insn [0 ].src_reg = BPF_PSEUDO_MAP_VALUE ;
6321- insn [0 ].imm = map_fd ;
6318+ insn [0 ].imm = map -> fd ;
63226319 } else {
63236320 poison_map_ldimm64 (prog , i , relo -> insn_idx , insn ,
63246321 relo -> map_idx , map );
@@ -6371,6 +6368,20 @@ bpf_object__relocate_data(struct bpf_object *obj, struct bpf_program *prog)
63716368 case RELO_CORE :
63726369 /* will be handled by bpf_program_record_relos() */
63736370 break ;
6371+ case RELO_INSN_ARRAY : {
6372+ int map_fd ;
6373+
6374+ map_fd = create_jt_map (obj , relo -> sym_off , relo -> sym_size , subprog_insn_off (prog , relo -> insn_idx ));
6375+ if (map_fd < 0 ) {
6376+ pr_warn ("prog '%s': relo #%d: failed to create a jt map for .rodata offset %u\n" ,
6377+ prog -> name , i , relo -> sym_off );
6378+ return map_fd ;
6379+ }
6380+ insn [0 ].src_reg = BPF_PSEUDO_MAP_VALUE ;
6381+ insn -> imm = map_fd ;
6382+ insn -> off = 0 ;
6383+ }
6384+ break ;
63746385 default :
63756386 pr_warn ("prog '%s': relo #%d: bad relo type %d\n" ,
63766387 prog -> name , i , relo -> type );
0 commit comments