lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite for Android: free password hash cracker in your pocket
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20241122045005.14617-9-yangtiezhu@loongson.cn>
Date: Fri, 22 Nov 2024 12:50:03 +0800
From: Tiezhu Yang <yangtiezhu@...ngson.cn>
To: Huacai Chen <chenhuacai@...nel.org>,
	Josh Poimboeuf <jpoimboe@...nel.org>,
	Peter Zijlstra <peterz@...radead.org>
Cc: loongarch@...ts.linux.dev,
	linux-kernel@...r.kernel.org
Subject: [PATCH v4 08/10] objtool/LoongArch: Add support for switch table

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@...ngson.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


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