* [PATCH v7 1/7] objtool: Handle various symbol types of rodata
2025-02-11 11:50 [PATCH v7 0/7] Add jump table support for objtool on LoongArch Tiezhu Yang
@ 2025-02-11 11:50 ` Tiezhu Yang
2025-03-14 20:04 ` [tip: objtool/core] " tip-bot2 for Tiezhu Yang
2025-02-11 11:50 ` [PATCH v7 2/7] objtool: Handle different entry size " Tiezhu Yang
` (6 subsequent siblings)
7 siblings, 1 reply; 14+ messages in thread
From: Tiezhu Yang @ 2025-02-11 11:50 UTC (permalink / raw)
To: Josh Poimboeuf, Peter Zijlstra, Huacai Chen; +Cc: loongarch, linux-kernel
In the relocation section ".rela.rodata" of each .o file compiled with
LoongArch toolchain, there are various symbol types such as STT_NOTYPE,
STT_OBJECT, STT_FUNC in addition to the usual STT_SECTION, it needs to
use reloc symbol offset instead of reloc addend to find the destination
instruction in find_jump_table() and add_jump_table().
For the most part, an absolute relocation type is used for rodata. In the
case of STT_SECTION, reloc->sym->offset is always zero, and 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.
Signed-off-by: Tiezhu Yang <yangtiezhu@loongson.cn>
---
tools/objtool/check.c | 16 +++++++++++-----
1 file changed, 11 insertions(+), 5 deletions(-)
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 497cb8dfb3eb..a84e76e8eae4 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -1953,6 +1953,7 @@ static int add_jump_table(struct objtool_file *file, struct instruction *insn,
unsigned int prev_offset = 0;
struct reloc *reloc = table;
struct alternative *alt;
+ unsigned long sym_offset;
/*
* Each @reloc is a switch table relocation which points to the target
@@ -1970,9 +1971,10 @@ static int add_jump_table(struct objtool_file *file, struct instruction *insn,
if (prev_offset && reloc_offset(reloc) != prev_offset + 8)
break;
+ sym_offset = reloc->sym->offset + reloc_addend(reloc);
+
/* Detect function pointers from contiguous objects: */
- if (reloc->sym->sec == pfunc->sec &&
- reloc_addend(reloc) == pfunc->offset)
+ if (reloc->sym->sec == pfunc->sec && sym_offset == pfunc->offset)
break;
/*
@@ -1980,10 +1982,10 @@ static int add_jump_table(struct objtool_file *file, struct instruction *insn,
* which point to the end of the function. Ignore them.
*/
if (reloc->sym->sec == pfunc->sec &&
- reloc_addend(reloc) == pfunc->offset + pfunc->len)
+ sym_offset == pfunc->offset + pfunc->len)
goto next;
- dest_insn = find_insn(file, reloc->sym->sec, reloc_addend(reloc));
+ dest_insn = find_insn(file, reloc->sym->sec, sym_offset);
if (!dest_insn)
break;
@@ -2022,6 +2024,7 @@ static void find_jump_table(struct objtool_file *file, struct symbol *func,
struct reloc *table_reloc;
struct instruction *dest_insn, *orig_insn = insn;
unsigned long table_size;
+ unsigned long sym_offset;
/*
* Backward search using the @first_jump_src links, these help avoid
@@ -2045,7 +2048,10 @@ static void find_jump_table(struct objtool_file *file, struct symbol *func,
table_reloc = arch_find_switch_table(file, insn, &table_size);
if (!table_reloc)
continue;
- dest_insn = find_insn(file, table_reloc->sym->sec, reloc_addend(table_reloc));
+
+ sym_offset = table_reloc->sym->offset + reloc_addend(table_reloc);
+
+ dest_insn = find_insn(file, table_reloc->sym->sec, sym_offset);
if (!dest_insn || !insn_func(dest_insn) || insn_func(dest_insn)->pfunc != func)
continue;
--
2.42.0
^ permalink raw reply [flat|nested] 14+ messages in thread* [tip: objtool/core] objtool: Handle various symbol types of rodata
2025-02-11 11:50 ` [PATCH v7 1/7] objtool: Handle various symbol types of rodata Tiezhu Yang
@ 2025-03-14 20:04 ` tip-bot2 for Tiezhu Yang
0 siblings, 0 replies; 14+ messages in thread
From: tip-bot2 for Tiezhu Yang @ 2025-03-14 20:04 UTC (permalink / raw)
To: linux-tip-commits
Cc: Tiezhu Yang, Huacai Chen, Josh Poimboeuf, x86, linux-kernel
The following commit has been merged into the objtool/core branch of tip:
Commit-ID: ab6ce22b789622ca732e91cbb3a5cb5ba370cbd0
Gitweb: https://git.kernel.org/tip/ab6ce22b789622ca732e91cbb3a5cb5ba370cbd0
Author: Tiezhu Yang <yangtiezhu@loongson.cn>
AuthorDate: Tue, 11 Feb 2025 19:50:10 +08:00
Committer: Josh Poimboeuf <jpoimboe@kernel.org>
CommitterDate: Wed, 12 Mar 2025 15:43:38 -07:00
objtool: Handle various symbol types of rodata
In the relocation section ".rela.rodata" of each .o file compiled with
LoongArch toolchain, there are various symbol types such as STT_NOTYPE,
STT_OBJECT, STT_FUNC in addition to the usual STT_SECTION, it needs to
use reloc symbol offset instead of reloc addend to find the destination
instruction in find_jump_table() and add_jump_table().
For the most part, an absolute relocation type is used for rodata. In the
case of STT_SECTION, reloc->sym->offset is always zero, and 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.
Signed-off-by: Tiezhu Yang <yangtiezhu@loongson.cn>
Link: https://lore.kernel.org/r/20250211115016.26913-2-yangtiezhu@loongson.cn
Acked-by: Huacai Chen <chenhuacai@loongson.cn>
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
---
tools/objtool/check.c | 16 +++++++++++-----
1 file changed, 11 insertions(+), 5 deletions(-)
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index ce973d9..cfab4a1 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -1954,6 +1954,7 @@ static int add_jump_table(struct objtool_file *file, struct instruction *insn,
unsigned int prev_offset = 0;
struct reloc *reloc = table;
struct alternative *alt;
+ unsigned long sym_offset;
/*
* Each @reloc is a switch table relocation which points to the target
@@ -1971,9 +1972,10 @@ static int add_jump_table(struct objtool_file *file, struct instruction *insn,
if (prev_offset && reloc_offset(reloc) != prev_offset + 8)
break;
+ sym_offset = reloc->sym->offset + reloc_addend(reloc);
+
/* Detect function pointers from contiguous objects: */
- if (reloc->sym->sec == pfunc->sec &&
- reloc_addend(reloc) == pfunc->offset)
+ if (reloc->sym->sec == pfunc->sec && sym_offset == pfunc->offset)
break;
/*
@@ -1981,10 +1983,10 @@ static int add_jump_table(struct objtool_file *file, struct instruction *insn,
* which point to the end of the function. Ignore them.
*/
if (reloc->sym->sec == pfunc->sec &&
- reloc_addend(reloc) == pfunc->offset + pfunc->len)
+ sym_offset == pfunc->offset + pfunc->len)
goto next;
- dest_insn = find_insn(file, reloc->sym->sec, reloc_addend(reloc));
+ dest_insn = find_insn(file, reloc->sym->sec, sym_offset);
if (!dest_insn)
break;
@@ -2023,6 +2025,7 @@ static void find_jump_table(struct objtool_file *file, struct symbol *func,
struct reloc *table_reloc;
struct instruction *dest_insn, *orig_insn = insn;
unsigned long table_size;
+ unsigned long sym_offset;
/*
* Backward search using the @first_jump_src links, these help avoid
@@ -2046,7 +2049,10 @@ static void find_jump_table(struct objtool_file *file, struct symbol *func,
table_reloc = arch_find_switch_table(file, insn, &table_size);
if (!table_reloc)
continue;
- dest_insn = find_insn(file, table_reloc->sym->sec, reloc_addend(table_reloc));
+
+ sym_offset = table_reloc->sym->offset + reloc_addend(table_reloc);
+
+ dest_insn = find_insn(file, table_reloc->sym->sec, sym_offset);
if (!dest_insn || !insn_func(dest_insn) || insn_func(dest_insn)->pfunc != func)
continue;
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v7 2/7] objtool: Handle different entry size of rodata
2025-02-11 11:50 [PATCH v7 0/7] Add jump table support for objtool on LoongArch Tiezhu Yang
2025-02-11 11:50 ` [PATCH v7 1/7] objtool: Handle various symbol types of rodata Tiezhu Yang
@ 2025-02-11 11:50 ` Tiezhu Yang
2025-03-14 20:04 ` [tip: objtool/core] " tip-bot2 for Tiezhu Yang
2025-02-11 11:50 ` [PATCH v7 3/7] objtool: Handle PC relative relocation type Tiezhu Yang
` (5 subsequent siblings)
7 siblings, 1 reply; 14+ messages in thread
From: Tiezhu Yang @ 2025-02-11 11:50 UTC (permalink / raw)
To: Josh Poimboeuf, Peter Zijlstra, Huacai Chen; +Cc: loongarch, linux-kernel
In the most cases, the entry size of rodata is 8 bytes because the
relocation type is 64 bit. There are also 32 bit relocation types,
the entry size of rodata should be 4 bytes in this case.
Add an arch-specific function arch_reloc_size() to assign the entry
size of rodata for x86, powerpc and LoongArch.
Signed-off-by: Tiezhu Yang <yangtiezhu@loongson.cn>
---
tools/objtool/arch/loongarch/decode.c | 11 +++++++++++
tools/objtool/arch/powerpc/decode.c | 15 +++++++++++++++
tools/objtool/arch/x86/decode.c | 13 +++++++++++++
tools/objtool/check.c | 2 +-
tools/objtool/include/objtool/arch.h | 2 ++
5 files changed, 42 insertions(+), 1 deletion(-)
diff --git a/tools/objtool/arch/loongarch/decode.c b/tools/objtool/arch/loongarch/decode.c
index 69b66994f2a1..b64205b89f6b 100644
--- a/tools/objtool/arch/loongarch/decode.c
+++ b/tools/objtool/arch/loongarch/decode.c
@@ -363,3 +363,14 @@ void arch_initial_func_cfi_state(struct cfi_init_state *state)
state->cfa.base = CFI_SP;
state->cfa.offset = 0;
}
+
+unsigned int arch_reloc_size(struct reloc *reloc)
+{
+ switch (reloc_type(reloc)) {
+ case R_LARCH_32:
+ case R_LARCH_32_PCREL:
+ return 4;
+ default:
+ return 8;
+ }
+}
diff --git a/tools/objtool/arch/powerpc/decode.c b/tools/objtool/arch/powerpc/decode.c
index 53b55690f320..3c95dd74fca0 100644
--- a/tools/objtool/arch/powerpc/decode.c
+++ b/tools/objtool/arch/powerpc/decode.c
@@ -106,3 +106,18 @@ void arch_initial_func_cfi_state(struct cfi_init_state *state)
state->regs[CFI_RA].base = CFI_CFA;
state->regs[CFI_RA].offset = 0;
}
+
+unsigned int arch_reloc_size(struct reloc *reloc)
+{
+ switch (reloc_type(reloc)) {
+ case R_PPC_REL32:
+ case R_PPC64_REL32:
+ case R_PPC_ADDR32:
+ case R_PPC_UADDR32:
+ case R_PPC_PLT32:
+ case R_PPC_PLTREL32:
+ return 4;
+ default:
+ return 8;
+ }
+}
diff --git a/tools/objtool/arch/x86/decode.c b/tools/objtool/arch/x86/decode.c
index fe1362c34564..fb9691a34d92 100644
--- a/tools/objtool/arch/x86/decode.c
+++ b/tools/objtool/arch/x86/decode.c
@@ -852,3 +852,16 @@ bool arch_is_embedded_insn(struct symbol *sym)
return !strcmp(sym->name, "retbleed_return_thunk") ||
!strcmp(sym->name, "srso_safe_ret");
}
+
+unsigned int arch_reloc_size(struct reloc *reloc)
+{
+ switch (reloc_type(reloc)) {
+ case R_X86_64_32:
+ case R_X86_64_32S:
+ case R_X86_64_PC32:
+ case R_X86_64_PLT32:
+ return 4;
+ default:
+ return 8;
+ }
+}
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index a84e76e8eae4..85c1988014dc 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -1968,7 +1968,7 @@ static int add_jump_table(struct objtool_file *file, struct instruction *insn,
break;
/* Make sure the table entries are consecutive: */
- if (prev_offset && reloc_offset(reloc) != prev_offset + 8)
+ if (prev_offset && reloc_offset(reloc) != prev_offset + arch_reloc_size(reloc))
break;
sym_offset = reloc->sym->offset + reloc_addend(reloc);
diff --git a/tools/objtool/include/objtool/arch.h b/tools/objtool/include/objtool/arch.h
index d63b46a19f39..396f7c6c81c0 100644
--- a/tools/objtool/include/objtool/arch.h
+++ b/tools/objtool/include/objtool/arch.h
@@ -97,4 +97,6 @@ int arch_rewrite_retpolines(struct objtool_file *file);
bool arch_pc_relative_reloc(struct reloc *reloc);
+unsigned int arch_reloc_size(struct reloc *reloc);
+
#endif /* _ARCH_H */
--
2.42.0
^ permalink raw reply [flat|nested] 14+ messages in thread* [tip: objtool/core] objtool: Handle different entry size of rodata
2025-02-11 11:50 ` [PATCH v7 2/7] objtool: Handle different entry size " Tiezhu Yang
@ 2025-03-14 20:04 ` tip-bot2 for Tiezhu Yang
0 siblings, 0 replies; 14+ messages in thread
From: tip-bot2 for Tiezhu Yang @ 2025-03-14 20:04 UTC (permalink / raw)
To: linux-tip-commits
Cc: Tiezhu Yang, Huacai Chen, Josh Poimboeuf, x86, linux-kernel
The following commit has been merged into the objtool/core branch of tip:
Commit-ID: 091bf313f8a852a7f30c3a8dcef569edfd06f5dc
Gitweb: https://git.kernel.org/tip/091bf313f8a852a7f30c3a8dcef569edfd06f5dc
Author: Tiezhu Yang <yangtiezhu@loongson.cn>
AuthorDate: Tue, 11 Feb 2025 19:50:11 +08:00
Committer: Josh Poimboeuf <jpoimboe@kernel.org>
CommitterDate: Wed, 12 Mar 2025 15:43:38 -07:00
objtool: Handle different entry size of rodata
In the most cases, the entry size of rodata is 8 bytes because the
relocation type is 64 bit. There are also 32 bit relocation types,
the entry size of rodata should be 4 bytes in this case.
Add an arch-specific function arch_reloc_size() to assign the entry
size of rodata for x86, powerpc and LoongArch.
Signed-off-by: Tiezhu Yang <yangtiezhu@loongson.cn>
Link: https://lore.kernel.org/r/20250211115016.26913-3-yangtiezhu@loongson.cn
Acked-by: Huacai Chen <chenhuacai@loongson.cn>
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
---
tools/objtool/arch/loongarch/decode.c | 11 +++++++++++
tools/objtool/arch/powerpc/decode.c | 14 ++++++++++++++
tools/objtool/arch/x86/decode.c | 13 +++++++++++++
tools/objtool/check.c | 2 +-
tools/objtool/include/objtool/arch.h | 2 ++
5 files changed, 41 insertions(+), 1 deletion(-)
diff --git a/tools/objtool/arch/loongarch/decode.c b/tools/objtool/arch/loongarch/decode.c
index 69b6699..b64205b 100644
--- a/tools/objtool/arch/loongarch/decode.c
+++ b/tools/objtool/arch/loongarch/decode.c
@@ -363,3 +363,14 @@ void arch_initial_func_cfi_state(struct cfi_init_state *state)
state->cfa.base = CFI_SP;
state->cfa.offset = 0;
}
+
+unsigned int arch_reloc_size(struct reloc *reloc)
+{
+ switch (reloc_type(reloc)) {
+ case R_LARCH_32:
+ case R_LARCH_32_PCREL:
+ return 4;
+ default:
+ return 8;
+ }
+}
diff --git a/tools/objtool/arch/powerpc/decode.c b/tools/objtool/arch/powerpc/decode.c
index 53b5569..7c0bf24 100644
--- a/tools/objtool/arch/powerpc/decode.c
+++ b/tools/objtool/arch/powerpc/decode.c
@@ -106,3 +106,17 @@ void arch_initial_func_cfi_state(struct cfi_init_state *state)
state->regs[CFI_RA].base = CFI_CFA;
state->regs[CFI_RA].offset = 0;
}
+
+unsigned int arch_reloc_size(struct reloc *reloc)
+{
+ switch (reloc_type(reloc)) {
+ case R_PPC_REL32:
+ case R_PPC_ADDR32:
+ case R_PPC_UADDR32:
+ case R_PPC_PLT32:
+ case R_PPC_PLTREL32:
+ return 4;
+ default:
+ return 8;
+ }
+}
diff --git a/tools/objtool/arch/x86/decode.c b/tools/objtool/arch/x86/decode.c
index fe1362c..fb9691a 100644
--- a/tools/objtool/arch/x86/decode.c
+++ b/tools/objtool/arch/x86/decode.c
@@ -852,3 +852,16 @@ bool arch_is_embedded_insn(struct symbol *sym)
return !strcmp(sym->name, "retbleed_return_thunk") ||
!strcmp(sym->name, "srso_safe_ret");
}
+
+unsigned int arch_reloc_size(struct reloc *reloc)
+{
+ switch (reloc_type(reloc)) {
+ case R_X86_64_32:
+ case R_X86_64_32S:
+ case R_X86_64_PC32:
+ case R_X86_64_PLT32:
+ return 4;
+ default:
+ return 8;
+ }
+}
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index cfab4a1..f762d23 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -1969,7 +1969,7 @@ static int add_jump_table(struct objtool_file *file, struct instruction *insn,
break;
/* Make sure the table entries are consecutive: */
- if (prev_offset && reloc_offset(reloc) != prev_offset + 8)
+ if (prev_offset && reloc_offset(reloc) != prev_offset + arch_reloc_size(reloc))
break;
sym_offset = reloc->sym->offset + reloc_addend(reloc);
diff --git a/tools/objtool/include/objtool/arch.h b/tools/objtool/include/objtool/arch.h
index d63b46a..396f7c6 100644
--- a/tools/objtool/include/objtool/arch.h
+++ b/tools/objtool/include/objtool/arch.h
@@ -97,4 +97,6 @@ int arch_rewrite_retpolines(struct objtool_file *file);
bool arch_pc_relative_reloc(struct reloc *reloc);
+unsigned int arch_reloc_size(struct reloc *reloc);
+
#endif /* _ARCH_H */
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v7 3/7] objtool: Handle PC relative relocation type
2025-02-11 11:50 [PATCH v7 0/7] Add jump table support for objtool on LoongArch Tiezhu Yang
2025-02-11 11:50 ` [PATCH v7 1/7] objtool: Handle various symbol types of rodata Tiezhu Yang
2025-02-11 11:50 ` [PATCH v7 2/7] objtool: Handle different entry size " Tiezhu Yang
@ 2025-02-11 11:50 ` Tiezhu Yang
2025-03-14 20:04 ` [tip: objtool/core] " tip-bot2 for Tiezhu Yang
2025-02-11 11:50 ` [PATCH v7 4/7] objtool/LoongArch: Add support for switch table Tiezhu Yang
` (4 subsequent siblings)
7 siblings, 1 reply; 14+ messages in thread
From: Tiezhu Yang @ 2025-02-11 11:50 UTC (permalink / raw)
To: Josh Poimboeuf, Peter Zijlstra, Huacai Chen; +Cc: loongarch, linux-kernel
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>
---
tools/objtool/arch/loongarch/decode.c | 17 +++++++++++++----
tools/objtool/arch/loongarch/include/arch/elf.h | 7 +++++++
tools/objtool/check.c | 7 ++++++-
tools/objtool/include/objtool/arch.h | 1 +
4 files changed, 27 insertions(+), 5 deletions(-)
diff --git a/tools/objtool/arch/loongarch/decode.c b/tools/objtool/arch/loongarch/decode.c
index b64205b89f6b..02e490555966 100644
--- a/tools/objtool/arch/loongarch/decode.c
+++ b/tools/objtool/arch/loongarch/decode.c
@@ -5,10 +5,7 @@
#include <asm/inst.h>
#include <asm/orc_types.h>
#include <linux/objtool_types.h>
-
-#ifndef EM_LOONGARCH
-#define EM_LOONGARCH 258
-#endif
+#include <arch/elf.h>
int arch_ftrace_match(char *name)
{
@@ -374,3 +371,15 @@ unsigned int arch_reloc_size(struct reloc *reloc)
return 8;
}
}
+
+unsigned long arch_jump_table_sym_offset(struct reloc *reloc, struct reloc *table)
+{
+ switch (reloc_type(reloc)) {
+ case R_LARCH_32_PCREL:
+ case R_LARCH_64_PCREL:
+ return reloc->sym->offset + reloc_addend(reloc) -
+ (reloc_offset(reloc) - reloc_offset(table));
+ default:
+ return reloc->sym->offset + reloc_addend(reloc);
+ }
+}
diff --git a/tools/objtool/arch/loongarch/include/arch/elf.h b/tools/objtool/arch/loongarch/include/arch/elf.h
index 9623d663220e..ec79062c9554 100644
--- a/tools/objtool/arch/loongarch/include/arch/elf.h
+++ b/tools/objtool/arch/loongarch/include/arch/elf.h
@@ -18,6 +18,13 @@
#ifndef R_LARCH_32_PCREL
#define R_LARCH_32_PCREL 99
#endif
+#ifndef R_LARCH_64_PCREL
+#define R_LARCH_64_PCREL 109
+#endif
+
+#ifndef EM_LOONGARCH
+#define EM_LOONGARCH 258
+#endif
#define R_NONE R_LARCH_NONE
#define R_ABS32 R_LARCH_32
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 85c1988014dc..7174dcb7496e 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -1943,6 +1943,11 @@ static int add_special_section_alts(struct objtool_file *file)
return ret;
}
+__weak unsigned long arch_jump_table_sym_offset(struct reloc *reloc, struct reloc *table)
+{
+ return reloc->sym->offset + reloc_addend(reloc);
+}
+
static int add_jump_table(struct objtool_file *file, struct instruction *insn,
struct reloc *next_table)
{
@@ -1971,7 +1976,7 @@ static int add_jump_table(struct objtool_file *file, struct instruction *insn,
if (prev_offset && reloc_offset(reloc) != prev_offset + arch_reloc_size(reloc))
break;
- sym_offset = reloc->sym->offset + reloc_addend(reloc);
+ sym_offset = arch_jump_table_sym_offset(reloc, table);
/* Detect function pointers from contiguous objects: */
if (reloc->sym->sec == pfunc->sec && sym_offset == pfunc->offset)
diff --git a/tools/objtool/include/objtool/arch.h b/tools/objtool/include/objtool/arch.h
index 396f7c6c81c0..089a1acc48a8 100644
--- a/tools/objtool/include/objtool/arch.h
+++ b/tools/objtool/include/objtool/arch.h
@@ -98,5 +98,6 @@ int arch_rewrite_retpolines(struct objtool_file *file);
bool arch_pc_relative_reloc(struct reloc *reloc);
unsigned int arch_reloc_size(struct reloc *reloc);
+unsigned long arch_jump_table_sym_offset(struct reloc *reloc, struct reloc *table);
#endif /* _ARCH_H */
--
2.42.0
^ permalink raw reply [flat|nested] 14+ messages in thread* [tip: objtool/core] objtool: Handle PC relative relocation type
2025-02-11 11:50 ` [PATCH v7 3/7] objtool: Handle PC relative relocation type Tiezhu Yang
@ 2025-03-14 20:04 ` tip-bot2 for Tiezhu Yang
0 siblings, 0 replies; 14+ messages in thread
From: tip-bot2 for Tiezhu Yang @ 2025-03-14 20:04 UTC (permalink / raw)
To: linux-tip-commits
Cc: Tiezhu Yang, Huacai Chen, Josh Poimboeuf, x86, linux-kernel
The following commit has been merged into the objtool/core branch of tip:
Commit-ID: c4b93b06230ae49870187189d9f7342f6ad4f14e
Gitweb: https://git.kernel.org/tip/c4b93b06230ae49870187189d9f7342f6ad4f14e
Author: Tiezhu Yang <yangtiezhu@loongson.cn>
AuthorDate: Tue, 11 Feb 2025 19:50:12 +08:00
Committer: Josh Poimboeuf <jpoimboe@kernel.org>
CommitterDate: Wed, 12 Mar 2025 15:43:38 -07:00
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>
---
tools/objtool/arch/loongarch/decode.c | 17 ++++++++++++----
tools/objtool/arch/loongarch/include/arch/elf.h | 7 +++++++-
tools/objtool/check.c | 7 ++++++-
tools/objtool/include/objtool/arch.h | 1 +-
4 files changed, 27 insertions(+), 5 deletions(-)
diff --git a/tools/objtool/arch/loongarch/decode.c b/tools/objtool/arch/loongarch/decode.c
index b64205b..02e4905 100644
--- a/tools/objtool/arch/loongarch/decode.c
+++ b/tools/objtool/arch/loongarch/decode.c
@@ -5,10 +5,7 @@
#include <asm/inst.h>
#include <asm/orc_types.h>
#include <linux/objtool_types.h>
-
-#ifndef EM_LOONGARCH
-#define EM_LOONGARCH 258
-#endif
+#include <arch/elf.h>
int arch_ftrace_match(char *name)
{
@@ -374,3 +371,15 @@ unsigned int arch_reloc_size(struct reloc *reloc)
return 8;
}
}
+
+unsigned long arch_jump_table_sym_offset(struct reloc *reloc, struct reloc *table)
+{
+ switch (reloc_type(reloc)) {
+ case R_LARCH_32_PCREL:
+ case R_LARCH_64_PCREL:
+ return reloc->sym->offset + reloc_addend(reloc) -
+ (reloc_offset(reloc) - reloc_offset(table));
+ default:
+ return reloc->sym->offset + reloc_addend(reloc);
+ }
+}
diff --git a/tools/objtool/arch/loongarch/include/arch/elf.h b/tools/objtool/arch/loongarch/include/arch/elf.h
index 9623d66..ec79062 100644
--- a/tools/objtool/arch/loongarch/include/arch/elf.h
+++ b/tools/objtool/arch/loongarch/include/arch/elf.h
@@ -18,6 +18,13 @@
#ifndef R_LARCH_32_PCREL
#define R_LARCH_32_PCREL 99
#endif
+#ifndef R_LARCH_64_PCREL
+#define R_LARCH_64_PCREL 109
+#endif
+
+#ifndef EM_LOONGARCH
+#define EM_LOONGARCH 258
+#endif
#define R_NONE R_LARCH_NONE
#define R_ABS32 R_LARCH_32
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index f762d23..7dbf22c 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -1944,6 +1944,11 @@ out:
return ret;
}
+__weak unsigned long arch_jump_table_sym_offset(struct reloc *reloc, struct reloc *table)
+{
+ return reloc->sym->offset + reloc_addend(reloc);
+}
+
static int add_jump_table(struct objtool_file *file, struct instruction *insn,
struct reloc *next_table)
{
@@ -1972,7 +1977,7 @@ static int add_jump_table(struct objtool_file *file, struct instruction *insn,
if (prev_offset && reloc_offset(reloc) != prev_offset + arch_reloc_size(reloc))
break;
- sym_offset = reloc->sym->offset + reloc_addend(reloc);
+ sym_offset = arch_jump_table_sym_offset(reloc, table);
/* Detect function pointers from contiguous objects: */
if (reloc->sym->sec == pfunc->sec && sym_offset == pfunc->offset)
diff --git a/tools/objtool/include/objtool/arch.h b/tools/objtool/include/objtool/arch.h
index 396f7c6..089a1ac 100644
--- a/tools/objtool/include/objtool/arch.h
+++ b/tools/objtool/include/objtool/arch.h
@@ -98,5 +98,6 @@ int arch_rewrite_retpolines(struct objtool_file *file);
bool arch_pc_relative_reloc(struct reloc *reloc);
unsigned int arch_reloc_size(struct reloc *reloc);
+unsigned long arch_jump_table_sym_offset(struct reloc *reloc, struct reloc *table);
#endif /* _ARCH_H */
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v7 4/7] objtool/LoongArch: Add support for switch table
2025-02-11 11:50 [PATCH v7 0/7] Add jump table support for objtool on LoongArch Tiezhu Yang
` (2 preceding siblings ...)
2025-02-11 11:50 ` [PATCH v7 3/7] objtool: Handle PC relative relocation type Tiezhu Yang
@ 2025-02-11 11:50 ` Tiezhu Yang
2025-03-14 20:04 ` [tip: objtool/core] " tip-bot2 for Tiezhu Yang
2025-02-11 11:50 ` [PATCH v7 5/7] objtool/LoongArch: Add support for goto table Tiezhu Yang
` (3 subsequent siblings)
7 siblings, 1 reply; 14+ messages in thread
From: Tiezhu Yang @ 2025-02-11 11:50 UTC (permalink / raw)
To: Josh Poimboeuf, Peter Zijlstra, Huacai Chen; +Cc: loongarch, linux-kernel
The objtool program need to analysis the control flow of each object file
generated by compiler toolchain, it needs to know all the locations that
a branch instruction may jump into, if a jump table is used, objtool has
to correlate the jump instruction with the table.
On x86 (which is the only port supported by objtool before LoongArch),
there is a relocation type on the jump instruction and directly points
to the table. But on LoongArch, the relocation is on another kind of
instruction prior to the jump instruction, and also with scheduling it
is not very easy to tell the offset of that instruction from the jump
instruction. Furthermore, because LoongArch has -fsection-anchors (often
enabled at -O1 or above) the relocation may actually points to a section
anchor instead of the table itself.
The good news is that after continuous analysis and discussion, at last
a GCC patch "LoongArch: Add support to annotate tablejump" and a Clang
patch "[LoongArch] Add options for annotate tablejump" have been merged
into the upstream mainline, the compiler changes make life much easier
for switch table support of objtool on LoongArch.
By now, there is an additional section ".discard.tablejump_annotate" to
store the jump info as pairs of addresses, each pair contains the address
of jump instruction and the address of jump table.
In order to find switch table, it is easy to parse the relocation section
".rela.discard.tablejump_annotate" to get table_sec and table_offset, the
rest process is somehow like x86.
Additionally, it needs to get each table size. When compiling on LoongArch,
there are unsorted table offsets of rodata if there exist many jump tables,
it will get the wrong table end and find the wrong table jump destination
instructions in add_jump_table().
Sort the rodata table offset by parsing ".rela.discard.tablejump_annotate"
and then get each table size of rodata corresponded with each table jump
instruction, it is used to check the table end and will break the process
when parsing ".rela.rodata" to avoid getting the wrong jump destination
instructions.
Link: https://gcc.gnu.org/git/?p=gcc.git;a=commit;h=0ee028f55640
Link: https://github.com/llvm/llvm-project/commit/4c2c17756739
Signed-off-by: Tiezhu Yang <yangtiezhu@loongson.cn>
---
tools/objtool/arch/loongarch/special.c | 131 ++++++++++++++++++++++++-
1 file changed, 130 insertions(+), 1 deletion(-)
diff --git a/tools/objtool/arch/loongarch/special.c b/tools/objtool/arch/loongarch/special.c
index 87230ed570fd..4fa6877d5b2b 100644
--- a/tools/objtool/arch/loongarch/special.c
+++ b/tools/objtool/arch/loongarch/special.c
@@ -1,5 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later
+#include <string.h>
#include <objtool/special.h>
+#include <objtool/warn.h>
bool arch_support_alt_relocation(struct special_alt *special_alt,
struct instruction *insn,
@@ -8,9 +10,136 @@ bool arch_support_alt_relocation(struct special_alt *special_alt,
return false;
}
+struct table_info {
+ struct list_head jump_info;
+ unsigned long insn_offset;
+ unsigned long rodata_offset;
+};
+
+static void get_rodata_table_size_by_table_annotate(struct objtool_file *file,
+ struct instruction *insn,
+ unsigned long *table_size)
+{
+ struct section *rsec;
+ struct reloc *reloc;
+ struct list_head table_list;
+ struct table_info *orig_table;
+ struct table_info *next_table;
+ unsigned long tmp_insn_offset;
+ unsigned long tmp_rodata_offset;
+
+ rsec = find_section_by_name(file->elf, ".rela.discard.tablejump_annotate");
+ if (!rsec)
+ return;
+
+ INIT_LIST_HEAD(&table_list);
+
+ for_each_reloc(rsec, reloc) {
+ orig_table = malloc(sizeof(struct table_info));
+ if (!orig_table) {
+ WARN("malloc failed");
+ return;
+ }
+
+ orig_table->insn_offset = reloc->sym->offset + reloc_addend(reloc);
+ reloc++;
+ orig_table->rodata_offset = reloc->sym->offset + reloc_addend(reloc);
+
+ list_add_tail(&orig_table->jump_info, &table_list);
+
+ if (reloc_idx(reloc) + 1 == sec_num_entries(rsec))
+ break;
+ }
+
+ list_for_each_entry(orig_table, &table_list, jump_info) {
+ next_table = list_next_entry(orig_table, jump_info);
+ list_for_each_entry_from(next_table, &table_list, jump_info) {
+ if (next_table->rodata_offset < orig_table->rodata_offset) {
+ tmp_insn_offset = next_table->insn_offset;
+ tmp_rodata_offset = next_table->rodata_offset;
+ next_table->insn_offset = orig_table->insn_offset;
+ next_table->rodata_offset = orig_table->rodata_offset;
+ orig_table->insn_offset = tmp_insn_offset;
+ orig_table->rodata_offset = tmp_rodata_offset;
+ }
+ }
+ }
+
+ list_for_each_entry(orig_table, &table_list, jump_info) {
+ if (insn->offset == orig_table->insn_offset) {
+ next_table = list_next_entry(orig_table, jump_info);
+ if (&next_table->jump_info == &table_list) {
+ *table_size = 0;
+ return;
+ }
+
+ while (next_table->rodata_offset == orig_table->rodata_offset) {
+ next_table = list_next_entry(next_table, jump_info);
+ if (&next_table->jump_info == &table_list) {
+ *table_size = 0;
+ return;
+ }
+ }
+
+ *table_size = next_table->rodata_offset - orig_table->rodata_offset;
+ }
+ }
+}
+
+static struct reloc *find_reloc_by_table_annotate(struct objtool_file *file,
+ struct instruction *insn,
+ unsigned long *table_size)
+{
+ struct section *rsec;
+ struct reloc *reloc;
+ unsigned long offset;
+
+ rsec = find_section_by_name(file->elf, ".rela.discard.tablejump_annotate");
+ if (!rsec)
+ return NULL;
+
+ for_each_reloc(rsec, reloc) {
+ if (reloc->sym->sec->rodata)
+ continue;
+
+ if (strcmp(insn->sec->name, reloc->sym->sec->name))
+ continue;
+
+ offset = reloc->sym->offset + reloc_addend(reloc);
+ if (insn->offset == offset) {
+ get_rodata_table_size_by_table_annotate(file, insn, table_size);
+ reloc++;
+ return reloc;
+ }
+ }
+
+ return NULL;
+}
+
struct reloc *arch_find_switch_table(struct objtool_file *file,
struct instruction *insn,
unsigned long *table_size)
{
- return NULL;
+ struct reloc *annotate_reloc;
+ struct reloc *rodata_reloc;
+ struct section *table_sec;
+ unsigned long table_offset;
+
+ annotate_reloc = find_reloc_by_table_annotate(file, insn, table_size);
+ if (!annotate_reloc)
+ return NULL;
+
+ table_sec = annotate_reloc->sym->sec;
+ table_offset = annotate_reloc->sym->offset + reloc_addend(annotate_reloc);
+
+ /*
+ * Each table entry has a rela associated with it. The rela
+ * should reference text in the same function as the original
+ * instruction.
+ */
+ rodata_reloc = find_reloc_by_dest(file->elf, table_sec, table_offset);
+ if (!rodata_reloc)
+ return NULL;
+
+ return rodata_reloc;
}
--
2.42.0
^ permalink raw reply [flat|nested] 14+ messages in thread* [tip: objtool/core] objtool/LoongArch: Add support for switch table
2025-02-11 11:50 ` [PATCH v7 4/7] objtool/LoongArch: Add support for switch table Tiezhu Yang
@ 2025-03-14 20:04 ` tip-bot2 for Tiezhu Yang
0 siblings, 0 replies; 14+ messages in thread
From: tip-bot2 for Tiezhu Yang @ 2025-03-14 20:04 UTC (permalink / raw)
To: linux-tip-commits
Cc: Tiezhu Yang, Huacai Chen, Josh Poimboeuf, x86, linux-kernel
The following commit has been merged into the objtool/core branch of tip:
Commit-ID: b95f852d3af21513e19a54c1e971c79f2911b54a
Gitweb: https://git.kernel.org/tip/b95f852d3af21513e19a54c1e971c79f2911b54a
Author: Tiezhu Yang <yangtiezhu@loongson.cn>
AuthorDate: Tue, 11 Feb 2025 19:50:13 +08:00
Committer: Josh Poimboeuf <jpoimboe@kernel.org>
CommitterDate: Wed, 12 Mar 2025 15:43:38 -07:00
objtool/LoongArch: Add support for switch table
The objtool program need to analysis the control flow of each object file
generated by compiler toolchain, it needs to know all the locations that
a branch instruction may jump into, if a jump table is used, objtool has
to correlate the jump instruction with the table.
On x86 (which is the only port supported by objtool before LoongArch),
there is a relocation type on the jump instruction and directly points
to the table. But on LoongArch, the relocation is on another kind of
instruction prior to the jump instruction, and also with scheduling it
is not very easy to tell the offset of that instruction from the jump
instruction. Furthermore, because LoongArch has -fsection-anchors (often
enabled at -O1 or above) the relocation may actually points to a section
anchor instead of the table itself.
The good news is that after continuous analysis and discussion, at last
a GCC patch "LoongArch: Add support to annotate tablejump" and a Clang
patch "[LoongArch] Add options for annotate tablejump" have been merged
into the upstream mainline, the compiler changes make life much easier
for switch table support of objtool on LoongArch.
By now, there is an additional section ".discard.tablejump_annotate" to
store the jump info as pairs of addresses, each pair contains the address
of jump instruction and the address of jump table.
In order to find switch table, it is easy to parse the relocation section
".rela.discard.tablejump_annotate" to get table_sec and table_offset, the
rest process is somehow like x86.
Additionally, it needs to get each table size. When compiling on LoongArch,
there are unsorted table offsets of rodata if there exist many jump tables,
it will get the wrong table end and find the wrong table jump destination
instructions in add_jump_table().
Sort the rodata table offset by parsing ".rela.discard.tablejump_annotate"
and then get each table size of rodata corresponded with each table jump
instruction, it is used to check the table end and will break the process
when parsing ".rela.rodata" to avoid getting the wrong jump destination
instructions.
Link: https://gcc.gnu.org/git/?p=gcc.git;a=commit;h=0ee028f55640
Link: https://github.com/llvm/llvm-project/commit/4c2c17756739
Signed-off-by: Tiezhu Yang <yangtiezhu@loongson.cn>
Link: https://lore.kernel.org/r/20250211115016.26913-5-yangtiezhu@loongson.cn
Acked-by: Huacai Chen <chenhuacai@loongson.cn>
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
---
tools/objtool/arch/loongarch/special.c | 131 +++++++++++++++++++++++-
1 file changed, 130 insertions(+), 1 deletion(-)
diff --git a/tools/objtool/arch/loongarch/special.c b/tools/objtool/arch/loongarch/special.c
index 87230ed..4fa6877 100644
--- a/tools/objtool/arch/loongarch/special.c
+++ b/tools/objtool/arch/loongarch/special.c
@@ -1,5 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later
+#include <string.h>
#include <objtool/special.h>
+#include <objtool/warn.h>
bool arch_support_alt_relocation(struct special_alt *special_alt,
struct instruction *insn,
@@ -8,9 +10,136 @@ bool arch_support_alt_relocation(struct special_alt *special_alt,
return false;
}
+struct table_info {
+ struct list_head jump_info;
+ unsigned long insn_offset;
+ unsigned long rodata_offset;
+};
+
+static void get_rodata_table_size_by_table_annotate(struct objtool_file *file,
+ struct instruction *insn,
+ unsigned long *table_size)
+{
+ struct section *rsec;
+ struct reloc *reloc;
+ struct list_head table_list;
+ struct table_info *orig_table;
+ struct table_info *next_table;
+ unsigned long tmp_insn_offset;
+ unsigned long tmp_rodata_offset;
+
+ rsec = find_section_by_name(file->elf, ".rela.discard.tablejump_annotate");
+ if (!rsec)
+ return;
+
+ INIT_LIST_HEAD(&table_list);
+
+ for_each_reloc(rsec, reloc) {
+ orig_table = malloc(sizeof(struct table_info));
+ if (!orig_table) {
+ WARN("malloc failed");
+ return;
+ }
+
+ orig_table->insn_offset = reloc->sym->offset + reloc_addend(reloc);
+ reloc++;
+ orig_table->rodata_offset = reloc->sym->offset + reloc_addend(reloc);
+
+ list_add_tail(&orig_table->jump_info, &table_list);
+
+ if (reloc_idx(reloc) + 1 == sec_num_entries(rsec))
+ break;
+ }
+
+ list_for_each_entry(orig_table, &table_list, jump_info) {
+ next_table = list_next_entry(orig_table, jump_info);
+ list_for_each_entry_from(next_table, &table_list, jump_info) {
+ if (next_table->rodata_offset < orig_table->rodata_offset) {
+ tmp_insn_offset = next_table->insn_offset;
+ tmp_rodata_offset = next_table->rodata_offset;
+ next_table->insn_offset = orig_table->insn_offset;
+ next_table->rodata_offset = orig_table->rodata_offset;
+ orig_table->insn_offset = tmp_insn_offset;
+ orig_table->rodata_offset = tmp_rodata_offset;
+ }
+ }
+ }
+
+ list_for_each_entry(orig_table, &table_list, jump_info) {
+ if (insn->offset == orig_table->insn_offset) {
+ next_table = list_next_entry(orig_table, jump_info);
+ if (&next_table->jump_info == &table_list) {
+ *table_size = 0;
+ return;
+ }
+
+ while (next_table->rodata_offset == orig_table->rodata_offset) {
+ next_table = list_next_entry(next_table, jump_info);
+ if (&next_table->jump_info == &table_list) {
+ *table_size = 0;
+ return;
+ }
+ }
+
+ *table_size = next_table->rodata_offset - orig_table->rodata_offset;
+ }
+ }
+}
+
+static struct reloc *find_reloc_by_table_annotate(struct objtool_file *file,
+ struct instruction *insn,
+ unsigned long *table_size)
+{
+ struct section *rsec;
+ struct reloc *reloc;
+ unsigned long offset;
+
+ rsec = find_section_by_name(file->elf, ".rela.discard.tablejump_annotate");
+ if (!rsec)
+ return NULL;
+
+ for_each_reloc(rsec, reloc) {
+ if (reloc->sym->sec->rodata)
+ continue;
+
+ if (strcmp(insn->sec->name, reloc->sym->sec->name))
+ continue;
+
+ offset = reloc->sym->offset + reloc_addend(reloc);
+ if (insn->offset == offset) {
+ get_rodata_table_size_by_table_annotate(file, insn, table_size);
+ reloc++;
+ return reloc;
+ }
+ }
+
+ return NULL;
+}
+
struct reloc *arch_find_switch_table(struct objtool_file *file,
struct instruction *insn,
unsigned long *table_size)
{
- return NULL;
+ struct reloc *annotate_reloc;
+ struct reloc *rodata_reloc;
+ struct section *table_sec;
+ unsigned long table_offset;
+
+ annotate_reloc = find_reloc_by_table_annotate(file, insn, table_size);
+ if (!annotate_reloc)
+ return NULL;
+
+ table_sec = annotate_reloc->sym->sec;
+ table_offset = annotate_reloc->sym->offset + reloc_addend(annotate_reloc);
+
+ /*
+ * Each table entry has a rela associated with it. The rela
+ * should reference text in the same function as the original
+ * instruction.
+ */
+ rodata_reloc = find_reloc_by_dest(file->elf, table_sec, table_offset);
+ if (!rodata_reloc)
+ return NULL;
+
+ return rodata_reloc;
}
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v7 5/7] objtool/LoongArch: Add support for goto table
2025-02-11 11:50 [PATCH v7 0/7] Add jump table support for objtool on LoongArch Tiezhu Yang
` (3 preceding siblings ...)
2025-02-11 11:50 ` [PATCH v7 4/7] objtool/LoongArch: Add support for switch table Tiezhu Yang
@ 2025-02-11 11:50 ` Tiezhu Yang
2025-03-14 20:04 ` [tip: objtool/core] " tip-bot2 for Tiezhu Yang
2025-02-11 11:50 ` [PATCH v7 6/7] LoongArch: Enable jump table for objtool Tiezhu Yang
` (2 subsequent siblings)
7 siblings, 1 reply; 14+ messages in thread
From: Tiezhu Yang @ 2025-02-11 11:50 UTC (permalink / raw)
To: Josh Poimboeuf, Peter Zijlstra, Huacai Chen; +Cc: loongarch, linux-kernel
The objtool program need to analysis the control flow of each object file
generated by compiler toolchain, it needs to know all the locations that
a branch instruction may jump into, if a jump table is used, objtool has
to correlate the jump instruction with the table.
On x86 (which is the only port supported by objtool before LoongArch),
there is a relocation type on the jump instruction and directly points
to the table. But on LoongArch, the relocation is on another kind of
instruction prior to the jump instruction, and also with scheduling it
is not very easy to tell the offset of that instruction from the jump
instruction. Furthermore, because LoongArch has -fsection-anchors (often
enabled at -O1 or above) the relocation may actually points to a section
anchor instead of the table itself.
For the jump table of switch cases, a GCC patch "LoongArch: Add support
to annotate tablejump" and a Clang patch "[LoongArch] Add options for
annotate tablejump" have been merged into the upstream mainline, it can
parse the additional section ".discard.tablejump_annotate" which stores
the jump info as pairs of addresses, each pair contains the address of
jump instruction and the address of jump table.
For the jump table of computed gotos, it is indeed not easy to implement
in the compiler, especially if there is more than one computed goto in a
function such as ___bpf_prog_run(). objdump kernel/bpf/core.o shows that
there are many table jump instructions in ___bpf_prog_run(), but there are
no relocations on the table jump instructions and to the table directly on
LoongArch.
Without the help of compiler, in order to figure out the address of goto
table for the special case of ___bpf_prog_run(), since the instruction
sequence is relatively single and stable, it makes sense to add a helper
find_reloc_of_rodata_c_jump_table() to find the relocation which points
to the section ".rodata..c_jump_table".
If find_reloc_by_table_annotate() failed, it means there is no relocation
info of switch table address in ".rela.discard.tablejump_annotate", then
objtool may find the relocation info of goto table ".rodata..c_jump_table"
with find_reloc_of_rodata_c_jump_table().
Signed-off-by: Tiezhu Yang <yangtiezhu@loongson.cn>
---
tools/objtool/arch/loongarch/special.c | 32 ++++++++++++++++++++++++--
1 file changed, 30 insertions(+), 2 deletions(-)
diff --git a/tools/objtool/arch/loongarch/special.c b/tools/objtool/arch/loongarch/special.c
index 4fa6877d5b2b..27c6473608f3 100644
--- a/tools/objtool/arch/loongarch/special.c
+++ b/tools/objtool/arch/loongarch/special.c
@@ -116,6 +116,30 @@ static struct reloc *find_reloc_by_table_annotate(struct objtool_file *file,
return NULL;
}
+static struct reloc *find_reloc_of_rodata_c_jump_table(struct section *sec,
+ unsigned long offset,
+ unsigned long *table_size)
+{
+ struct section *rsec;
+ struct reloc *reloc;
+
+ rsec = sec->rsec;
+ if (!rsec)
+ return NULL;
+
+ for_each_reloc(rsec, reloc) {
+ if (reloc_offset(reloc) > offset)
+ break;
+
+ if (!strncmp(reloc->sym->sec->name, ".rodata..c_jump_table", 21)) {
+ *table_size = 0;
+ return reloc;
+ }
+ }
+
+ return NULL;
+}
+
struct reloc *arch_find_switch_table(struct objtool_file *file,
struct instruction *insn,
unsigned long *table_size)
@@ -126,8 +150,12 @@ struct reloc *arch_find_switch_table(struct objtool_file *file,
unsigned long table_offset;
annotate_reloc = find_reloc_by_table_annotate(file, insn, table_size);
- if (!annotate_reloc)
- return NULL;
+ if (!annotate_reloc) {
+ annotate_reloc = find_reloc_of_rodata_c_jump_table(
+ insn->sec, insn->offset, table_size);
+ if (!annotate_reloc)
+ return NULL;
+ }
table_sec = annotate_reloc->sym->sec;
table_offset = annotate_reloc->sym->offset + reloc_addend(annotate_reloc);
--
2.42.0
^ permalink raw reply [flat|nested] 14+ messages in thread* [tip: objtool/core] objtool/LoongArch: Add support for goto table
2025-02-11 11:50 ` [PATCH v7 5/7] objtool/LoongArch: Add support for goto table Tiezhu Yang
@ 2025-03-14 20:04 ` tip-bot2 for Tiezhu Yang
0 siblings, 0 replies; 14+ messages in thread
From: tip-bot2 for Tiezhu Yang @ 2025-03-14 20:04 UTC (permalink / raw)
To: linux-tip-commits
Cc: Tiezhu Yang, Huacai Chen, Josh Poimboeuf, x86, linux-kernel
The following commit has been merged into the objtool/core branch of tip:
Commit-ID: 88cbb468d4545526a33126f8a41352cac6dd0f3c
Gitweb: https://git.kernel.org/tip/88cbb468d4545526a33126f8a41352cac6dd0f3c
Author: Tiezhu Yang <yangtiezhu@loongson.cn>
AuthorDate: Tue, 11 Feb 2025 19:50:14 +08:00
Committer: Josh Poimboeuf <jpoimboe@kernel.org>
CommitterDate: Wed, 12 Mar 2025 15:43:39 -07:00
objtool/LoongArch: Add support for goto table
The objtool program need to analysis the control flow of each object file
generated by compiler toolchain, it needs to know all the locations that
a branch instruction may jump into, if a jump table is used, objtool has
to correlate the jump instruction with the table.
On x86 (which is the only port supported by objtool before LoongArch),
there is a relocation type on the jump instruction and directly points
to the table. But on LoongArch, the relocation is on another kind of
instruction prior to the jump instruction, and also with scheduling it
is not very easy to tell the offset of that instruction from the jump
instruction. Furthermore, because LoongArch has -fsection-anchors (often
enabled at -O1 or above) the relocation may actually points to a section
anchor instead of the table itself.
For the jump table of switch cases, a GCC patch "LoongArch: Add support
to annotate tablejump" and a Clang patch "[LoongArch] Add options for
annotate tablejump" have been merged into the upstream mainline, it can
parse the additional section ".discard.tablejump_annotate" which stores
the jump info as pairs of addresses, each pair contains the address of
jump instruction and the address of jump table.
For the jump table of computed gotos, it is indeed not easy to implement
in the compiler, especially if there is more than one computed goto in a
function such as ___bpf_prog_run(). objdump kernel/bpf/core.o shows that
there are many table jump instructions in ___bpf_prog_run(), but there are
no relocations on the table jump instructions and to the table directly on
LoongArch.
Without the help of compiler, in order to figure out the address of goto
table for the special case of ___bpf_prog_run(), since the instruction
sequence is relatively single and stable, it makes sense to add a helper
find_reloc_of_rodata_c_jump_table() to find the relocation which points
to the section ".rodata..c_jump_table".
If find_reloc_by_table_annotate() failed, it means there is no relocation
info of switch table address in ".rela.discard.tablejump_annotate", then
objtool may find the relocation info of goto table ".rodata..c_jump_table"
with find_reloc_of_rodata_c_jump_table().
Signed-off-by: Tiezhu Yang <yangtiezhu@loongson.cn>
Link: https://lore.kernel.org/r/20250211115016.26913-6-yangtiezhu@loongson.cn
Acked-by: Huacai Chen <chenhuacai@loongson.cn>
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
---
tools/objtool/arch/loongarch/special.c | 32 +++++++++++++++++++++++--
1 file changed, 30 insertions(+), 2 deletions(-)
diff --git a/tools/objtool/arch/loongarch/special.c b/tools/objtool/arch/loongarch/special.c
index 4fa6877..e39f86d 100644
--- a/tools/objtool/arch/loongarch/special.c
+++ b/tools/objtool/arch/loongarch/special.c
@@ -116,6 +116,30 @@ static struct reloc *find_reloc_by_table_annotate(struct objtool_file *file,
return NULL;
}
+static struct reloc *find_reloc_of_rodata_c_jump_table(struct section *sec,
+ unsigned long offset,
+ unsigned long *table_size)
+{
+ struct section *rsec;
+ struct reloc *reloc;
+
+ rsec = sec->rsec;
+ if (!rsec)
+ return NULL;
+
+ for_each_reloc(rsec, reloc) {
+ if (reloc_offset(reloc) > offset)
+ break;
+
+ if (!strcmp(reloc->sym->sec->name, C_JUMP_TABLE_SECTION)) {
+ *table_size = 0;
+ return reloc;
+ }
+ }
+
+ return NULL;
+}
+
struct reloc *arch_find_switch_table(struct objtool_file *file,
struct instruction *insn,
unsigned long *table_size)
@@ -126,8 +150,12 @@ struct reloc *arch_find_switch_table(struct objtool_file *file,
unsigned long table_offset;
annotate_reloc = find_reloc_by_table_annotate(file, insn, table_size);
- if (!annotate_reloc)
- return NULL;
+ if (!annotate_reloc) {
+ annotate_reloc = find_reloc_of_rodata_c_jump_table(
+ insn->sec, insn->offset, table_size);
+ if (!annotate_reloc)
+ return NULL;
+ }
table_sec = annotate_reloc->sym->sec;
table_offset = annotate_reloc->sym->offset + reloc_addend(annotate_reloc);
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v7 6/7] LoongArch: Enable jump table for objtool
2025-02-11 11:50 [PATCH v7 0/7] Add jump table support for objtool on LoongArch Tiezhu Yang
` (4 preceding siblings ...)
2025-02-11 11:50 ` [PATCH v7 5/7] objtool/LoongArch: Add support for goto table Tiezhu Yang
@ 2025-02-11 11:50 ` Tiezhu Yang
2025-02-11 11:50 ` [PATCH v7 7/7] LoongArch: Convert unreachable() to BUG() Tiezhu Yang
2025-03-08 5:47 ` [PATCH v7 0/7] Add jump table support for objtool on LoongArch Huacai Chen
7 siblings, 0 replies; 14+ messages in thread
From: Tiezhu Yang @ 2025-02-11 11:50 UTC (permalink / raw)
To: Josh Poimboeuf, Peter Zijlstra, Huacai Chen; +Cc: loongarch, linux-kernel
For now, it is time to remove -fno-jump-tables to enable jump table for
objtool if the compiler has -mannotate-tablejump, otherwise it is better
to remain -fno-jump-tables to keep compatibility with older compilers.
Signed-off-by: Tiezhu Yang <yangtiezhu@loongson.cn>
---
arch/loongarch/Kconfig | 3 +++
arch/loongarch/Makefile | 6 +++++-
2 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig
index 2b8bd27a852f..15aaa2e6757e 100644
--- a/arch/loongarch/Kconfig
+++ b/arch/loongarch/Kconfig
@@ -291,6 +291,9 @@ config AS_HAS_LBT_EXTENSION
config AS_HAS_LVZ_EXTENSION
def_bool $(as-instr,hvcl 0)
+config CC_HAS_ANNOTATE_TABLEJUMP
+ def_bool $(cc-option,-mannotate-tablejump)
+
menu "Kernel type and options"
source "kernel/Kconfig.hz"
diff --git a/arch/loongarch/Makefile b/arch/loongarch/Makefile
index 567bd122a9ee..0304eabbe606 100644
--- a/arch/loongarch/Makefile
+++ b/arch/loongarch/Makefile
@@ -101,7 +101,11 @@ KBUILD_AFLAGS += $(call cc-option,-mthin-add-sub) $(call cc-option,-Wa$(comma)
KBUILD_CFLAGS += $(call cc-option,-mthin-add-sub) $(call cc-option,-Wa$(comma)-mthin-add-sub)
ifdef CONFIG_OBJTOOL
-KBUILD_CFLAGS += -fno-jump-tables
+ifdef CONFIG_CC_HAS_ANNOTATE_TABLEJUMP
+KBUILD_CFLAGS += -mannotate-tablejump
+else
+KBUILD_CFLAGS += -fno-jump-tables # keep compatibility with older compilers
+endif
endif
KBUILD_RUSTFLAGS += --target=loongarch64-unknown-none-softfloat -Ccode-model=small
--
2.42.0
^ permalink raw reply [flat|nested] 14+ messages in thread* [PATCH v7 7/7] LoongArch: Convert unreachable() to BUG()
2025-02-11 11:50 [PATCH v7 0/7] Add jump table support for objtool on LoongArch Tiezhu Yang
` (5 preceding siblings ...)
2025-02-11 11:50 ` [PATCH v7 6/7] LoongArch: Enable jump table for objtool Tiezhu Yang
@ 2025-02-11 11:50 ` Tiezhu Yang
2025-03-08 5:47 ` [PATCH v7 0/7] Add jump table support for objtool on LoongArch Huacai Chen
7 siblings, 0 replies; 14+ messages in thread
From: Tiezhu Yang @ 2025-02-11 11:50 UTC (permalink / raw)
To: Josh Poimboeuf, Peter Zijlstra, Huacai Chen; +Cc: loongarch, linux-kernel
When compiling on LoongArch, there exists the following objtool
warning in arch/loongarch/kernel/machine_kexec.o:
kexec_reboot() falls through to next function crash_shutdown_secondary()
Avoid unreachable() as it can (and will in the absence of UBSAN)
generate fallthrough code. Use BUG() so we get a "break BRK_BUG"
trap (with unreachable annotation).
Signed-off-by: Tiezhu Yang <yangtiezhu@loongson.cn>
---
arch/loongarch/kernel/machine_kexec.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/loongarch/kernel/machine_kexec.c b/arch/loongarch/kernel/machine_kexec.c
index 8ae641dc53bb..f9381800e291 100644
--- a/arch/loongarch/kernel/machine_kexec.c
+++ b/arch/loongarch/kernel/machine_kexec.c
@@ -126,14 +126,14 @@ void kexec_reboot(void)
/* All secondary cpus go to kexec_smp_wait */
if (smp_processor_id() > 0) {
relocated_kexec_smp_wait(NULL);
- unreachable();
+ BUG();
}
#endif
do_kexec = (void *)reboot_code_buffer;
do_kexec(efi_boot, cmdline_ptr, systable_ptr, start_addr, first_ind_entry);
- unreachable();
+ BUG();
}
--
2.42.0
^ permalink raw reply [flat|nested] 14+ messages in thread* Re: [PATCH v7 0/7] Add jump table support for objtool on LoongArch
2025-02-11 11:50 [PATCH v7 0/7] Add jump table support for objtool on LoongArch Tiezhu Yang
` (6 preceding siblings ...)
2025-02-11 11:50 ` [PATCH v7 7/7] LoongArch: Convert unreachable() to BUG() Tiezhu Yang
@ 2025-03-08 5:47 ` Huacai Chen
7 siblings, 0 replies; 14+ messages in thread
From: Huacai Chen @ 2025-03-08 5:47 UTC (permalink / raw)
To: Tiezhu Yang; +Cc: Josh Poimboeuf, Peter Zijlstra, loongarch, linux-kernel
Hi, Josh and Peter,
Since "unreachable: Unify", "x86: Convert unreachable() to BUG()" and
other relevant patches have been backported to 6.12/6.13, I think the
7th of this series should also be backported to avoid build warnings.
Since tip.git hasn't applied this series, I will apply the 7th patch
as part of loongarch-fixes now.
Huacai
On Tue, Feb 11, 2025 at 7:50 PM Tiezhu Yang <yangtiezhu@loongson.cn> wrote:
>
> This version is based on tip/tip.git master branch [1], the patch
> "objtool: Handle unreachable entry of rodata" is dropped, tested
> with the latest mainline Binutils, GCC and Clang (2025-02-11).
>
> [1] https://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git/log/?h=master
>
> Tiezhu Yang (7):
> objtool: Handle various symbol types of rodata
> objtool: Handle different entry size of rodata
> objtool: Handle PC relative relocation type
> objtool/LoongArch: Add support for switch table
> objtool/LoongArch: Add support for goto table
> LoongArch: Enable jump table for objtool
> LoongArch: Convert unreachable() to BUG()
>
> arch/loongarch/Kconfig | 3 +
> arch/loongarch/Makefile | 6 +-
> arch/loongarch/kernel/machine_kexec.c | 4 +-
> tools/objtool/arch/loongarch/decode.c | 28 ++-
> .../objtool/arch/loongarch/include/arch/elf.h | 7 +
> tools/objtool/arch/loongarch/special.c | 159 +++++++++++++++++-
> tools/objtool/arch/powerpc/decode.c | 15 ++
> tools/objtool/arch/x86/decode.c | 13 ++
> tools/objtool/check.c | 23 ++-
> tools/objtool/include/objtool/arch.h | 3 +
> 10 files changed, 247 insertions(+), 14 deletions(-)
>
> --
> 2.42.0
>
^ permalink raw reply [flat|nested] 14+ messages in thread