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) + if (rela) { + rela->jump_table_start = true; + insn->jump_table = 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; - /* - * 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; - } - - prev_jump = insn; - prev_rela = rela; - } - - 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; diff --git a/tools/objtool/check.h b/tools/objtool/check.h index cb60b9acf5cf..afa6a79e0715 100644 --- a/tools/objtool/check.h +++ b/tools/objtool/check.h @@ -38,6 +38,7 @@ struct instruction { struct symbol *call_dest; struct instruction *jump_dest; struct instruction *first_jump_src; + struct rela *jump_table; struct list_head alts; struct symbol *func; struct stack_op stack_op; diff --git a/tools/objtool/elf.h b/tools/objtool/elf.h index d4d3e0528d4a..44150204db4d 100644 --- a/tools/objtool/elf.h +++ b/tools/objtool/elf.h @@ -62,6 +62,7 @@ struct rela { unsigned int type; unsigned long offset; int addend; + bool jump_table_start; }; struct elf {