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:

dd88a0a0c861 ("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: kbuild test robot <fengguang.wu@intel.com>
Signed-off-by: Josh 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: dd88a0a0c861 ("objtool: Handle GCC stack pointer adjustment bug")
Link: http://lkml.kernel.org/r/8c7aa8e9a36fbbb6655d9d8e7cea58958c912da8.1505942196.git.jpoimboe@redhat.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>

authored by Josh Poimboeuf and committed by Ingo Molnar 0d0970ee 4ba55e65

Changed files
+32 -17
tools
objtool
arch
x86
+3 -3
tools/objtool/arch/x86/decode.c
··· 208 208 break; 209 209 210 210 case 0x89: 211 - if (rex == 0x48 && modrm == 0xe5) { 211 + if (rex_w && !rex_r && modrm_mod == 3 && modrm_reg == 4) { 212 212 213 - /* mov %rsp, %rbp */ 213 + /* mov %rsp, reg */ 214 214 *type = INSN_STACK; 215 215 op->src.type = OP_SRC_REG; 216 216 op->src.reg = CFI_SP; 217 217 op->dest.type = OP_DEST_REG; 218 - op->dest.reg = CFI_BP; 218 + op->dest.reg = op_to_cfi_reg[modrm_rm][rex_b]; 219 219 break; 220 220 } 221 221
+29 -14
tools/objtool/check.c
··· 1203 1203 switch (op->src.type) { 1204 1204 1205 1205 case OP_SRC_REG: 1206 - if (op->src.reg == CFI_SP && op->dest.reg == CFI_BP) { 1206 + if (op->src.reg == CFI_SP && op->dest.reg == CFI_BP && 1207 + cfa->base == CFI_SP && 1208 + regs[CFI_BP].base == CFI_CFA && 1209 + regs[CFI_BP].offset == -cfa->offset) { 1207 1210 1208 - if (cfa->base == CFI_SP && 1209 - regs[CFI_BP].base == CFI_CFA && 1210 - regs[CFI_BP].offset == -cfa->offset) { 1211 + /* mov %rsp, %rbp */ 1212 + cfa->base = op->dest.reg; 1213 + state->bp_scratch = false; 1214 + } 1211 1215 1212 - /* mov %rsp, %rbp */ 1213 - cfa->base = op->dest.reg; 1214 - state->bp_scratch = false; 1215 - } 1216 + else if (op->src.reg == CFI_SP && 1217 + op->dest.reg == CFI_BP && state->drap) { 1216 1218 1217 - else if (state->drap) { 1219 + /* drap: mov %rsp, %rbp */ 1220 + regs[CFI_BP].base = CFI_BP; 1221 + regs[CFI_BP].offset = -state->stack_size; 1222 + state->bp_scratch = false; 1223 + } 1218 1224 1219 - /* drap: mov %rsp, %rbp */ 1220 - regs[CFI_BP].base = CFI_BP; 1221 - regs[CFI_BP].offset = -state->stack_size; 1222 - state->bp_scratch = false; 1223 - } 1225 + else if (op->src.reg == CFI_SP && cfa->base == CFI_SP) { 1226 + 1227 + /* 1228 + * mov %rsp, %reg 1229 + * 1230 + * This is needed for the rare case where GCC 1231 + * does: 1232 + * 1233 + * mov %rsp, %rax 1234 + * ... 1235 + * mov %rax, %rsp 1236 + */ 1237 + state->vals[op->dest.reg].base = CFI_CFA; 1238 + state->vals[op->dest.reg].offset = -state->stack_size; 1224 1239 } 1225 1240 1226 1241 else if (op->dest.reg == cfa->base) {