[arm-gnu] Re: Strange assembly generated in G++ ARM Thumb mode
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[arm-gnu] Re: Strange assembly generated in G++ ARM Thumb mode



Ping.  Any takers on this?  Or would it be better to ask the main GCC
list about it?

Thanks,
Matt

On Wed, Aug 10, 2011 at 12:32 PM, Matt Fischer <mattfischer84@xxxxxxxxx> wrote:
> I have a question about some assembly code that's being generated by
> G++.  It looks wrong to me (and causes a crash when run), but I'm not
> yet entirely certain whether it's an error in the compiler or some
> kind of mistake in the code that it's compiling.  I'd appreciate any
> insights.
>
> A test program that illustrates the problem is the following:
>
> -----------------------------------------------------------
>
> #include <boost/signal.hpp>
>
> bool func()
> {
>  return false;
> }
>
> int main(int argc, char *argv[])
> {
>  boost::signal<bool ()> sig;
>  sig.connect(func);
>  bool result = sig();
> }
>
> ------------------------------------------------------------
>
> When compiled with most combinations of ARM flags, this works just
> fine (this is G++ 4.5.2 on Windows, with Boost version 1.40).
> However, when I try to build this as -mthumb -Os, I get the following
> code sequence down inside some random Boost function:
>
> 00000000 <boost::detail::postfix_increment_result<boost::signals::detail::slot_call_iterator<boost::signals::detail::call_bound0<bool>::caller<boost::functi
>   0:   b537            push    {r0, r1, r2, r4, r5, lr}
>   2:   1c05            adds    r5, r0, #0
>   4:   ac01            add     r4, sp, #4
>   6:   1c29            adds    r1, r5, #0
>   8:   1c20            adds    r0, r4, #0
>   a:   f7ff fffe       bl      0
> <boost::detail::postfix_increment_result<boost::signals::detail::slot_call_iterator<boost::signals::detail::call_bound0<bo
>   e:   1c28            adds    r0, r5, #0
>  10:   f7ff fffe       bl      0
> <boost::detail::postfix_increment_result<boost::signals::detail::slot_call_iterator<boost::signals::detail::call_bound0<bo
>  14:   7820            ldrb    r0, [r4, #0]
>  16:   bc37            pop     {r0, r1, r2, r4, r5}
>  18:   bc02            pop     {r1}
>  1a:   4708            bx      r1
>
> I have no idea what this particular function does (it's Boost, so who
> really does), but stepping through this code in a debugger shows that
> its return value is getting corrupted.  Examining the assembly reveals
> why.  This function returns a bool, and you can see it loading up r0
> with the byte at [r4, #0] at the end of the function, in preparation
> for function return.  However, immediately after that, we pop off
> stack contents into r0-r2, destroying this value, and causing the
> function to return garbage to its caller.
>
> If I change the type of the return from bool to int, the problem goes away:
>
> 00000000 <boost::detail::postfix_increment_result<boost::signals::detail::slot_call_iterator<boost::signals::detail::call_bound0<int>::caller<boost::functio
>   0:   b513            push    {r0, r1, r4, lr}
>   2:   1c04            adds    r4, r0, #0
>   4:   1c21            adds    r1, r4, #0
>   6:   a801            add     r0, sp, #4
>   8:   f7ff fffe       bl      0
> <boost::detail::postfix_increment_result<boost::signals::detail::slot_call_iterator<boost::signals::detail::call_bound0<in
>   c:   1c20            adds    r0, r4, #0
>   e:   f7ff fffe       bl      0
> <boost::detail::postfix_increment_result<boost::signals::detail::slot_call_iterator<boost::signals::detail::call_bound0<in
>  12:   9801            ldr     r0, [sp, #4]
>  14:   bc16            pop     {r1, r2, r4}
>  16:   bc02            pop     {r1}
>  18:   4708            bx      r1
>
> This leads to a couple questions:
>
> 1)  Why is GCC saving r0-r2 anyway?  They're caller-saved, so it
> shouldn't have any problem overwriting them in the function.
> 2)  Given that it is saving them, why is it restoring them at the
> expense of the function's return value?
> 3)  Even in the second case, where the return value is being preserved
> properly, we're getting this return value from [sp, #4], which is the
> value that we're also going to then put into r2 during the final pop.
> Why are we saving registers to the stack and then turning around and
> using those locations as temp space?
>
> My best guess at this point is that we're pushing r0-r2 during the
> prologue as some poor man's way of creating temp space on the stack
> without needing a separate 'sub sp, #' instruction, but then we're
> forgetting about the fact that we're returning a value at the end of
> the function, so we accidentally pop over the top of r0 during the
> epilogue, or something like that.
>
> I always hate to be the idiot who cries "compiler bug" at the first
> sign of weirdness, only to eventually discover some more mundane
> solution, but this does seem pretty weird to me.  Can anybody shed any
> light on what's going on here?
>
> Thanks,
> Matt
>