[PATCH v1 2/6] objtool/LoongArch: Add support for jump table

From: Tiezhu Yang
Date: Tue Oct 15 2024 - 07:40:05 EST


The objtool program needs to analysis the control flow of each object
file generated by compiler toolchain, 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,
the relocation is directly on the jump instruction and to the table.
But on LoongArch, the relocation is on some kind of instruction prior
to the jump instruction, with scheduling it is not easy to tell the
offset of that instruction from the jump instruction. Furthermore,
because LoongArch has -fsection-anchors the relocation may actually
points to a section anchor instead of the table itself. So it needs
some non-trivial data flow analysis in objtool without special support
of compiler.

The good news is that the GCC patch "LoongArch: Add support to annotate
tablejump" has been merged into the upstream mainline, the changes are
very trivial in GCC, it makes life much easier for jump 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.

Link: https://gcc.gnu.org/git/?p=gcc.git;a=commit;h=0ee028f55640
Signed-off-by: Tiezhu Yang <yangtiezhu@xxxxxxxxxxx>
---
tools/objtool/arch/loongarch/special.c | 53 +++++++++++++++++++++++++-
1 file changed, 52 insertions(+), 1 deletion(-)

diff --git a/tools/objtool/arch/loongarch/special.c b/tools/objtool/arch/loongarch/special.c
index 9bba1e9318e0..65b1ed297d57 100644
--- a/tools/objtool/arch/loongarch/special.c
+++ b/tools/objtool/arch/loongarch/special.c
@@ -1,4 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-or-later
+#include <string.h>
+
#include <objtool/special.h>

bool arch_support_alt_relocation(struct special_alt *special_alt,
@@ -8,8 +10,57 @@ bool arch_support_alt_relocation(struct special_alt *special_alt,
return false;
}

+static struct reloc *find_reloc_by_table_annotate(struct objtool_file *file,
+ struct instruction *insn)
+{
+ 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;
+ if (insn->offset == offset) {
+ reloc++;
+ return reloc;
+ }
+ }
+
+ return NULL;
+}
+
struct reloc *arch_find_switch_table(struct objtool_file *file,
struct instruction *insn)
{
- 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);
+ if (!annotate_reloc)
+ return NULL;
+
+ table_sec = annotate_reloc->sym->sec;
+ table_offset = annotate_reloc->sym->offset;
+
+ /*
+ * 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