From: Ard Biesheuvel <[email protected]> In preparation for implementing support for the use of compiler emitted jump table annotations, move the existing code out of the generic sources. This will permit a clean separation between the two approaches, where the old one will not be wired up for architectures other than x86.
Signed-off-by: Ard Biesheuvel <[email protected]> --- tools/objtool/arch/loongarch/special.c | 7 -- tools/objtool/arch/powerpc/special.c | 7 -- tools/objtool/arch/x86/special.c | 114 +++++++++++++++++++- tools/objtool/check.c | 112 +------------------ tools/objtool/include/objtool/special.h | 9 +- 5 files changed, 122 insertions(+), 127 deletions(-) diff --git a/tools/objtool/arch/loongarch/special.c b/tools/objtool/arch/loongarch/special.c index 87230ed570fd..acf3a391a2f9 100644 --- a/tools/objtool/arch/loongarch/special.c +++ b/tools/objtool/arch/loongarch/special.c @@ -7,10 +7,3 @@ bool arch_support_alt_relocation(struct special_alt *special_alt, { return false; } - -struct reloc *arch_find_switch_table(struct objtool_file *file, - struct instruction *insn, - unsigned long *table_size) -{ - return NULL; -} diff --git a/tools/objtool/arch/powerpc/special.c b/tools/objtool/arch/powerpc/special.c index 51610689abf7..3a108437cfa6 100644 --- a/tools/objtool/arch/powerpc/special.c +++ b/tools/objtool/arch/powerpc/special.c @@ -11,10 +11,3 @@ bool arch_support_alt_relocation(struct special_alt *special_alt, { exit(-1); } - -struct reloc *arch_find_switch_table(struct objtool_file *file, - struct instruction *insn, - unsigned long *table_size) -{ - exit(-1); -} diff --git a/tools/objtool/arch/x86/special.c b/tools/objtool/arch/x86/special.c index f8fb67636384..cd964b85e2b1 100644 --- a/tools/objtool/arch/x86/special.c +++ b/tools/objtool/arch/x86/special.c @@ -108,9 +108,9 @@ bool arch_support_alt_relocation(struct special_alt *special_alt, * * NOTE: MITIGATION_RETPOLINE made it harder still to decode dynamic jumps. */ -struct reloc *arch_find_switch_table(struct objtool_file *file, - struct instruction *insn, - unsigned long *table_size) +static struct reloc *find_switch_table(struct objtool_file *file, + struct instruction *insn, + unsigned long *table_size) { struct reloc *text_reloc, *rodata_reloc; struct section *table_sec; @@ -154,3 +154,111 @@ struct reloc *arch_find_switch_table(struct objtool_file *file, *table_size = 0; return rodata_reloc; } + +/* + * find_jump_table() - Given a dynamic jump, find the switch jump table + * associated with it. + */ +static void find_jump_table(struct objtool_file *file, + struct symbol *func, + struct instruction *insn) +{ + struct reloc *table_reloc; + struct instruction *dest_insn, *orig_insn = insn; + unsigned long table_size; + + /* + * Backward search using the @first_jump_src links, these help avoid + * much of the 'in between' code. Which avoids us getting confused by + * it. + */ + for (; + insn && insn_func(insn) && insn_func(insn)->pfunc == func; + insn = insn->first_jump_src ?: prev_insn_same_sym(file, insn)) { + + if (insn != orig_insn && insn->type == INSN_JUMP_DYNAMIC) + break; + + /* allow small jumps within the range */ + if (insn->type == INSN_JUMP_UNCONDITIONAL && + insn->jump_dest && + (insn->jump_dest->offset <= insn->offset || + insn->jump_dest->offset > orig_insn->offset)) + break; + + table_reloc = find_switch_table(file, insn, &table_size); + if (!table_reloc) + continue; + dest_insn = find_insn(file, table_reloc->sym->sec, reloc_addend(table_reloc)); + if (!dest_insn || !insn_func(dest_insn) || insn_func(dest_insn)->pfunc != func) + continue; + + orig_insn->_jump_table = table_reloc; + orig_insn->_jump_table_size = table_size; + break; + } +} + +/* + * 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; + + func_for_each_insn(file, func, insn) { + if (!last) + last = insn; + + /* + * Store back-pointers for unconditional forward jumps such + * that find_jump_table() can back-track using those and + * avoid some potentially confusing code. + */ + if (insn->type == INSN_JUMP_UNCONDITIONAL && insn->jump_dest && + insn->offset > last->offset && + insn->jump_dest->offset > insn->offset && + !insn->jump_dest->first_jump_src) { + + insn->jump_dest->first_jump_src = insn; + last = insn->jump_dest; + } + + if (insn->type == INSN_JUMP_DYNAMIC) + find_jump_table(file, func, insn); + } +} + +int add_func_jump_tables(struct objtool_file *file, + struct symbol *func) +{ + struct instruction *insn, *insn_t1 = NULL, *insn_t2; + int ret = 0; + + mark_func_jump_tables(file, func); + + func_for_each_insn(file, func, insn) { + 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)); + if (ret) + return ret; + + insn_t1 = insn_t2; + } + + if (insn_t1) + ret = add_jump_table(file, insn_t1, NULL); + + return ret; +} diff --git a/tools/objtool/check.c b/tools/objtool/check.c index fbb05e973acc..389475dde47c 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -2091,8 +2091,8 @@ static int add_special_section_alts(struct objtool_file *file) return ret; } -static int add_jump_table(struct objtool_file *file, struct instruction *insn, - struct reloc *next_table) +int add_jump_table(struct objtool_file *file, struct instruction *insn, + struct reloc *next_table) { unsigned long table_size = insn_jump_table_size(insn); struct symbol *pfunc = insn_func(insn)->pfunc; @@ -2169,111 +2169,10 @@ static int add_jump_table(struct objtool_file *file, struct instruction *insn, return 0; } -/* - * find_jump_table() - Given a dynamic jump, find the switch jump table - * associated with it. - */ -static void find_jump_table(struct objtool_file *file, struct symbol *func, - struct instruction *insn) +int __weak add_func_jump_tables(struct objtool_file *file, + struct symbol *func) { - struct reloc *table_reloc; - struct instruction *dest_insn, *orig_insn = insn; - unsigned long table_size; - - /* - * Backward search using the @first_jump_src links, these help avoid - * much of the 'in between' code. Which avoids us getting confused by - * it. - */ - for (; - insn && insn_func(insn) && insn_func(insn)->pfunc == func; - insn = insn->first_jump_src ?: prev_insn_same_sym(file, insn)) { - - if (insn != orig_insn && insn->type == INSN_JUMP_DYNAMIC) - break; - - /* allow small jumps within the range */ - if (insn->type == INSN_JUMP_UNCONDITIONAL && - insn->jump_dest && - (insn->jump_dest->offset <= insn->offset || - insn->jump_dest->offset > orig_insn->offset)) - break; - - table_reloc = arch_find_switch_table(file, insn, &table_size); - if (!table_reloc) - continue; - dest_insn = find_insn(file, table_reloc->sym->sec, reloc_addend(table_reloc)); - if (!dest_insn || !insn_func(dest_insn) || insn_func(dest_insn)->pfunc != func) - continue; - - orig_insn->_jump_table = table_reloc; - orig_insn->_jump_table_size = table_size; - break; - } -} - -/* - * 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; - - func_for_each_insn(file, func, insn) { - if (!last) - last = insn; - - /* - * Store back-pointers for unconditional forward jumps such - * that find_jump_table() can back-track using those and - * avoid some potentially confusing code. - */ - if (insn->type == INSN_JUMP_UNCONDITIONAL && insn->jump_dest && - insn->offset > last->offset && - insn->jump_dest->offset > insn->offset && - !insn->jump_dest->first_jump_src) { - - insn->jump_dest->first_jump_src = insn; - last = insn->jump_dest; - } - - if (insn->type != INSN_JUMP_DYNAMIC) - continue; - - find_jump_table(file, func, insn); - } -} - -static int add_func_jump_tables(struct objtool_file *file, - struct symbol *func) -{ - struct instruction *insn, *insn_t1 = NULL, *insn_t2; - int ret = 0; - - func_for_each_insn(file, func, insn) { - 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)); - if (ret) - return ret; - - insn_t1 = insn_t2; - } - - if (insn_t1) - ret = add_jump_table(file, insn_t1, NULL); - - return ret; + return 0; } /* @@ -2293,7 +2192,6 @@ 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/include/objtool/special.h b/tools/objtool/include/objtool/special.h index e7ee7ffccefd..019b511eca6e 100644 --- a/tools/objtool/include/objtool/special.h +++ b/tools/objtool/include/objtool/special.h @@ -37,7 +37,10 @@ void arch_handle_alternative(unsigned short feature, struct special_alt *alt); bool arch_support_alt_relocation(struct special_alt *special_alt, struct instruction *insn, struct reloc *reloc); -struct reloc *arch_find_switch_table(struct objtool_file *file, - struct instruction *insn, - unsigned long *table_size); + +int add_func_jump_tables(struct objtool_file *file, struct symbol *func); + +int add_jump_table(struct objtool_file *file, struct instruction *insn, + struct reloc *next_table); + #endif /* _SPECIAL_H */ -- 2.47.0.rc1.288.g06298d1525-goog
