We are developing an application for the Atmel AVR32 / UC3C0512C using AtmelStudio 7.0.1645. While doing some basic tests, I noticed something very weird.
Please consider the following code (I know that it is bad style and uncommon, but that's not the point here):
float GetAtan2f(float p_f_y,
float p_f_x)
{
unsigned int l_ui_x,
l_ui_y,
l_ui_Sign_x,
l_ui_Sign_y,
l_ui_Result;
float l_f_Add,
l_f_Result;
asm volatile(
"RJMP GETATAN2_EXIT \n"
:
: /* 0 */ "m" (p_f_y),
/* 1 */ "m" (p_f_x)
: "cc", "memory", "r0", "r1", "r2", "r3", "r5"
);
GETATAN2_EXIT:
return (l_f_Result);
}
When looking into the disassembly of that code (after it has been compiled / linked), I find the following:
Disassembly of section .text.GetAtan2f:
00078696 <GetAtan2f>:
78696: eb cd 40 af pushm r0-r3,r5,r7,lr
7869a: 1a 97 mov r7,sp
7869c: 20 9d sub sp,36
7869e: ef 4c ff e0 st.w r7[-32],r12
786a2: ef 4b ff dc st.w r7[-36],r11
786a6: e0 8f 00 00 bral 786a6 <GetAtan2f+0x10>
786aa: ee f8 ff fc ld.w r8,r7[-4]
786ae: 10 9c mov r12,r8
786b0: 2f 7d sub sp,-36
786b2: e3 cd 80 af ldm sp++,r0-r3,r5,r7,pc
We notice that rjmp
has become bral
- perfectly acceptable, just another mnemonic for the same thing.
But when looking at the branch target in that line, we also notice that this will produce an endless loop, which it clearly shouldn't. It should branch to 786aa
(which is the begin of the function return) instead of 786a6
.
If I change the code so that it reads
float GetAtan2f(float p_f_y,
float p_f_x)
{
unsigned int l_ui_x,
l_ui_y,
l_ui_Sign_x,
l_ui_Sign_y,
l_ui_Result;
float l_f_Add,
l_f_Result;
asm volatile(
"RJMP GETATAN2_EXIT \n"
:
: /* 0 */ "m" (p_f_y),
/* 1 */ "m" (p_f_x)
: "cc", "memory", "r0", "r1", "r2", "r3", "r5"
);
asm volatile(
"GETATAN2_EXIT: \n"
:
:
: "cc", "memory"
);
return (l_f_Result);
}
it works as expected, i.e. the disassembly now reads
Disassembly of section .text.GetAtan2f:
00078696 <GETATAN2_EXIT-0x12>:
78696: eb cd 40 af pushm r0-r3,r5,r7,lr
7869a: 1a 97 mov r7,sp
7869c: 20 9d sub sp,36
7869e: ef 4c ff e0 st.w r7[-32],r12
786a2: ef 4b ff dc st.w r7[-36],r11
786a6: c0 18 rjmp 786a8 <GETATAN2_EXIT>
000786a8 <GETATAN2_EXIT>:
786a8: ee f8 ff fc ld.w r8,r7[-4]
786ac: 10 9c mov r12,r8
786ae: 2f 7d sub sp,-36
786b0: e3 cd 80 af ldm sp++,r0-r3,r5,r7,pc
We notice that the branch target now is correct.
So the inline assembler obviously does not know about C labels (i.e. labels which are not in inline assembly), which per se would be O.K. - lesson learned.
But in addition it does not warn or throw errors when it encounters an unknown (undefined) label, but instead produces endless loops by just using an offset of 0 when branching / jumping to such labels.
I am considering the latter a catastrophic bug. It probably means that (without any warning) I'll get an endless loop in my software whenever I use an undefined label in inline assembly code (e.g. because of a typo).
Is there anything I can do about it?