]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
objtool: Handle Clang RSP musical chairs
authorJosh Poimboeuf <jpoimboe@kernel.org>
Fri, 6 Mar 2026 17:35:06 +0000 (09:35 -0800)
committerJosh Poimboeuf <jpoimboe@kernel.org>
Mon, 9 Mar 2026 15:45:10 +0000 (08:45 -0700)
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>
tools/objtool/arch/x86/decode.c
tools/objtool/check.c

index 73bfea220d1bf613ea94048158e6336ba88523fb..c5817829cdfac05fc17959db7aee4cb10988c7b4 100644 (file)
@@ -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;
+               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 = modrm_rm;
                        }
-
                        break;
                }
 
-               if (rm_is_reg(CFI_SP)) {
+               /* skip RIP relative displacement */
+               if (is_RIP())
+                       break;
 
-                       /* mov reg, %rsp */
+               /* 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 = modrm_reg;
-                               op->dest.type = OP_DEST_REG;
-                               op->dest.reg = CFI_SP;
+                               op->src.reg = CFI_SP;
+                               op->dest.type = OP_DEST_REG_INDIRECT;
+                               op->dest.reg = modrm_rm;
+                               op->dest.offset = ins.displacement.value;
                        }
                        break;
                }
index a30379e4ff97e5b63bfcf842e9bde45fe1af7c07..786b2f2adbab6b4879063a4c82df9154cd3abf4a 100644 (file)
@@ -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;