[PATCH v2 3/5] objtool/LoongArch: Add support for switch table

Tiezhu Yang posted 5 patches 2 weeks, 4 days ago
There is a newer version of this series
[PATCH v2 3/5] objtool/LoongArch: Add support for switch table
Posted by Tiezhu Yang 2 weeks, 4 days ago
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.

There is a GCC patch "LoongArch: Add support to annotate tablejump" which
has been merged into the upstream mainline, the changes are very trivial
in GCC, it makes 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
Signed-off-by: Tiezhu Yang <yangtiezhu@loongson.cn>
---
 tools/objtool/arch/loongarch/special.c | 59 +++++++++++++++++++++++++-
 1 file changed, 58 insertions(+), 1 deletion(-)

diff --git a/tools/objtool/arch/loongarch/special.c b/tools/objtool/arch/loongarch/special.c
index 9bba1e9318e0..31e0f94e31e8 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>
 
 bool arch_support_alt_relocation(struct special_alt *special_alt,
@@ -8,8 +9,64 @@ 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;
+
+		if (reloc->sym->type == STT_SECTION)
+			offset = reloc_addend(reloc);
+		else
+			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;
+	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