[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <3e31a9910c471ad9c17b76a96cc910e7a8aa2a10.1736955567.git.christophe.leroy@csgroup.eu>
Date: Wed, 15 Jan 2025 23:42:49 +0100
From: Christophe Leroy <christophe.leroy@...roup.eu>
To: Josh Poimboeuf <jpoimboe@...nel.org>,
Peter Zijlstra <peterz@...radead.org>,
Nathan Chancellor <nathan@...nel.org>,
Nick Desaulniers <ndesaulniers@...gle.com>,
Bill Wendling <morbo@...gle.com>,
Justin Stitt <justinstitt@...gle.com>,
Julien Thierry <jthierry@...hat.com>,
Miroslav Benes <mbenes@...e.cz>,
Raphael Gault <raphael.gault@....com>,
Michael Ellerman <mpe@...erman.id.au>,
Nicholas Piggin <npiggin@...il.com>,
Naveen N Rao <naveen@...nel.org>,
Madhavan Srinivasan <maddy@...ux.ibm.com>
Cc: Christophe Leroy <christophe.leroy@...roup.eu>,
linux-kernel@...r.kernel.org,
linuxppc-dev@...ts.ozlabs.org,
llvm@...ts.linux.dev
Subject: [PATCH v5 09/15] objtool: Find end of switch table directly
At the time being, the end of a switch table can only be known
once the start of the following switch table has ben located.
This is a problem when switch tables are nested because until the first
switch table is properly added, the second one cannot be located as a
the backward walk will abut on the dynamic switch of the previous one.
So perform a first forward walk in the code in order to locate all
possible relocations to switch tables and build a local table with
those relocations. Later on once one switch table is found, go through
this local table to know where next switch table starts.
Signed-off-by: Christophe Leroy <christophe.leroy@...roup.eu>
---
tools/objtool/check.c | 63 ++++++++++++++++++++++++++++++++-----------
1 file changed, 47 insertions(+), 16 deletions(-)
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 72b977f81dd6..0ad2bdd92232 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -2058,14 +2058,30 @@ static void find_jump_table(struct objtool_file *file, struct symbol *func,
}
}
+static struct reloc *find_next_table(struct instruction *insn,
+ struct reloc **table, unsigned int size)
+{
+ unsigned long offset = reloc_offset(insn_jump_table(insn));
+ int i;
+ struct reloc *reloc = NULL;
+
+ for (i = 0; i < size; i++) {
+ if (reloc_offset(table[i]) > offset &&
+ (!reloc || reloc_offset(table[i]) < reloc_offset(reloc)))
+ reloc = table[i];
+ }
+ return reloc;
+}
+
/*
* First pass: Mark the head of each jump table so that in the next pass,
* we know when a given jump table ends and the next one starts.
*/
static int mark_add_func_jump_tables(struct objtool_file *file,
- struct symbol *func)
+ struct symbol *func,
+ struct reloc **table, unsigned int size)
{
- struct instruction *insn, *last = NULL, *insn_t1 = NULL, *insn_t2;
+ struct instruction *insn, *last = NULL;
int ret = 0;
func_for_each_insn(file, func, insn) {
@@ -2094,23 +2110,11 @@ static int mark_add_func_jump_tables(struct objtool_file *file,
if (!insn_jump_table(insn))
continue;
- if (!insn_t1) {
- insn_t1 = insn;
- continue;
- }
-
- insn_t2 = insn;
-
- ret = add_jump_table(file, insn_t1, insn_jump_table(insn_t2));
+ ret = add_jump_table(file, insn, find_next_table(insn, table, size));
if (ret)
return ret;
-
- insn_t1 = insn_t2;
}
- if (insn_t1)
- ret = add_jump_table(file, insn_t1, NULL);
-
return ret;
}
@@ -2123,15 +2127,42 @@ static int add_jump_table_alts(struct objtool_file *file)
{
struct symbol *func;
int ret;
+ struct instruction *insn;
+ unsigned int size = 0, i = 0;
+ struct reloc **table = NULL;
if (!file->rodata)
return 0;
+ for_each_insn(file, insn) {
+ struct instruction *dest_insn;
+ struct reloc *reloc;
+ unsigned long table_size;
+
+ func = insn_func(insn) ? insn_func(insn)->pfunc : NULL;
+ reloc = arch_find_switch_table(file, insn, &table_size, NULL);
+ /*
+ * Each table entry has a rela associated with it. The rela
+ * should reference text in the same function as the original
+ * instruction.
+ */
+ if (!reloc)
+ continue;
+ dest_insn = find_insn(file, reloc->sym->sec, reloc_addend(reloc));
+ if (!dest_insn || !insn_func(dest_insn) || insn_func(dest_insn)->pfunc != func)
+ continue;
+ if (i == size) {
+ size += 1024;
+ table = realloc(table, size * sizeof(*table));
+ }
+ table[i++] = reloc;
+ }
+
for_each_sym(file, func) {
if (func->type != STT_FUNC)
continue;
- ret = mark_add_func_jump_tables(file, func);
+ ret = mark_add_func_jump_tables(file, func, table, i);
if (ret)
return ret;
}
--
2.47.0
Powered by blists - more mailing lists