Commit 0d0970ee authored by Josh Poimboeuf's avatar Josh Poimboeuf Committed by Ingo Molnar

objtool: Handle another GCC stack pointer adjustment bug

The kbuild bot reported the following warning with GCC 4.4 and a
randconfig:

  net/socket.o: warning: objtool: compat_sock_ioctl()+0x1083: stack state mismatch: cfa1=7+160 cfa2=-1+0

This is caused by another GCC non-optimization, where it backs up and
restores the stack pointer for no apparent reason:

    2f91:       48 89 e0                mov    %rsp,%rax
    2f94:       4c 89 e7                mov    %r12,%rdi
    2f97:       4c 89 f6                mov    %r14,%rsi
    2f9a:       ba 20 00 00 00          mov    $0x20,%edx
    2f9f:       48 89 c4                mov    %rax,%rsp

This issue would have been happily ignored before the following commit:

  dd88a0a0 ("objtool: Handle GCC stack pointer adjustment bug")

But now that objtool is paying attention to such stack pointer writes
to/from a register, it needs to understand them properly.  In this case
that means recognizing that the "mov %rsp, %rax" instruction is
potentially a backup of the stack pointer.
Reported-by: default avatarkbuild test robot <fengguang.wu@intel.com>
Signed-off-by: default avatarJosh Poimboeuf <jpoimboe@redhat.com>
Cc: Alexander Potapenko <glider@google.com>
Cc: Andrey Ryabinin <aryabinin@virtuozzo.com>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Dmitriy Vyukov <dvyukov@google.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Matthias Kaehlcke <mka@chromium.org>
Cc: Miguel Bernal Marin <miguel.bernal.marin@linux.intel.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Fixes: dd88a0a0 ("objtool: Handle GCC stack pointer adjustment bug")
Link: http://lkml.kernel.org/r/8c7aa8e9a36fbbb6655d9d8e7cea58958c912da8.1505942196.git.jpoimboe@redhat.comSigned-off-by: default avatarIngo Molnar <mingo@kernel.org>
parent 4ba55e65
...@@ -208,14 +208,14 @@ int arch_decode_instruction(struct elf *elf, struct section *sec, ...@@ -208,14 +208,14 @@ int arch_decode_instruction(struct elf *elf, struct section *sec,
break; break;
case 0x89: case 0x89:
if (rex == 0x48 && modrm == 0xe5) { if (rex_w && !rex_r && modrm_mod == 3 && modrm_reg == 4) {
/* mov %rsp, %rbp */ /* mov %rsp, reg */
*type = INSN_STACK; *type = INSN_STACK;
op->src.type = OP_SRC_REG; op->src.type = OP_SRC_REG;
op->src.reg = CFI_SP; op->src.reg = CFI_SP;
op->dest.type = OP_DEST_REG; op->dest.type = OP_DEST_REG;
op->dest.reg = CFI_BP; op->dest.reg = op_to_cfi_reg[modrm_rm][rex_b];
break; break;
} }
......
...@@ -1203,9 +1203,8 @@ static int update_insn_state(struct instruction *insn, struct insn_state *state) ...@@ -1203,9 +1203,8 @@ static int update_insn_state(struct instruction *insn, struct insn_state *state)
switch (op->src.type) { switch (op->src.type) {
case OP_SRC_REG: case OP_SRC_REG:
if (op->src.reg == CFI_SP && op->dest.reg == CFI_BP) { if (op->src.reg == CFI_SP && op->dest.reg == CFI_BP &&
cfa->base == CFI_SP &&
if (cfa->base == CFI_SP &&
regs[CFI_BP].base == CFI_CFA && regs[CFI_BP].base == CFI_CFA &&
regs[CFI_BP].offset == -cfa->offset) { regs[CFI_BP].offset == -cfa->offset) {
...@@ -1214,13 +1213,29 @@ static int update_insn_state(struct instruction *insn, struct insn_state *state) ...@@ -1214,13 +1213,29 @@ static int update_insn_state(struct instruction *insn, struct insn_state *state)
state->bp_scratch = false; state->bp_scratch = false;
} }
else if (state->drap) { else if (op->src.reg == CFI_SP &&
op->dest.reg == CFI_BP && state->drap) {
/* drap: mov %rsp, %rbp */ /* drap: mov %rsp, %rbp */
regs[CFI_BP].base = CFI_BP; regs[CFI_BP].base = CFI_BP;
regs[CFI_BP].offset = -state->stack_size; regs[CFI_BP].offset = -state->stack_size;
state->bp_scratch = false; state->bp_scratch = false;
} }
else if (op->src.reg == CFI_SP && cfa->base == CFI_SP) {
/*
* mov %rsp, %reg
*
* This is needed for the rare case where GCC
* does:
*
* mov %rsp, %rax
* ...
* mov %rax, %rsp
*/
state->vals[op->dest.reg].base = CFI_CFA;
state->vals[op->dest.reg].offset = -state->stack_size;
} }
else if (op->dest.reg == cfa->base) { else if (op->dest.reg == cfa->base) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment