[arm-gnu] Strange assembly generated in G++ ARM Thumb mode
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[arm-gnu] Strange assembly generated in G++ ARM Thumb mode
- To: arm-gnu@xxxxxxxxxxxxxxxx
- Subject: [arm-gnu] Strange assembly generated in G++ ARM Thumb mode
- From: Matt Fischer <mattfischer84@xxxxxxxxx>
- Date: Wed, 10 Aug 2011 12:32:02 -0500
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