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

Configure Feed

Select the types of activity you want to include in your feed.

objtool: Handle PC relative relocation type

For the most part, an absolute relocation type is used for rodata.
In the case of STT_SECTION, reloc->sym->offset is always zero, for
the other symbol types, reloc_addend(reloc) is always zero, thus it
can use a simple statement "reloc->sym->offset + reloc_addend(reloc)"
to obtain the symbol offset for various symbol types.

When compiling on LoongArch, there exist PC relative relocation types
for rodata, it needs to calculate the symbol offset with "S + A - PC"
according to the spec of "ELF for the LoongArch Architecture".

If there is only one jump table in the rodata, the "PC" is the entry
address which is equal with the value of reloc_offset(reloc), at this
time, reloc_offset(table) is 0.

If there are many jump tables in the rodata, the "PC" is the offset
of the jump table's base address which is equal with the value of
reloc_offset(reloc) - reloc_offset(table).

So for LoongArch, if the relocation type is PC relative, it can use a
statement "reloc_offset(reloc) - reloc_offset(table)" to get the "PC"
value when calculating the symbol offset with "S + A - PC" for one or
many jump tables in the rodata.

Add an arch-specific function arch_jump_table_sym_offset() to assign
the symbol offset, for the most part that is an absolute relocation,
the default value is "reloc->sym->offset + reloc_addend(reloc)" in
the weak definition, it can be overridden by each architecture that
has different requirements.

Link: https://github.com/loongson/la-abi-specs/blob/release/laelf.adoc
Signed-off-by: Tiezhu Yang <yangtiezhu@loongson.cn>
Link: https://lore.kernel.org/r/20250211115016.26913-4-yangtiezhu@loongson.cn
Acked-by: Huacai Chen <chenhuacai@loongson.cn>
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>

authored by

Tiezhu Yang and committed by
Josh Poimboeuf
c4b93b06 091bf313

+27 -5
+13 -4
tools/objtool/arch/loongarch/decode.c
··· 5 5 #include <asm/inst.h> 6 6 #include <asm/orc_types.h> 7 7 #include <linux/objtool_types.h> 8 - 9 - #ifndef EM_LOONGARCH 10 - #define EM_LOONGARCH 258 11 - #endif 8 + #include <arch/elf.h> 12 9 13 10 int arch_ftrace_match(char *name) 14 11 { ··· 369 372 return 4; 370 373 default: 371 374 return 8; 375 + } 376 + } 377 + 378 + unsigned long arch_jump_table_sym_offset(struct reloc *reloc, struct reloc *table) 379 + { 380 + switch (reloc_type(reloc)) { 381 + case R_LARCH_32_PCREL: 382 + case R_LARCH_64_PCREL: 383 + return reloc->sym->offset + reloc_addend(reloc) - 384 + (reloc_offset(reloc) - reloc_offset(table)); 385 + default: 386 + return reloc->sym->offset + reloc_addend(reloc); 372 387 } 373 388 }
+7
tools/objtool/arch/loongarch/include/arch/elf.h
··· 18 18 #ifndef R_LARCH_32_PCREL 19 19 #define R_LARCH_32_PCREL 99 20 20 #endif 21 + #ifndef R_LARCH_64_PCREL 22 + #define R_LARCH_64_PCREL 109 23 + #endif 24 + 25 + #ifndef EM_LOONGARCH 26 + #define EM_LOONGARCH 258 27 + #endif 21 28 22 29 #define R_NONE R_LARCH_NONE 23 30 #define R_ABS32 R_LARCH_32
+6 -1
tools/objtool/check.c
··· 1944 1944 return ret; 1945 1945 } 1946 1946 1947 + __weak unsigned long arch_jump_table_sym_offset(struct reloc *reloc, struct reloc *table) 1948 + { 1949 + return reloc->sym->offset + reloc_addend(reloc); 1950 + } 1951 + 1947 1952 static int add_jump_table(struct objtool_file *file, struct instruction *insn, 1948 1953 struct reloc *next_table) 1949 1954 { ··· 1977 1972 if (prev_offset && reloc_offset(reloc) != prev_offset + arch_reloc_size(reloc)) 1978 1973 break; 1979 1974 1980 - sym_offset = reloc->sym->offset + reloc_addend(reloc); 1975 + sym_offset = arch_jump_table_sym_offset(reloc, table); 1981 1976 1982 1977 /* Detect function pointers from contiguous objects: */ 1983 1978 if (reloc->sym->sec == pfunc->sec && sym_offset == pfunc->offset)
+1
tools/objtool/include/objtool/arch.h
··· 98 98 bool arch_pc_relative_reloc(struct reloc *reloc); 99 99 100 100 unsigned int arch_reloc_size(struct reloc *reloc); 101 + unsigned long arch_jump_table_sym_offset(struct reloc *reloc, struct reloc *table); 101 102 102 103 #endif /* _ARCH_H */