Re: [PATCH] objtool: Support Clang RAX DRAP sequence

From: Josh Poimboeuf

Date: Tue Mar 17 2026 - 18:45:04 EST


On Tue, Mar 17, 2026 at 09:35:02PM +0100, Peter Zijlstra wrote:
> On Tue, Mar 17, 2026 at 08:30:59AM -0700, Josh Poimboeuf wrote:
> > On Tue, Mar 17, 2026 at 09:18:25AM +0100, Peter Zijlstra wrote:
> > > On Mon, Mar 16, 2026 at 05:47:56PM -0700, Josh Poimboeuf wrote:
> > > > Recent Clang can use RAX as a temporary register for the DRAP stack
> > > > alignment sequence. Add support for that.
> > > >
> > > > Fixes the following warning:
> > > >
> > > > vmlinux.o: error: objtool: vmw_host_printf+0xd: unknown CFA base reg 0
> > > >
> > > > Reported-by: Arnd Bergmann <arnd@xxxxxxxx>
> > > > Closes: https://lore.kernel.org/cefefdd1-7b82-406d-8ff4-e4b167e45ee6@xxxxxxxxxxxxxxxx
> > > > Signed-off-by: Josh Poimboeuf <jpoimboe@xxxxxxxxxx>
> > > > ---
> > > > arch/x86/include/asm/orc_types.h | 1 +
> > > > arch/x86/kernel/unwind_orc.c | 8 ++++++++
> > > > tools/arch/x86/include/asm/orc_types.h | 1 +
> > > > tools/objtool/arch/x86/decode.c | 3 +++
> > > > tools/objtool/arch/x86/orc.c | 5 +++++
> > > > 5 files changed, 18 insertions(+)
> > > >
> > > > diff --git a/arch/x86/include/asm/orc_types.h b/arch/x86/include/asm/orc_types.h
> > > > index e0125afa53fb..b3cc7970fa54 100644
> > > > --- a/arch/x86/include/asm/orc_types.h
> > > > +++ b/arch/x86/include/asm/orc_types.h
> > > > @@ -37,6 +37,7 @@
> > > > #define ORC_REG_R13 7
> > > > #define ORC_REG_BP_INDIRECT 8
> > > > #define ORC_REG_SP_INDIRECT 9
> > > > +#define ORC_REG_AX 10
> > > > #define ORC_REG_MAX 15
> > >
> > > I'm 'annoyed' at the placement of that register. I know its not
> > > important, but I can't silence my OCD saying that AX should come before
> > > DX.
> > >
> > > Also, SP comes before BP and both before DI.
> > >
> > > Something like so perhaps?
> >
> > That bothered me too, but I was trying to keep the diffstat down. But
> > sure, why not...
> >
> > What about the switch statements? Should we reorder them too while at
> > it? If so, starting to feel like a separate patch.
>
> Agreed, switch statement order should match the definition order. And
> yes separate patch is fine.

Ok, we can add the following on top:

---8<---

From: Josh Poimboeuf <jpoimboe@xxxxxxxxxx>
Subject: [PATCH] objtool/x86: Reorder ORC register numbering

Reorder the ORC register values so their ordering matches the x86
instruction set register encodings.

No functional change intended.

Suggested-by: Peter Zijlstra <peterz@xxxxxxxxxxxxx>
Signed-off-by: Josh Poimboeuf <jpoimboe@xxxxxxxxxx>
---
arch/x86/include/asm/orc_types.h | 10 +++---
arch/x86/kernel/unwind_orc.c | 48 +++++++++++++++-----------
tools/arch/x86/include/asm/orc_types.h | 10 +++---
tools/objtool/arch/x86/decode.c | 21 ++++++-----
tools/objtool/arch/x86/orc.c | 36 +++++++++----------
5 files changed, 67 insertions(+), 58 deletions(-)

diff --git a/arch/x86/include/asm/orc_types.h b/arch/x86/include/asm/orc_types.h
index b3cc7970fa54..5837c2bb277f 100644
--- a/arch/x86/include/asm/orc_types.h
+++ b/arch/x86/include/asm/orc_types.h
@@ -28,16 +28,16 @@
* and GCC realigned stacks.
*/
#define ORC_REG_UNDEFINED 0
-#define ORC_REG_PREV_SP 1
+#define ORC_REG_AX 1
#define ORC_REG_DX 2
-#define ORC_REG_DI 3
+#define ORC_REG_SP 3
#define ORC_REG_BP 4
-#define ORC_REG_SP 5
+#define ORC_REG_DI 5
#define ORC_REG_R10 6
#define ORC_REG_R13 7
-#define ORC_REG_BP_INDIRECT 8
+#define ORC_REG_PREV_SP 8
#define ORC_REG_SP_INDIRECT 9
-#define ORC_REG_AX 10
+#define ORC_REG_BP_INDIRECT 10
#define ORC_REG_MAX 15

