The objtool program needs 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 on the jump instruction and to the table directly. But on
LoongArch, the relocation is on some kind of instruction prior to the jump
instruction, and also with scheduling it is not 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 discussions, 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.
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 | 60 +++++++++++++++++++++++++-
1 file changed, 59 insertions(+), 1 deletion(-)
diff --git a/tools/objtool/arch/loongarch/special.c b/tools/objtool/arch/loongarch/special.c
index 454bd01226a4..366517deb35b 100644
--- a/tools/objtool/arch/loongarch/special.c
+++ b/tools/objtool/arch/loongarch/special.c
@@ -1,4 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-or-later
+#include <string.h>
#include <objtool/special.h>
#include <objtool/warn.h>
@@ -80,8 +81,65 @@ static void get_rodata_table_size_by_table_annotate(struct objtool_file *file,
}
}
+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;
+
+ if (reloc->sym->type == STT_SECTION)
+ offset = reloc_addend(reloc);
+ else
+ offset = reloc->sym->offset;
+
+ if (insn->offset == offset) {
+ get_rodata_table_size_by_table_annotate(file, insn);
+ 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;
+ if (annotate_reloc->sym->type == STT_SECTION)
+ table_offset = reloc_addend(annotate_reloc);
+ else
+ 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