mirror of
https://gitee.com/open-loongarch/linux-6.12.git
synced 2026-10-28 05:57:12 +08: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. 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:
committed by
maoxiaochuan
parent
9e2e5de7f8
commit
c095d3e54a
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user