| From foo@baz Wed Aug 22 09:42:09 CEST 2018 |
| From: Josh Poimboeuf <jpoimboe@redhat.com> |
| Date: Wed, 27 Jun 2018 17:03:45 -0500 |
| Subject: objtool: Support GCC 8 '-fnoreorder-functions' |
| |
| From: Josh Poimboeuf <jpoimboe@redhat.com> |
| |
| [ Upstream commit 08b393d01c88aff27347ed2b1b354eb4db2f1532 ] |
| |
| Since the following commit: |
| |
| cd77849a69cf ("objtool: Fix GCC 8 cold subfunction detection for aliased functions") |
| |
| ... if the kernel is built with EXTRA_CFLAGS='-fno-reorder-functions', |
| objtool can get stuck in an infinite loop. |
| |
| That flag causes the new GCC 8 cold subfunctions to be placed in .text |
| instead of .text.unlikely. But it also has an unfortunate quirk: in the |
| symbol table, the subfunction (e.g., nmi_panic.cold.7) is nested inside |
| the parent (nmi_panic). |
| |
| That function overlap confuses objtool, and causes it to get into an |
| infinite loop in next_insn_same_func(). Here's Allan's description of |
| the loop: |
| |
| "Objtool iterates through the instructions in nmi_panic using |
| next_insn_same_func. Once it reaches the end of nmi_panic at 0x534 it |
| jumps to 0x528 as that's the start of nmi_panic.cold.7. However, since |
| the instructions starting at 0x528 are still associated with nmi_panic |
| objtool will get stuck in a loop, continually jumping back to 0x528 |
| after reaching 0x534." |
| |
| Fix it by shortening the length of the parent function so that the |
| functions no longer overlap. |
| |
| Reported-and-analyzed-by: Allan Xavier <allan.x.xavier@oracle.com> |
| Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com> |
| Cc: Allan Xavier <allan.x.xavier@oracle.com> |
| Cc: Andy Lutomirski <luto@kernel.org> |
| Cc: Borislav Petkov <bp@alien8.de> |
| Cc: Brian Gerst <brgerst@gmail.com> |
| Cc: Denys Vlasenko <dvlasenk@redhat.com> |
| Cc: H. Peter Anvin <hpa@zytor.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/9e704c52bee651129b036be14feda317ae5606ae.1530136978.git.jpoimboe@redhat.com |
| Signed-off-by: Ingo Molnar <mingo@kernel.org> |
| Signed-off-by: Sasha Levin <alexander.levin@microsoft.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| tools/objtool/elf.c | 37 ++++++++++++++++++++++++++----------- |
| 1 file changed, 26 insertions(+), 11 deletions(-) |
| |
| --- a/tools/objtool/elf.c |
| +++ b/tools/objtool/elf.c |
| @@ -302,19 +302,34 @@ static int read_symbols(struct elf *elf) |
| continue; |
| sym->pfunc = sym->cfunc = sym; |
| coldstr = strstr(sym->name, ".cold."); |
| - if (coldstr) { |
| - coldstr[0] = '\0'; |
| - pfunc = find_symbol_by_name(elf, sym->name); |
| - coldstr[0] = '.'; |
| + if (!coldstr) |
| + continue; |
| + |
| + coldstr[0] = '\0'; |
| + pfunc = find_symbol_by_name(elf, sym->name); |
| + coldstr[0] = '.'; |
| + |
| + if (!pfunc) { |
| + WARN("%s(): can't find parent function", |
| + sym->name); |
| + goto err; |
| + } |
| |
| - if (!pfunc) { |
| - WARN("%s(): can't find parent function", |
| - sym->name); |
| - goto err; |
| - } |
| + sym->pfunc = pfunc; |
| + pfunc->cfunc = sym; |
| |
| - sym->pfunc = pfunc; |
| - pfunc->cfunc = sym; |
| + /* |
| + * Unfortunately, -fnoreorder-functions puts the child |
| + * inside the parent. Remove the overlap so we can |
| + * have sane assumptions. |
| + * |
| + * Note that pfunc->len now no longer matches |
| + * pfunc->sym.st_size. |
| + */ |
| + if (sym->sec == pfunc->sec && |
| + sym->offset >= pfunc->offset && |
| + sym->offset + sym->len == pfunc->offset + pfunc->len) { |
| + pfunc->len -= sym->len; |
| } |
| } |
| } |