Skip to content

Commit

Permalink
objtool: Allow arch code to discover jump table size
Browse files Browse the repository at this point in the history
In preparation for adding support for annotated jump tables, where
ELF relocations and symbols are used to describe the locations of jump
tables in the executable, refactor the jump table discovery logic so the
table size can be returned from arch_find_switch_table().

Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://lkml.kernel.org/r/20241011170847.334429-12-ardb+git@google.com
  • Loading branch information
Ard Biesheuvel authored and Peter Zijlstra committed Dec 2, 2024
1 parent e7e0eb5 commit c3cb6c1
Show file tree
Hide file tree
Showing 6 changed files with 33 additions and 16 deletions.
3 changes: 2 additions & 1 deletion tools/objtool/arch/loongarch/special.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ bool arch_support_alt_relocation(struct special_alt *special_alt,
}

struct reloc *arch_find_switch_table(struct objtool_file *file,
struct instruction *insn)
struct instruction *insn,
unsigned long *table_size)
{
return NULL;
}
3 changes: 2 additions & 1 deletion tools/objtool/arch/powerpc/special.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ bool arch_support_alt_relocation(struct special_alt *special_alt,
}

struct reloc *arch_find_switch_table(struct objtool_file *file,
struct instruction *insn)
struct instruction *insn,
unsigned long *table_size)
{
exit(-1);
}
4 changes: 3 additions & 1 deletion tools/objtool/arch/x86/special.c
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,8 @@ 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)
struct instruction *insn,
unsigned long *table_size)
{
struct reloc *text_reloc, *rodata_reloc;
struct section *table_sec;
Expand Down Expand Up @@ -158,5 +159,6 @@ struct reloc *arch_find_switch_table(struct objtool_file *file,
if (reloc_type(text_reloc) == R_X86_64_PC32)
file->ignore_unreachables = true;

*table_size = 0;
return rodata_reloc;
}
31 changes: 20 additions & 11 deletions tools/objtool/check.c
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,15 @@ static inline struct reloc *insn_jump_table(struct instruction *insn)
return NULL;
}

static inline unsigned long insn_jump_table_size(struct instruction *insn)
{
if (insn->type == INSN_JUMP_DYNAMIC ||
insn->type == INSN_CALL_DYNAMIC)
return insn->_jump_table_size;

return 0;
}

static bool is_jump_table_jump(struct instruction *insn)
{
struct alt_group *alt_group = insn->alt_group;
Expand Down Expand Up @@ -1937,6 +1946,7 @@ static int add_special_section_alts(struct objtool_file *file)
static 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;
struct reloc *table = insn_jump_table(insn);
struct instruction *dest_insn;
Expand All @@ -1951,6 +1961,8 @@ static int add_jump_table(struct objtool_file *file, struct instruction *insn,
for_each_reloc_from(table->sec, reloc) {

/* Check for the end of the table: */
if (table_size && reloc_offset(reloc) - reloc_offset(table) >= table_size)
break;
if (reloc != table && reloc == next_table)
break;

Expand Down Expand Up @@ -1995,12 +2007,12 @@ static int add_jump_table(struct objtool_file *file, struct instruction *insn,
* find_jump_table() - Given a dynamic jump, find the switch jump table
* associated with it.
*/
static struct reloc *find_jump_table(struct objtool_file *file,
struct symbol *func,
struct instruction *insn)
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
Expand All @@ -2021,17 +2033,17 @@ static struct reloc *find_jump_table(struct objtool_file *file,
insn->jump_dest->offset > orig_insn->offset))
break;

table_reloc = arch_find_switch_table(file, insn);
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;

return table_reloc;
orig_insn->_jump_table = table_reloc;
orig_insn->_jump_table_size = table_size;
break;
}

return NULL;
}

/*
Expand All @@ -2042,7 +2054,6 @@ static void mark_func_jump_tables(struct objtool_file *file,
struct symbol *func)
{
struct instruction *insn, *last = NULL;
struct reloc *reloc;

func_for_each_insn(file, func, insn) {
if (!last)
Expand All @@ -2065,9 +2076,7 @@ static void mark_func_jump_tables(struct objtool_file *file,
if (insn->type != INSN_JUMP_DYNAMIC)
continue;

reloc = find_jump_table(file, func, insn);
if (reloc)
insn->_jump_table = reloc;
find_jump_table(file, func, insn);
}
}

Expand Down
5 changes: 4 additions & 1 deletion tools/objtool/include/objtool/check.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,10 @@ struct instruction {
struct instruction *first_jump_src;
union {
struct symbol *_call_dest;
struct reloc *_jump_table;
struct {
struct reloc *_jump_table;
unsigned long _jump_table_size;
};
};
struct alternative *alts;
struct symbol *sym;
Expand Down
3 changes: 2 additions & 1 deletion tools/objtool/include/objtool/special.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,5 +38,6 @@ 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);
struct instruction *insn,
unsigned long *table_size);
#endif /* _SPECIAL_H */

0 comments on commit c3cb6c1

Please sign in to comment.