UNWIND_HINT type=UNWIND_HINT_TYPE_RESTORE
 .endm
 
+
+/*
+ * RET_OFFSET: Used on instructions that terminate a function; mostly RETURN
+ * and sibling calls. On these, sp_offset denotes the expected offset from
+ * initial_func_cfi.
+ */
+.macro UNWIND_HINT_RET_OFFSET sp_offset=8
+       UNWIND_HINT type=UNWIND_HINT_TYPE_RET_OFFSET sp_offset=\sp_offset
+.endm
+
 #else /* !__ASSEMBLY__ */
 
 #define UNWIND_HINT(sp_reg, sp_offset, type, end)              \
 
                } else if (hint->type == UNWIND_HINT_TYPE_RESTORE) {
                        insn->restore = true;
                        insn->hint = true;
+
+               } else if (hint->type == UNWIND_HINT_TYPE_RET_OFFSET) {
+                       insn->ret_offset = hint->sp_offset;
                        continue;
                }
 
        return false;
 }
 
-static bool has_modified_stack_frame(struct insn_state *state)
+static bool has_modified_stack_frame(struct instruction *insn, struct insn_state *state)
 {
+       u8 ret_offset = insn->ret_offset;
        int i;
 
-       if (state->cfa.base != initial_func_cfi.cfa.base ||
-           state->cfa.offset != initial_func_cfi.cfa.offset ||
-           state->stack_size != initial_func_cfi.cfa.offset ||
-           state->drap)
+       if (state->cfa.base != initial_func_cfi.cfa.base || state->drap)
+               return true;
+
+       if (state->cfa.offset != initial_func_cfi.cfa.offset + ret_offset)
                return true;
 
-       for (i = 0; i < CFI_NUM_REGS; i++)
+       if (state->stack_size != initial_func_cfi.cfa.offset + ret_offset)
+               return true;
+
+       for (i = 0; i < CFI_NUM_REGS; i++) {
                if (state->regs[i].base != initial_func_cfi.regs[i].base ||
                    state->regs[i].offset != initial_func_cfi.regs[i].offset)
                        return true;
+       }
 
        return false;
 }
 
 static int validate_sibling_call(struct instruction *insn, struct insn_state *state)
 {
-       if (has_modified_stack_frame(state)) {
+       if (has_modified_stack_frame(insn, state)) {
                WARN_FUNC("sibling call from callable instruction with modified stack frame",
                                insn->sec, insn->offset);
                return 1;
                return 1;
        }
 
-       if (func && has_modified_stack_frame(state)) {
+       if (func && has_modified_stack_frame(insn, state)) {
                WARN_FUNC("return with modified stack frame",
                          insn->sec, insn->offset);
                return 1;
 
        unsigned int len;
        enum insn_type type;
        unsigned long immediate;
-       bool alt_group, dead_end, ignore, hint, save, restore, ignore_alts;
+       bool alt_group, dead_end, ignore, ignore_alts;
+       bool hint, save, restore;
        bool retpoline_safe;
        u8 visited;
+       u8 ret_offset;
        struct symbol *call_dest;
        struct instruction *jump_dest;
        struct instruction *first_jump_src;