forked from Minki/linux
objtool: Don't set 'jump_dest' for sibling calls
For most sibling calls, 'jump_dest' is NULL because objtool treats the jump like a call and sets 'call_dest'. But there are a few edge cases where that's not true. Make it consistent to avoid unexpected behavior. Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Link: https://lkml.kernel.org/r/8737d6b9d1691831aed73375f444f0f42da3e2c9.1649718562.git.jpoimboe@redhat.com
This commit is contained in:
parent
02041b3225
commit
26ff604102
@ -1271,7 +1271,7 @@ static bool is_first_func_insn(struct objtool_file *file, struct instruction *in
|
|||||||
*/
|
*/
|
||||||
static int add_jump_destinations(struct objtool_file *file)
|
static int add_jump_destinations(struct objtool_file *file)
|
||||||
{
|
{
|
||||||
struct instruction *insn;
|
struct instruction *insn, *jump_dest;
|
||||||
struct reloc *reloc;
|
struct reloc *reloc;
|
||||||
struct section *dest_sec;
|
struct section *dest_sec;
|
||||||
unsigned long dest_off;
|
unsigned long dest_off;
|
||||||
@ -1291,7 +1291,10 @@ static int add_jump_destinations(struct objtool_file *file)
|
|||||||
add_retpoline_call(file, insn);
|
add_retpoline_call(file, insn);
|
||||||
continue;
|
continue;
|
||||||
} else if (insn->func) {
|
} else if (insn->func) {
|
||||||
/* internal or external sibling call (with reloc) */
|
/*
|
||||||
|
* External sibling call or internal sibling call with
|
||||||
|
* STT_FUNC reloc.
|
||||||
|
*/
|
||||||
add_call_dest(file, insn, reloc->sym, true);
|
add_call_dest(file, insn, reloc->sym, true);
|
||||||
continue;
|
continue;
|
||||||
} else if (reloc->sym->sec->idx) {
|
} else if (reloc->sym->sec->idx) {
|
||||||
@ -1303,8 +1306,8 @@ static int add_jump_destinations(struct objtool_file *file)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
insn->jump_dest = find_insn(file, dest_sec, dest_off);
|
jump_dest = find_insn(file, dest_sec, dest_off);
|
||||||
if (!insn->jump_dest) {
|
if (!jump_dest) {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is a special case where an alt instruction
|
* This is a special case where an alt instruction
|
||||||
@ -1323,8 +1326,8 @@ static int add_jump_destinations(struct objtool_file *file)
|
|||||||
/*
|
/*
|
||||||
* Cross-function jump.
|
* Cross-function jump.
|
||||||
*/
|
*/
|
||||||
if (insn->func && insn->jump_dest->func &&
|
if (insn->func && jump_dest->func &&
|
||||||
insn->func != insn->jump_dest->func) {
|
insn->func != jump_dest->func) {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For GCC 8+, create parent/child links for any cold
|
* For GCC 8+, create parent/child links for any cold
|
||||||
@ -1342,16 +1345,22 @@ static int add_jump_destinations(struct objtool_file *file)
|
|||||||
* subfunction is through a jump table.
|
* subfunction is through a jump table.
|
||||||
*/
|
*/
|
||||||
if (!strstr(insn->func->name, ".cold") &&
|
if (!strstr(insn->func->name, ".cold") &&
|
||||||
strstr(insn->jump_dest->func->name, ".cold")) {
|
strstr(jump_dest->func->name, ".cold")) {
|
||||||
insn->func->cfunc = insn->jump_dest->func;
|
insn->func->cfunc = jump_dest->func;
|
||||||
insn->jump_dest->func->pfunc = insn->func;
|
jump_dest->func->pfunc = insn->func;
|
||||||
|
|
||||||
} else if (!same_function(insn, insn->jump_dest) &&
|
} else if (!same_function(insn, jump_dest) &&
|
||||||
is_first_func_insn(file, insn->jump_dest)) {
|
is_first_func_insn(file, jump_dest)) {
|
||||||
/* internal sibling call (without reloc) */
|
/*
|
||||||
add_call_dest(file, insn, insn->jump_dest->func, true);
|
* Internal sibling call without reloc or with
|
||||||
|
* STT_SECTION reloc.
|
||||||
|
*/
|
||||||
|
add_call_dest(file, insn, jump_dest->func, true);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
insn->jump_dest = jump_dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
Loading…
Reference in New Issue
Block a user