mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-11 07:39:47 +00:00
objtool: Keep track of retpoline call sites
Provide infrastructure for architectures to rewrite/augment compiler generated retpoline calls. Similar to what we do for static_call()s, keep track of the instructions that are retpoline calls. Use the same list_head, since a retpoline call cannot also be a static_call. Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Signed-off-by: Borislav Petkov <bp@suse.de> Signed-off-by: Ingo Molnar <mingo@kernel.org> Reviewed-by: Miroslav Benes <mbenes@suse.cz> Link: https://lkml.kernel.org/r/20210326151300.130805730@infradead.org
This commit is contained in:
parent
2f2f7e47f0
commit
43d5430ad7
@ -451,7 +451,7 @@ static int create_static_call_sections(struct objtool_file *file)
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
idx = 0;
|
idx = 0;
|
||||||
list_for_each_entry(insn, &file->static_call_list, static_call_node)
|
list_for_each_entry(insn, &file->static_call_list, call_node)
|
||||||
idx++;
|
idx++;
|
||||||
|
|
||||||
sec = elf_create_section(file->elf, ".static_call_sites", SHF_WRITE,
|
sec = elf_create_section(file->elf, ".static_call_sites", SHF_WRITE,
|
||||||
@ -460,7 +460,7 @@ static int create_static_call_sections(struct objtool_file *file)
|
|||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
idx = 0;
|
idx = 0;
|
||||||
list_for_each_entry(insn, &file->static_call_list, static_call_node) {
|
list_for_each_entry(insn, &file->static_call_list, call_node) {
|
||||||
|
|
||||||
site = (struct static_call_site *)sec->data->d_buf + idx;
|
site = (struct static_call_site *)sec->data->d_buf + idx;
|
||||||
memset(site, 0, sizeof(struct static_call_site));
|
memset(site, 0, sizeof(struct static_call_site));
|
||||||
@ -829,13 +829,16 @@ static int add_jump_destinations(struct objtool_file *file)
|
|||||||
else
|
else
|
||||||
insn->type = INSN_JUMP_DYNAMIC_CONDITIONAL;
|
insn->type = INSN_JUMP_DYNAMIC_CONDITIONAL;
|
||||||
|
|
||||||
|
list_add_tail(&insn->call_node,
|
||||||
|
&file->retpoline_call_list);
|
||||||
|
|
||||||
insn->retpoline_safe = true;
|
insn->retpoline_safe = true;
|
||||||
continue;
|
continue;
|
||||||
} else if (insn->func) {
|
} else if (insn->func) {
|
||||||
/* internal or external sibling call (with reloc) */
|
/* internal or external sibling call (with reloc) */
|
||||||
insn->call_dest = reloc->sym;
|
insn->call_dest = reloc->sym;
|
||||||
if (insn->call_dest->static_call_tramp) {
|
if (insn->call_dest->static_call_tramp) {
|
||||||
list_add_tail(&insn->static_call_node,
|
list_add_tail(&insn->call_node,
|
||||||
&file->static_call_list);
|
&file->static_call_list);
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
@ -897,7 +900,7 @@ static int add_jump_destinations(struct objtool_file *file)
|
|||||||
/* internal sibling call (without reloc) */
|
/* internal sibling call (without reloc) */
|
||||||
insn->call_dest = insn->jump_dest->func;
|
insn->call_dest = insn->jump_dest->func;
|
||||||
if (insn->call_dest->static_call_tramp) {
|
if (insn->call_dest->static_call_tramp) {
|
||||||
list_add_tail(&insn->static_call_node,
|
list_add_tail(&insn->call_node,
|
||||||
&file->static_call_list);
|
&file->static_call_list);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -981,6 +984,9 @@ static int add_call_destinations(struct objtool_file *file)
|
|||||||
insn->type = INSN_CALL_DYNAMIC;
|
insn->type = INSN_CALL_DYNAMIC;
|
||||||
insn->retpoline_safe = true;
|
insn->retpoline_safe = true;
|
||||||
|
|
||||||
|
list_add_tail(&insn->call_node,
|
||||||
|
&file->retpoline_call_list);
|
||||||
|
|
||||||
remove_insn_ops(insn);
|
remove_insn_ops(insn);
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -988,7 +994,7 @@ static int add_call_destinations(struct objtool_file *file)
|
|||||||
insn->call_dest = reloc->sym;
|
insn->call_dest = reloc->sym;
|
||||||
|
|
||||||
if (insn->call_dest && insn->call_dest->static_call_tramp) {
|
if (insn->call_dest && insn->call_dest->static_call_tramp) {
|
||||||
list_add_tail(&insn->static_call_node,
|
list_add_tail(&insn->call_node,
|
||||||
&file->static_call_list);
|
&file->static_call_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1714,6 +1720,11 @@ static void mark_rodata(struct objtool_file *file)
|
|||||||
file->rodata = found;
|
file->rodata = found;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
__weak int arch_rewrite_retpolines(struct objtool_file *file)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int decode_sections(struct objtool_file *file)
|
static int decode_sections(struct objtool_file *file)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
@ -1742,6 +1753,10 @@ static int decode_sections(struct objtool_file *file)
|
|||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Must be before add_special_section_alts() as that depends on
|
||||||
|
* jump_dest being set.
|
||||||
|
*/
|
||||||
ret = add_jump_destinations(file);
|
ret = add_jump_destinations(file);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
@ -1778,6 +1793,15 @@ static int decode_sections(struct objtool_file *file)
|
|||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Must be after add_special_section_alts(), since this will emit
|
||||||
|
* alternatives. Must be after add_{jump,call}_destination(), since
|
||||||
|
* those create the call insn lists.
|
||||||
|
*/
|
||||||
|
ret = arch_rewrite_retpolines(file);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,4 +88,6 @@ int arch_decode_hint_reg(struct instruction *insn, u8 sp_reg);
|
|||||||
|
|
||||||
bool arch_is_retpoline(struct symbol *sym);
|
bool arch_is_retpoline(struct symbol *sym);
|
||||||
|
|
||||||
|
int arch_rewrite_retpolines(struct objtool_file *file);
|
||||||
|
|
||||||
#endif /* _ARCH_H */
|
#endif /* _ARCH_H */
|
||||||
|
@ -39,7 +39,7 @@ struct alt_group {
|
|||||||
struct instruction {
|
struct instruction {
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
struct hlist_node hash;
|
struct hlist_node hash;
|
||||||
struct list_head static_call_node;
|
struct list_head call_node;
|
||||||
struct list_head mcount_loc_node;
|
struct list_head mcount_loc_node;
|
||||||
struct section *sec;
|
struct section *sec;
|
||||||
unsigned long offset;
|
unsigned long offset;
|
||||||
|
@ -18,6 +18,7 @@ struct objtool_file {
|
|||||||
struct elf *elf;
|
struct elf *elf;
|
||||||
struct list_head insn_list;
|
struct list_head insn_list;
|
||||||
DECLARE_HASHTABLE(insn_hash, 20);
|
DECLARE_HASHTABLE(insn_hash, 20);
|
||||||
|
struct list_head retpoline_call_list;
|
||||||
struct list_head static_call_list;
|
struct list_head static_call_list;
|
||||||
struct list_head mcount_loc_list;
|
struct list_head mcount_loc_list;
|
||||||
bool ignore_unreachables, c_file, hints, rodata;
|
bool ignore_unreachables, c_file, hints, rodata;
|
||||||
|
@ -61,6 +61,7 @@ struct objtool_file *objtool_open_read(const char *_objname)
|
|||||||
|
|
||||||
INIT_LIST_HEAD(&file.insn_list);
|
INIT_LIST_HEAD(&file.insn_list);
|
||||||
hash_init(file.insn_hash);
|
hash_init(file.insn_hash);
|
||||||
|
INIT_LIST_HEAD(&file.retpoline_call_list);
|
||||||
INIT_LIST_HEAD(&file.static_call_list);
|
INIT_LIST_HEAD(&file.static_call_list);
|
||||||
INIT_LIST_HEAD(&file.mcount_loc_list);
|
INIT_LIST_HEAD(&file.mcount_loc_list);
|
||||||
file.c_file = !vmlinux && find_section_by_name(file.elf, ".comment");
|
file.c_file = !vmlinux && find_section_by_name(file.elf, ".comment");
|
||||||
|
Loading…
x
Reference in New Issue
Block a user