From 14fc15928b31c18c06f6c075ba0394c0000d3981 Mon Sep 17 00:00:00 2001 From: Tommi Rantala Date: Fri, 10 Aug 2012 10:58:57 +0300 Subject: [PATCH] ARM: fix non-signal-frame local unw_resume() due to compiler optimization cleverness When cross-compiling libunwind with optimizations (-O1 or higher), gcc-4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5) optimizes away the memory writes prior to the inline asm() statement in arm_local_resume() in the non-signal-frame path, causing the `regs' array to be only allocated on the stack, but not populated. This means that we are restoring garbage to the registers. As suggested in the GCC docs, add a fixed size input memory constraint for the array content. This is enough to get the desired code to be generated. Adding __builtin_unreachable() to the point that we should never reach was also in itself enough to inhibit the optimization. It also reduces the function size by a few instructions. --- src/arm/Gresume.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/arm/Gresume.c b/src/arm/Gresume.c index da45dec8..4100d873 100644 --- a/src/arm/Gresume.c +++ b/src/arm/Gresume.c @@ -1,6 +1,7 @@ /* libunwind - a platform-independent unwind library Copyright (C) 2008 CodeSourcery Copyright 2011 Linaro Limited + Copyright (C) 2012 Tommi Rantala This file is part of libunwind. @@ -51,11 +52,16 @@ arm_local_resume (unw_addr_space_t as, unw_cursor_t *cursor, void *arg) regs[8] = uc->regs[13]; /* SP */ regs[9] = uc->regs[14]; /* LR */ + struct regs_overlay { + char x[sizeof(regs)]; + }; + asm __volatile__ ( "ldmia %0, {r4-r12, lr}\n" "mov sp, r12\n" "bx lr\n" - : : "r" (regs) + : : "r" (regs), + "m" (*(struct regs_overlay *)regs) ); } else @@ -90,6 +96,7 @@ arm_local_resume (unw_addr_space_t as, unw_cursor_t *cursor, void *arg) : : "r" (c->sigcontext_sp), "r" (c->sigcontext_pc) ); } + __builtin_unreachable(); #else printf ("%s: implement me\n", __FUNCTION__); #endif