mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-03-22 07:27:12 +08:00
objtool: Handle Clang RSP musical chairs
For no apparent reason (possibly related to CONFIG_KMSAN), Clang can randomly pass the value of RSP to other registers and then back again to RSP. Handle that accordingly. Fixes the following warnings: drivers/input/misc/uinput.o: warning: objtool: uinput_str_to_user+0x165: undefined stack state drivers/input/misc/uinput.o: warning: objtool: uinput_str_to_user+0x165: unknown CFA base reg -1 Reported-by: Arnd Bergmann <arnd@arndb.de> Closes: https://lore.kernel.org/90956545-2066-46e3-b547-10c884582eb0@app.fastmail.com Link: https://patch.msgid.link/240e6a172cc73292499334a3724d02ccb3247fc7.1772818491.git.jpoimboe@kernel.org Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
This commit is contained in:
@@ -395,52 +395,36 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec
|
||||
if (!rex_w)
|
||||
break;
|
||||
|
||||
if (modrm_reg == CFI_SP) {
|
||||
|
||||
if (mod_is_reg()) {
|
||||
/* mov %rsp, reg */
|
||||
ADD_OP(op) {
|
||||
op->src.type = OP_SRC_REG;
|
||||
op->src.reg = CFI_SP;
|
||||
op->dest.type = OP_DEST_REG;
|
||||
op->dest.reg = modrm_rm;
|
||||
}
|
||||
break;
|
||||
|
||||
} else {
|
||||
/* skip RIP relative displacement */
|
||||
if (is_RIP())
|
||||
break;
|
||||
|
||||
/* skip nontrivial SIB */
|
||||
if (have_SIB()) {
|
||||
modrm_rm = sib_base;
|
||||
if (sib_index != CFI_SP)
|
||||
break;
|
||||
}
|
||||
|
||||
/* mov %rsp, disp(%reg) */
|
||||
ADD_OP(op) {
|
||||
op->src.type = OP_SRC_REG;
|
||||
op->src.reg = CFI_SP;
|
||||
op->dest.type = OP_DEST_REG_INDIRECT;
|
||||
op->dest.reg = modrm_rm;
|
||||
op->dest.offset = ins.displacement.value;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (rm_is_reg(CFI_SP)) {
|
||||
|
||||
/* mov reg, %rsp */
|
||||
if (mod_is_reg()) {
|
||||
/* mov reg, reg */
|
||||
ADD_OP(op) {
|
||||
op->src.type = OP_SRC_REG;
|
||||
op->src.reg = modrm_reg;
|
||||
op->dest.type = OP_DEST_REG;
|
||||
op->dest.reg = CFI_SP;
|
||||
op->dest.reg = modrm_rm;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* skip RIP relative displacement */
|
||||
if (is_RIP())
|
||||
break;
|
||||
|
||||
/* skip nontrivial SIB */
|
||||
if (have_SIB()) {
|
||||
modrm_rm = sib_base;
|
||||
if (sib_index != CFI_SP)
|
||||
break;
|
||||
}
|
||||
|
||||
/* mov %rsp, disp(%reg) */
|
||||
if (modrm_reg == CFI_SP) {
|
||||
ADD_OP(op) {
|
||||
op->src.type = OP_SRC_REG;
|
||||
op->src.reg = CFI_SP;
|
||||
op->dest.type = OP_DEST_REG_INDIRECT;
|
||||
op->dest.reg = modrm_rm;
|
||||
op->dest.offset = ins.displacement.value;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -3000,6 +3000,20 @@ static int update_cfi_state(struct instruction *insn,
|
||||
cfi->stack_size += 8;
|
||||
}
|
||||
|
||||
else if (cfi->vals[op->src.reg].base == CFI_CFA) {
|
||||
/*
|
||||
* Clang RSP musical chairs:
|
||||
*
|
||||
* mov %rsp, %rdx [handled above]
|
||||
* ...
|
||||
* mov %rdx, %rbx [handled here]
|
||||
* ...
|
||||
* mov %rbx, %rsp [handled above]
|
||||
*/
|
||||
cfi->vals[op->dest.reg].base = CFI_CFA;
|
||||
cfi->vals[op->dest.reg].offset = cfi->vals[op->src.reg].offset;
|
||||
}
|
||||
|
||||
|
||||
break;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user