Commit 43d5430a authored by Peter Zijlstra's avatar Peter Zijlstra Committed by Ingo Molnar
Browse files

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: default avatarPeter Zijlstra (Intel) <peterz@infradead.org>
Signed-off-by: default avatarBorislav Petkov <bp@suse.de>
Signed-off-by: default avatarIngo Molnar <mingo@kernel.org>
Reviewed-by: default avatarMiroslav Benes <mbenes@suse.cz>
Link: https://lkml.kernel.org/r/20210326151300.130805730@infradead.org
parent 2f2f7e47
Loading
Loading
Loading
Loading
+29 −5
Original line number Diff line number Diff line
@@ -451,7 +451,7 @@ static int create_static_call_sections(struct objtool_file *file)
		return 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++;

	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;

	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;
		memset(site, 0, sizeof(struct static_call_site));
@@ -829,13 +829,16 @@ static int add_jump_destinations(struct objtool_file *file)
			else
				insn->type = INSN_JUMP_DYNAMIC_CONDITIONAL;

			list_add_tail(&insn->call_node,
				      &file->retpoline_call_list);

			insn->retpoline_safe = true;
			continue;
		} else if (insn->func) {
			/* internal or external sibling call (with reloc) */
			insn->call_dest = reloc->sym;
			if (insn->call_dest->static_call_tramp) {
				list_add_tail(&insn->static_call_node,
				list_add_tail(&insn->call_node,
					      &file->static_call_list);
			}
			continue;
@@ -897,7 +900,7 @@ static int add_jump_destinations(struct objtool_file *file)
				/* internal sibling call (without reloc) */
				insn->call_dest = insn->jump_dest->func;
				if (insn->call_dest->static_call_tramp) {
					list_add_tail(&insn->static_call_node,
					list_add_tail(&insn->call_node,
						      &file->static_call_list);
				}
			}
@@ -981,6 +984,9 @@ static int add_call_destinations(struct objtool_file *file)
			insn->type = INSN_CALL_DYNAMIC;
			insn->retpoline_safe = true;

			list_add_tail(&insn->call_node,
				      &file->retpoline_call_list);

			remove_insn_ops(insn);
			continue;

@@ -988,7 +994,7 @@ static int add_call_destinations(struct objtool_file *file)
			insn->call_dest = reloc->sym;

		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);
		}

@@ -1714,6 +1720,11 @@ static void mark_rodata(struct objtool_file *file)
	file->rodata = found;
}

__weak int arch_rewrite_retpolines(struct objtool_file *file)
{
	return 0;
}

static int decode_sections(struct objtool_file *file)
{
	int ret;
@@ -1742,6 +1753,10 @@ static int decode_sections(struct objtool_file *file)
	if (ret)
		return ret;

	/*
	 * Must be before add_special_section_alts() as that depends on
	 * jump_dest being set.
	 */
	ret = add_jump_destinations(file);
	if (ret)
		return ret;
@@ -1778,6 +1793,15 @@ static int decode_sections(struct objtool_file *file)
	if (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;
}

+2 −0
Original line number Diff line number Diff line
@@ -88,4 +88,6 @@ int arch_decode_hint_reg(struct instruction *insn, u8 sp_reg);

bool arch_is_retpoline(struct symbol *sym);

int arch_rewrite_retpolines(struct objtool_file *file);

#endif /* _ARCH_H */
+1 −1
Original line number Diff line number Diff line
@@ -39,7 +39,7 @@ struct alt_group {
struct instruction {
	struct list_head list;
	struct hlist_node hash;
	struct list_head static_call_node;
	struct list_head call_node;
	struct list_head mcount_loc_node;
	struct section *sec;
	unsigned long offset;
+1 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ struct objtool_file {
	struct elf *elf;
	struct list_head insn_list;
	DECLARE_HASHTABLE(insn_hash, 20);
	struct list_head retpoline_call_list;
	struct list_head static_call_list;
	struct list_head mcount_loc_list;
	bool ignore_unreachables, c_file, hints, rodata;
+1 −0
Original line number Diff line number Diff line
@@ -61,6 +61,7 @@ struct objtool_file *objtool_open_read(const char *_objname)

	INIT_LIST_HEAD(&file.insn_list);
	hash_init(file.insn_hash);
	INIT_LIST_HEAD(&file.retpoline_call_list);
	INIT_LIST_HEAD(&file.static_call_list);
	INIT_LIST_HEAD(&file.mcount_loc_list);
	file.c_file = !vmlinux && find_section_by_name(file.elf, ".comment");