Re: objtool: undefined stack state in folio_zero_user()

From: Peter Zijlstra

Date: Tue Jun 30 2026 - 09:57:57 EST



+ KMSAN / clang folks

On Tue, Jun 30, 2026 at 12:44:35PM +0200, Peter Zijlstra wrote:
> On Mon, Jun 22, 2026 at 04:23:46PM +0300, Dmitry Antipov wrote:
> > As of ef0c9f75a195 ("lib: Add stale 'raid6' directory to .gitignore file")
> > with clang 22.1.8 and KMSAN enabled, objtool stucks in folio_zero_user():
> >
> > $ ./tools/objtool/objtool --hacks=jump_label --hacks=noinstr \
> > --hacks=skylake --ibt --prefix=16 --orc --retpoline --rethunk \
> > --static-call --uaccess --no-unreachable --noinstr --unret --link \
> > vmlinux.o
> > vmlinux.o: warning: objtool: folio_zero_user+0x947: undefined stack state
> > vmlinux.o: error: objtool: folio_zero_user+0x947: unknown CFA base reg -1
> >
> > Dmitry
>
> > 0000000001533940 <folio_zero_user>:
>
> > 1534272: 48 89 e1 mov %rsp,%rcx
> > 1534275: 48 85 ed test %rbp,%rbp
> > 1534278: 8b 54 24 1c mov 0x1c(%rsp),%edx
> > 153427c: 0f 85 c2 00 00 00 jne 1534344 <folio_zero_user+0xa04>
> > 1534282: 31 c0 xor %eax,%eax
> > 1534284: 48 89 cc mov %rcx,%rsp
> > 1534287: 4c 89 f7 mov %r14,%rdi ;; HERE
>
> ...
> > 1534327: 48 89 64 24 78 mov %rsp,0x78(%rsp)
> ...
> > 153433a: 48 8b 4c 24 78 mov 0x78(%rsp),%rcx
> > 153433f: e9 31 ff ff ff jmp 1534275 <folio_zero_user+0x935>
>
>
> This is well insane codegen, and I cannot blame objtool for hating on it
> -- in fact, I hate on it too.
>
> Let me try and figure out how best to fix this insane compiler output.


This seems to 'work', but it is somewhat yuck.

Josh, any better ideas?

---
diff --git a/tools/objtool/arch/x86/decode.c b/tools/objtool/arch/x86/decode.c
index 1b387d5a195b..839c91d3c28c 100644
--- a/tools/objtool/arch/x86/decode.c
+++ b/tools/objtool/arch/x86/decode.c
@@ -391,7 +391,7 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec

break;

- case 0x89:
+ case 0x89: /* mov r16/32/64,r/m16/32/64 */
if (!rex_w)
break;

@@ -430,7 +430,7 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec
}

fallthrough;
- case 0x88:
+ case 0x88: /* mov r8, r/m8 */
if (!rex_w)
break;

@@ -462,7 +462,7 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec

break;

- case 0x8b:
+ case 0x8b: /* mov r/m16/32/64, r16/32/64 */
if (!rex_w)
break;

@@ -494,6 +494,9 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec

break;

+ case 0x8a: /* mov r/m8, r8 */
+ break;
+
case 0x8d:
if (mod_is_reg()) {
WARN("invalid LEA encoding at %s:0x%lx", sec->name, offset);
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 10b18cf9c360..53a67b322856 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -3149,8 +3149,25 @@ static int update_cfi_state(struct instruction *insn,
/* drap: mov disp(%rbp), %reg */
restore_reg(cfi, op->dest.reg);

+ } else if (op->src.reg == CFI_SP &&
+ regs[CFI_SP].base == CFI_CFA &&
+ op->src.offset == regs[CFI_SP].offset + cfi->stack_size) {
+
+ /*
+ * Clang RSP musical chains:
+ *
+ * mov %rsp, disp(%rsp)
+ * ...
+ * mov disp(%rsp), %reg [handled here]
+ * ...
+ * mov %reg, %rsp
+ */
+ cfi->vals[op->dest.reg].base = CFI_CFA;
+ cfi->vals[op->dest.reg].offset = -cfi->stack_size;
+ restore_reg(cfi, CFI_SP);
+
} else if (op->src.reg == cfa->base &&
- op->src.offset == regs[op->dest.reg].offset + cfa->offset) {
+ op->src.offset == regs[op->dest.reg].offset + cfa->offset) {

/* mov disp(%rbp), %reg */
/* mov disp(%rsp), %reg */
@@ -3233,6 +3250,12 @@ static int update_cfi_state(struct instruction *insn,

} else if (op->dest.reg == cfa->base) {

+ /* mov %rsp, disp(%rsp) */
+ if (op->src.reg == CFI_SP && cfi->regs[CFI_SP].base == CFI_UNDEFINED) {
+ cfi->regs[CFI_SP].base = CFI_CFA;
+ cfi->regs[CFI_SP].offset = op->dest.offset - cfi->stack_size;
+ }
+
/* mov reg, disp(%rbp) */
/* mov reg, disp(%rsp) */
save_reg(cfi, op->src.reg, CFI_CFA,