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.

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>
Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
Signed-off-by: michael <michael5hzg@gmail.com>
Signed-off-by: maoxiaochuan <maoxiaochuan@loongson.cn>
This commit is contained in:
Tiezhu Yang
2025-02-13 14:26:41 +08:00
committed by maoxiaochuan
parent 9e2e5de7f8
commit c095d3e54a
+59 -1
View File
@@ -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;
}