#define ORC_TYPE_UNDEFINED 0
diff --git a/arch/x86/kernel/unwind_orc.c b/arch/x86/kernel/unwind_orc.c
index 32f7e918d3d9..6407bc9256bf 100644
--- a/arch/x86/kernel/unwind_orc.c
+++ b/arch/x86/kernel/unwind_orc.c
@@ -546,25 +546,15 @@ bool unwind_next_frame(struct unwind_state *state)
indirect = true;
break;

- case ORC_REG_R10:
- if (!get_reg(state, offsetof(struct pt_regs, r10), &sp)) {
- orc_warn_current("missing R10 value at %pB\n",
- (void *)state->ip);
- goto err;
- }
- break;
+ /*
+ * Any of the below registers may temporarily hold the stack pointer,
+ * typically during a DRAP stack realignment sequence or some other
+ * stack swizzle.
+ */

- case ORC_REG_R13:
- if (!get_reg(state, offsetof(struct pt_regs, r13), &sp)) {
- orc_warn_current("missing R13 value at %pB\n",
- (void *)state->ip);
- goto err;
- }
- break;
-
- case ORC_REG_DI:
- if (!get_reg(state, offsetof(struct pt_regs, di), &sp)) {
- orc_warn_current("missing RDI value at %pB\n",
+ case ORC_REG_AX:
+ if (!get_reg(state, offsetof(struct pt_regs, ax), &sp)) {
+ orc_warn_current("missing AX value at %pB\n",
(void *)state->ip);
goto err;
}
@@ -578,9 +568,25 @@ bool unwind_next_frame(struct unwind_state *state)
}
break;

- case ORC_REG_AX:
- if (!get_reg(state, offsetof(struct pt_regs, ax), &sp)) {
- orc_warn_current("missing AX value at %pB\n",
+ case ORC_REG_DI:
+ if (!get_reg(state, offsetof(struct pt_regs, di), &sp)) {
+ orc_warn_current("missing RDI value at %pB\n",
+ (void *)state->ip);
+ goto err;
+ }
+ break;
+
+ case ORC_REG_R10:
+ if (!get_reg(state, offsetof(struct pt_regs, r10), &sp)) {
+ orc_warn_current("missing R10 value at %pB\n",
+ (void *)state->ip);
+ goto err;
+ }
+ break;
+
+ case ORC_REG_R13:
+ if (!get_reg(state, offsetof(struct pt_regs, r13), &sp)) {
+ orc_warn_current("missing R13 value at %pB\n",
(void *)state->ip);
goto err;
}
diff --git a/tools/arch/x86/include/asm/orc_types.h b/tools/arch/x86/include/asm/orc_types.h
index b3cc7970fa54..5837c2bb277f 100644
--- a/tools/arch/x86/include/asm/orc_types.h
+++ b/tools/arch/x86/include/asm/orc_types.h
@@ -28,16 +28,16 @@
* and GCC realigned stacks.
*/
#define ORC_REG_UNDEFINED 0
-#define ORC_REG_PREV_SP 1
+#define ORC_REG_AX 1
#define ORC_REG_DX 2
-#define ORC_REG_DI 3
+#define ORC_REG_SP 3
#define ORC_REG_BP 4
-#define ORC_REG_SP 5
+#define ORC_REG_DI 5
#define ORC_REG_R10 6
#define ORC_REG_R13 7
-#define ORC_REG_BP_INDIRECT 8
+#define ORC_REG_PREV_SP 8
#define ORC_REG_SP_INDIRECT 9
-#define ORC_REG_AX 10
+#define ORC_REG_BP_INDIRECT 10
#define ORC_REG_MAX 15

#define ORC_TYPE_UNDEFINED 0
diff --git a/tools/objtool/arch/x86/decode.c b/tools/objtool/arch/x86/decode.c
index 5931b2393bd8..350b8ee6e776 100644
--- a/tools/objtool/arch/x86/decode.c
+++ b/tools/objtool/arch/x86/decode.c
@@ -875,14 +875,20 @@ int arch_decode_hint_reg(u8 sp_reg, int *base)
case ORC_REG_UNDEFINED:
*base = CFI_UNDEFINED;
break;
+ case ORC_REG_AX:
+ *base = CFI_AX;
+ break;
+ case ORC_REG_DX:
+ *base = CFI_DX;
+ break;
case ORC_REG_SP:
*base = CFI_SP;
break;
case ORC_REG_BP:
*base = CFI_BP;
break;
- case ORC_REG_SP_INDIRECT:
- *base = CFI_SP_INDIRECT;
+ case ORC_REG_DI:
+ *base = CFI_DI;
break;
case ORC_REG_R10:
*base = CFI_R10;
@@ -890,14 +896,11 @@ int arch_decode_hint_reg(u8 sp_reg, int *base)
case ORC_REG_R13:
*base = CFI_R13;
break;
- case ORC_REG_DI:
- *base = CFI_DI;
+ case ORC_REG_SP_INDIRECT:
+ *base = CFI_SP_INDIRECT;
break;
- case ORC_REG_DX:
- *base = CFI_DX;
- break;
- case ORC_REG_AX:
- *base = CFI_AX;
+ case ORC_REG_BP_INDIRECT:
+ *base = CFI_BP_INDIRECT;
break;
default:
return -1;
diff --git a/tools/objtool/arch/x86/orc.c b/tools/objtool/arch/x86/orc.c
index 5494bb450ab5..eff078ecc945 100644
--- a/tools/objtool/arch/x86/orc.c
+++ b/tools/objtool/arch/x86/orc.c
@@ -46,17 +46,20 @@ int init_orc_entry(struct orc_entry *orc, struct cfi_state *cfi, struct instruct
orc->signal = cfi->signal;

switch (cfi->cfa.base) {
+ case CFI_AX:
+ orc->sp_reg = ORC_REG_AX;
+ break;
+ case CFI_DX:
+ orc->sp_reg = ORC_REG_DX;
+ break;
case CFI_SP:
orc->sp_reg = ORC_REG_SP;
break;
- case CFI_SP_INDIRECT:
- orc->sp_reg = ORC_REG_SP_INDIRECT;
- break;
case CFI_BP:
orc->sp_reg = ORC_REG_BP;
break;
- case CFI_BP_INDIRECT:
- orc->sp_reg = ORC_REG_BP_INDIRECT;
+ case CFI_DI:
+ orc->sp_reg = ORC_REG_DI;
break;
case CFI_R10:
orc->sp_reg = ORC_REG_R10;
@@ -64,14 +67,11 @@ int init_orc_entry(struct orc_entry *orc, struct cfi_state *cfi, struct instruct
case CFI_R13:
orc->sp_reg = ORC_REG_R13;
break;
- case CFI_DI:
- orc->sp_reg = ORC_REG_DI;
+ case CFI_SP_INDIRECT:
+ orc->sp_reg = ORC_REG_SP_INDIRECT;
break;
- case CFI_DX:
- orc->sp_reg = ORC_REG_DX;
- break;
- case CFI_AX:
- orc->sp_reg = ORC_REG_AX;
+ case CFI_BP_INDIRECT:
+ orc->sp_reg = ORC_REG_BP_INDIRECT;
break;
default:
ERROR_INSN(insn, "unknown CFA base reg %d", cfi->cfa.base);
@@ -125,24 +125,24 @@ static const char *reg_name(unsigned int reg)
switch (reg) {
case ORC_REG_PREV_SP:
return "prevsp";
+ case ORC_REG_AX:
+ return "ax";
case ORC_REG_DX:
return "dx";
- case ORC_REG_DI:
- return "di";
case ORC_REG_BP:
return "bp";
case ORC_REG_SP:
return "sp";
+ case ORC_REG_DI:
+ return "di";
case ORC_REG_R10:
return "r10";
case ORC_REG_R13:
return "r13";
- case ORC_REG_BP_INDIRECT:
- return "bp(ind)";
case ORC_REG_SP_INDIRECT:
return "sp(ind)";
- case ORC_REG_AX:
- return "ax";
+ case ORC_REG_BP_INDIRECT:
+ return "bp(ind)";
default:
return "?";
}
--
2.53.0