Introduce __save_reg() which allows using the !arch_callee_saved_reg()s and make sure they're wiped after every stack op so they don't linger, allow for a single op exception so they can be used on the very next stack-op.
Signed-off-by: Peter Zijlstra (Intel) <pet...@infradead.org> --- tools/objtool/check.c | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -1775,15 +1775,20 @@ static int update_cfi_state_regs(struct return 0; } -static void save_reg(struct cfi_state *cfi, unsigned char reg, int base, int offset) +static void __save_reg(struct cfi_state *cfi, unsigned char reg, int base, int offset) { - if (arch_callee_saved_reg(reg) && - cfi->regs[reg].base == CFI_UNDEFINED) { + if (cfi->regs[reg].base == CFI_UNDEFINED) { cfi->regs[reg].base = base; cfi->regs[reg].offset = offset; } } +static void save_reg(struct cfi_state *cfi, unsigned char reg, int base, int offset) +{ + if (arch_callee_saved_reg(reg)) + __save_reg(cfi, reg, base, offset); +} + static void restore_reg(struct cfi_state *cfi, unsigned char reg) { cfi->regs[reg].base = initial_func_cfi.regs[reg].base; @@ -1848,6 +1853,7 @@ static int update_cfi_state(struct instr { struct cfi_reg *cfa = &cfi->cfa; struct cfi_reg *regs = cfi->regs; + bool skip_wipe = false; /* stack operations don't make sense with an undefined CFA */ if (cfa->base == CFI_UNDEFINED) { @@ -2192,6 +2198,21 @@ static int update_cfi_state(struct instr return -1; } + /* + * Only callee saved registers are preserved; the rest is scratch space + * preserved at most one instruction. + */ + if (!skip_wipe) { + int i; + + for (i = 0; i < CFI_NUM_REGS; i++) { + if (arch_callee_saved_reg(i)) + continue; + + restore_reg(cfi, i); + } + } + return 0; }