Natively support the stack swizzle pattern:

        mov %rsp, (%[tos])
        mov %[tos], %rsp
        ...
        pop %rsp

with the constraint that %[tos] must be !arch_callee_saved_reg().

It uses the (newly minted) scratch regs to link the first two
stack-ops, and detect the SP to SP_INDIRECT swizzle.

Signed-off-by: Peter Zijlstra (Intel) <pet...@infradead.org>
---
 tools/objtool/check.c |   43 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 43 insertions(+)

--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -1937,6 +1937,34 @@ static int update_cfi_state(struct instr
                                        cfa->offset = 
-cfi->vals[op->src.reg].offset;
                                        cfi->stack_size = cfa->offset;
 
+                               } else if (cfa->base == CFI_SP &&
+                                          cfi->regs[op->src.reg].base == 
CFI_SP_INDIRECT &&
+                                          cfi->regs[op->src.reg].offset == 
cfa->offset) {
+
+                                       /*
+                                        * Stack swizzle:
+                                        *
+                                        * 1: mov %rsp, (%[tos])
+                                        * 2: mov %[tos], %rsp
+                                        *    ...
+                                        * 3: pop %rsp
+                                        *
+                                        * Where:
+                                        *
+                                        * 1 - places a pointer to the previous
+                                        *     stack at the Top-of-Stack of the
+                                        *     new stack.
+                                        *
+                                        * 2 - switches to the new stack.
+                                        *
+                                        * 3 - pops the Top-of-Stack to restore
+                                        *     the original stack.
+                                        *
+                                        * Note:
+                                        * %[tos] must not be a callee saved reg
+                                        */
+                                       cfa->base = CFI_SP_INDIRECT;
+
                                } else {
                                        cfa->base = CFI_UNDEFINED;
                                        cfa->offset = 0;
@@ -2028,6 +2056,13 @@ static int update_cfi_state(struct instr
 
                case OP_SRC_POP:
                case OP_SRC_POPF:
+                       if (op->dest.reg == CFI_SP && cfa->base == 
CFI_SP_INDIRECT) {
+
+                               /* pop %rsp; # restore from a stack swizzle */
+                               cfa->base = CFI_SP;
+                               break;
+                       }
+
                        if (!cfi->drap && op->dest.reg == cfa->base) {
 
                                /* pop %rbp */
@@ -2154,6 +2189,14 @@ static int update_cfi_state(struct instr
                        /* mov reg, disp(%rsp) */
                        save_reg(cfi, op->src.reg, CFI_CFA,
                                 op->dest.offset - cfi->cfa.offset);
+
+               } else if (op->src.reg == CFI_SP && op->dest.offset == 0) {
+
+                       /* mov %rsp, (%reg); # setup a stack swizzle. */
+                       if (!arch_callee_saved_reg(op->dest.reg)) {
+                               __save_reg(cfi, op->dest.reg, CFI_SP_INDIRECT, 
cfi->cfa.offset);
+                               skip_wipe = true;
+                       }
                }
 
                break;


Reply via email to