summaryrefslogtreecommitdiff
path: root/tools/objtool/check.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/objtool/check.c')
-rw-r--r--tools/objtool/check.c53
1 files changed, 28 insertions, 25 deletions
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 4525cf677a1b..66f7c01385a4 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -900,7 +900,7 @@ out:
}
static int add_jump_table(struct objtool_file *file, struct instruction *insn,
- struct rela *table, struct rela *next_table)
+ struct rela *table)
{
struct rela *rela = table;
struct instruction *dest_insn;
@@ -913,7 +913,9 @@ static int add_jump_table(struct objtool_file *file, struct instruction *insn,
* instruction.
*/
list_for_each_entry_from(rela, &table->sec->rela_list, list) {
- if (rela == next_table)
+
+ /* Check for the end of the table: */
+ if (rela != table && rela->jump_table_start)
break;
/* Make sure the table entries are consecutive: */
@@ -1072,13 +1074,15 @@ static struct rela *find_jump_table(struct objtool_file *file,
return NULL;
}
-
-static int add_func_jump_tables(struct objtool_file *file,
- struct symbol *func)
+/*
+ * 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 void mark_func_jump_tables(struct objtool_file *file,
+ struct symbol *func)
{
- struct instruction *insn, *last = NULL, *prev_jump = NULL;
- struct rela *rela, *prev_rela = NULL;
- int ret;
+ struct instruction *insn, *last = NULL;
+ struct rela *rela;
func_for_each_insn_all(file, func, insn) {
if (!last)
@@ -1102,26 +1106,24 @@ static int add_func_jump_tables(struct objtool_file *file,
continue;
rela = find_jump_table(file, func, insn);
- if (!rela)
- continue;
-
- /*
- * We found a jump table, but we don't know yet how big it
- * is. Don't add it until we reach the end of the function or
- * the beginning of another jump table in the same function.
- */
- if (prev_jump) {
- ret = add_jump_table(file, prev_jump, prev_rela, rela);
- if (ret)
- return ret;
+ if (rela) {
+ rela->jump_table_start = true;
+ insn->jump_table = rela;
}
-
- prev_jump = insn;
- prev_rela = rela;
}
+}
+
+static int add_func_jump_tables(struct objtool_file *file,
+ struct symbol *func)
+{
+ struct instruction *insn;
+ int ret;
+
+ func_for_each_insn_all(file, func, insn) {
+ if (!insn->jump_table)
+ continue;
- if (prev_jump) {
- ret = add_jump_table(file, prev_jump, prev_rela, NULL);
+ ret = add_jump_table(file, insn, insn->jump_table);
if (ret)
return ret;
}
@@ -1148,6 +1150,7 @@ static int add_jump_table_alts(struct objtool_file *file)
if (func->type != STT_FUNC)
continue;
+ mark_func_jump_tables(file, func);
ret = add_func_jump_tables(file, func);
if (ret)
return ret;