@@ -653,34 +653,38 @@ void CLG_(setup_bbcc)(BB* bb)
653653 /* Manipulate JmpKind if needed, only using BB specific info */
654654
655655 csp = CLG_ (current_call_stack ).sp ;
656-
657656 /* A return not matching the top call in our callstack is a jump */
658657 if ( (jmpkind == jk_Return ) && (csp > 0 )) {
659658 Int csp_up = csp - 1 ;
660659 call_entry * top_ce = & (CLG_ (current_call_stack ).entry [csp_up ]);
661660
662- /* We have a real return if
663- * - the stack pointer (SP) left the current stack frame, or
664- * - SP has the same value as when reaching the current function
665- * and the address of this BB is the return address of last call
666- * (we even allow to leave multiple frames if the SP stays the
667- * same and we find a matching return address)
668- * The latter condition is needed because on PPC, SP can stay
669- * the same over CALL=b(c)l / RET=b(c)lr boundaries
661+ /* We have a real return if the stack pointer (SP) left the
662+ * current stack frame. If the return target matches an older
663+ * shadow-stack frame whose entry SP is also outside the current
664+ * native frame, unwind all intervening frames. This happens in
665+ * hand-written startup/loader code that can collapse multiple native
666+ * frames before returning to a saved link register.
667+ *
668+ * If SP is unchanged, require the return target to match the recorded
669+ * return address. This is needed because on PPC, SP can stay the same
670+ * over CALL=b(c)l / RET=b(c)lr boundaries.
670671 */
671- if (sp < top_ce -> sp ) popcount_on_return = 0 ;
672- else if (top_ce -> sp == sp ) {
672+ if (sp < top_ce -> sp ) {
673+ popcount_on_return = 0 ;
674+ }
675+ else {
676+ Bool sp_changed = top_ce -> sp != sp ;
673677 while (1 ) {
674678 if (top_ce -> ret_addr == bb_addr (bb )) break ;
675679 if (csp_up > 0 ) {
676680 csp_up -- ;
677681 top_ce = & (CLG_ (current_call_stack ).entry [csp_up ]);
678- if (top_ce -> sp = = sp ) {
682+ if (top_ce -> sp < = sp ) {
679683 popcount_on_return ++ ;
680- continue ;
684+ continue ;
681685 }
682686 }
683- popcount_on_return = 0 ;
687+ popcount_on_return = sp_changed ? 1 : 0 ;
684688 break ;
685689 }
686690 }
0 commit comments