Commit 45245f51 authored by Julien Thierry's avatar Julien Thierry Committed by Josh Poimboeuf
Browse files

objtool: Make relocation in alternative handling arch dependent



As pointed out by the comment in handle_group_alt(), support of
relocation for instructions in an alternative group depends on whether
arch specific kernel code handles it.

So, let objtool arch specific code decide whether a relocation for
the alternative section should be accepted.

Reviewed-by: default avatarMiroslav Benes <mbenes@suse.cz>
Signed-off-by: default avatarJulien Thierry <jthierry@redhat.com>
Signed-off-by: default avatarJosh Poimboeuf <jpoimboe@redhat.com>
parent eda3dc90
Loading
Loading
Loading
Loading
+13 −0
Original line number Diff line number Diff line
@@ -35,3 +35,16 @@ void arch_handle_alternative(unsigned short feature, struct special_alt *alt)
		break;
	}
}

bool arch_support_alt_relocation(struct special_alt *special_alt,
				 struct instruction *insn,
				 struct reloc *reloc)
{
	/*
	 * The x86 alternatives code adjusts the offsets only when it
	 * encounters a branch instruction at the very beginning of the
	 * replacement group.
	 */
	return insn->offset == special_alt->new_off &&
	       (insn->type == INSN_CALL || is_static_jump(insn));
}
+6 −13
Original line number Diff line number Diff line
@@ -110,12 +110,6 @@ static struct instruction *prev_insn_same_sym(struct objtool_file *file,
	for (insn = next_insn_same_sec(file, insn); insn;		\
	     insn = next_insn_same_sec(file, insn))

static bool is_static_jump(struct instruction *insn)
{
	return insn->type == INSN_JUMP_CONDITIONAL ||
	       insn->type == INSN_JUMP_UNCONDITIONAL;
}

static bool is_sibling_call(struct instruction *insn)
{
	/* An indirect jump is either a sibling call or a jump to a table. */
@@ -972,6 +966,8 @@ static int handle_group_alt(struct objtool_file *file,
	alt_group = alt_group_next_index++;
	insn = *new_insn;
	sec_for_each_insn_from(file, insn) {
		struct reloc *alt_reloc;

		if (insn->offset >= special_alt->new_off + special_alt->new_len)
			break;

@@ -988,14 +984,11 @@ static int handle_group_alt(struct objtool_file *file,
		 * .altinstr_replacement section, unless the arch's
		 * alternatives code can adjust the relative offsets
		 * accordingly.
		 *
		 * The x86 alternatives code adjusts the offsets only when it
		 * encounters a branch instruction at the very beginning of the
		 * replacement group.
		 */
		if ((insn->offset != special_alt->new_off ||
		    (insn->type != INSN_CALL && !is_static_jump(insn))) &&
		    find_reloc_by_dest_range(file->elf, insn->sec, insn->offset, insn->len)) {
		alt_reloc = find_reloc_by_dest_range(file->elf, insn->sec,
						   insn->offset, insn->len);
		if (alt_reloc &&
		    !arch_support_alt_relocation(special_alt, insn, alt_reloc)) {

			WARN_FUNC("unsupported relocation in alternatives section",
				  insn->sec, insn->offset);
+6 −0
Original line number Diff line number Diff line
@@ -48,6 +48,12 @@ struct instruction {
#endif
};

static inline bool is_static_jump(struct instruction *insn)
{
	return insn->type == INSN_JUMP_CONDITIONAL ||
	       insn->type == INSN_JUMP_UNCONDITIONAL;
}

struct instruction *find_insn(struct objtool_file *file,
			      struct section *sec, unsigned long offset);

+4 −0
Original line number Diff line number Diff line
@@ -7,6 +7,7 @@
#define _SPECIAL_H

#include <stdbool.h>
#include "check.h"
#include "elf.h"

struct special_alt {
@@ -30,4 +31,7 @@ int special_get_alts(struct elf *elf, struct list_head *alts);

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);
#endif /* _SPECIAL_H */