diff options
author | Josh Poimboeuf <jpoimboe@redhat.com> | 2017-09-20 17:24:32 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2017-09-23 09:06:19 -0400 |
commit | 0d0970eef3b03ef08b19da5bc3044410731cf38f (patch) | |
tree | 3cbc6c409fce79dddb54b110a557a78dc8720086 | |
parent | 4ba55e65f471d011d3ba2ac2022180ea0877d68e (diff) |
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>
-rw-r--r-- | tools/objtool/arch/x86/decode.c | 6 | ||||
-rw-r--r-- | tools/objtool/check.c | 43 |
2 files changed, 32 insertions, 17 deletions
diff --git a/tools/objtool/arch/x86/decode.c b/tools/objtool/arch/x86/decode.c index 0e8c8ec4fd4e..0f22768c0d4d 100644 --- a/tools/objtool/arch/x86/decode.c +++ b/tools/objtool/arch/x86/decode.c | |||
@@ -208,14 +208,14 @@ int arch_decode_instruction(struct elf *elf, struct section *sec, | |||
208 | break; | 208 | break; |
209 | 209 | ||
210 | case 0x89: | 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 | *type = INSN_STACK; | 214 | *type = INSN_STACK; |
215 | op->src.type = OP_SRC_REG; | 215 | op->src.type = OP_SRC_REG; |
216 | op->src.reg = CFI_SP; | 216 | op->src.reg = CFI_SP; |
217 | op->dest.type = OP_DEST_REG; | 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 | break; | 219 | break; |
220 | } | 220 | } |
221 | 221 | ||
diff --git a/tools/objtool/check.c b/tools/objtool/check.c index f744617c9946..a0c518ecf085 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c | |||
@@ -1203,24 +1203,39 @@ static int update_insn_state(struct instruction *insn, struct insn_state *state) | |||
1203 | switch (op->src.type) { | 1203 | switch (op->src.type) { |
1204 | 1204 | ||
1205 | case OP_SRC_REG: | 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) { | ||
1210 | |||
1211 | /* mov %rsp, %rbp */ | ||
1212 | cfa->base = op->dest.reg; | ||
1213 | state->bp_scratch = false; | ||
1214 | } | ||
1207 | 1215 | ||
1208 | if (cfa->base == CFI_SP && | 1216 | else if (op->src.reg == CFI_SP && |
1209 | regs[CFI_BP].base == CFI_CFA && | 1217 | op->dest.reg == CFI_BP && state->drap) { |
1210 | regs[CFI_BP].offset == -cfa->offset) { | ||
1211 | 1218 | ||
1212 | /* mov %rsp, %rbp */ | 1219 | /* drap: mov %rsp, %rbp */ |
1213 | cfa->base = op->dest.reg; | 1220 | regs[CFI_BP].base = CFI_BP; |
1214 | state->bp_scratch = false; | 1221 | regs[CFI_BP].offset = -state->stack_size; |
1215 | } | 1222 | state->bp_scratch = false; |
1223 | } | ||
1216 | 1224 | ||
1217 | else if (state->drap) { | 1225 | else if (op->src.reg == CFI_SP && cfa->base == CFI_SP) { |
1218 | 1226 | ||
1219 | /* drap: mov %rsp, %rbp */ | 1227 | /* |
1220 | regs[CFI_BP].base = CFI_BP; | 1228 | * mov %rsp, %reg |
1221 | regs[CFI_BP].offset = -state->stack_size; | 1229 | * |
1222 | state->bp_scratch = false; | 1230 | * This is needed for the rare case where GCC |
1223 | } | 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 | else if (op->dest.reg == cfa->base) { | 1241 | else if (op->dest.reg == cfa->base) { |