diff options
Diffstat (limited to 'tools/objtool/check.c')
-rw-r--r-- | tools/objtool/check.c | 43 |
1 files changed, 43 insertions, 0 deletions
diff --git a/tools/objtool/check.c b/tools/objtool/check.c index ae1d4f996803..0e0e5b5a72c8 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -3346,6 +3346,49 @@ static bool ignore_unreachable_insn(struct objtool_file *file, struct instructio !strcmp(insn->sec->name, ".altinstr_aux")) return true; + /* + * Whole archive runs might encounder dead code from weak symbols. + * This is where the linker will have dropped the weak symbol in + * favour of a regular symbol, but leaves the code in place. + * + * In this case we'll find a piece of code (whole function) that is not + * covered by a !section symbol. Ignore them. + */ + if (!insn->func && lto) { + int size = find_symbol_hole_containing(insn->sec, insn->offset); + unsigned long end = insn->offset + size; + + if (!size) /* not a hole */ + return false; + + if (size < 0) /* hole until the end */ + return true; + + sec_for_each_insn_continue(file, insn) { + /* + * If we reach a visited instruction at or before the + * end of the hole, ignore the unreachable. + */ + if (insn->visited) + return true; + + if (insn->offset >= end) + break; + + /* + * If this hole jumps to a .cold function, mark it ignore too. + */ + if (insn->jump_dest && insn->jump_dest->func && + strstr(insn->jump_dest->func->name, ".cold")) { + struct instruction *dest = insn->jump_dest; + func_for_each_insn(file, dest->func, dest) + dest->ignore = true; + } + } + + return false; + } + if (!insn->func) return false; |