objtool: Add support for alternatives at the end of a section

commit 17bc33914b

Now that the previous patch gave objtool the ability to read retpoline
alternatives, it shows a new warning:

  arch/x86/entry/entry_64.o: warning: objtool: .entry_trampoline: don't know how to handle alternatives at end of section

This is due to the JMP_NOSPEC in entry_SYSCALL_64_trampoline().

Previously, objtool ignored this situation because it wasn't needed, and
it would have required a bit of extra code.  Now that this case exists,
add proper support for it.

Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Dave Hansen <dave.hansen@linux.intel.com>
Cc: David Woodhouse <dwmw2@infradead.org>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Guenter Roeck <linux@roeck-us.net>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Juergen Gross <jgross@suse.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lkml.kernel.org/r/2a30a3c2158af47d891a76e69bb1ef347e0443fd.1517284349.git.jpoimboe@redhat.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Josh Poimboeuf 2018-01-29 22:00:40 -06:00 committed by Greg Kroah-Hartman
parent a358df0327
commit 3e04e09855
1 changed files with 30 additions and 21 deletions

View File

@ -594,7 +594,7 @@ static int handle_group_alt(struct objtool_file *file,
struct instruction *orig_insn, struct instruction *orig_insn,
struct instruction **new_insn) struct instruction **new_insn)
{ {
struct instruction *last_orig_insn, *last_new_insn, *insn, *fake_jump; struct instruction *last_orig_insn, *last_new_insn, *insn, *fake_jump = NULL;
unsigned long dest_off; unsigned long dest_off;
last_orig_insn = NULL; last_orig_insn = NULL;
@ -610,12 +610,7 @@ static int handle_group_alt(struct objtool_file *file,
last_orig_insn = insn; last_orig_insn = insn;
} }
if (!next_insn_same_sec(file, last_orig_insn)) { if (next_insn_same_sec(file, last_orig_insn)) {
WARN("%s: don't know how to handle alternatives at end of section",
special_alt->orig_sec->name);
return -1;
}
fake_jump = malloc(sizeof(*fake_jump)); fake_jump = malloc(sizeof(*fake_jump));
if (!fake_jump) { if (!fake_jump) {
WARN("malloc failed"); WARN("malloc failed");
@ -630,8 +625,15 @@ static int handle_group_alt(struct objtool_file *file,
fake_jump->type = INSN_JUMP_UNCONDITIONAL; fake_jump->type = INSN_JUMP_UNCONDITIONAL;
fake_jump->jump_dest = list_next_entry(last_orig_insn, list); fake_jump->jump_dest = list_next_entry(last_orig_insn, list);
fake_jump->ignore = true; fake_jump->ignore = true;
}
if (!special_alt->new_len) { if (!special_alt->new_len) {
if (!fake_jump) {
WARN("%s: empty alternative at end of section",
special_alt->orig_sec->name);
return -1;
}
*new_insn = fake_jump; *new_insn = fake_jump;
return 0; return 0;
} }
@ -654,8 +656,14 @@ static int handle_group_alt(struct objtool_file *file,
continue; continue;
dest_off = insn->offset + insn->len + insn->immediate; dest_off = insn->offset + insn->len + insn->immediate;
if (dest_off == special_alt->new_off + special_alt->new_len) if (dest_off == special_alt->new_off + special_alt->new_len) {
if (!fake_jump) {
WARN("%s: alternative jump to end of section",
special_alt->orig_sec->name);
return -1;
}
insn->jump_dest = fake_jump; insn->jump_dest = fake_jump;
}
if (!insn->jump_dest) { if (!insn->jump_dest) {
WARN_FUNC("can't find alternative jump destination", WARN_FUNC("can't find alternative jump destination",
@ -670,6 +678,7 @@ static int handle_group_alt(struct objtool_file *file,
return -1; return -1;
} }
if (fake_jump)
list_add(&fake_jump->list, &last_new_insn->list); list_add(&fake_jump->list, &last_new_insn->list);
return 0; return 0;