I don't see anything wrong here. Except for the concept of this call.
Right before the call instruction, R1 points to mem, so the compiler uses R1 as
the source for the call address.
But what does the processor do?
If it is instructed to CALL R1, it will push the return address on stack, then
decrements R1 and then jumps to the given address. Unfortunately, the address
was in R1 and R1 has been changed by teh last microcode
step. The processor does not care for the case that the call destination is R1.
It just takes the current value and moves it into R0.
Think of it as a macro
#define call(x) \
sub #2,r1 \
mov r0,@r1 \
mov x,r0
If you set x=r1, it won't work as expected.
All this happens outside the control (and knowledge) of the compiler and of
course causes a bad jump. The compiler does not analyze internal microcode
sub-steps when optimizing.
On the MSP5438, the errata sheet lists
> CPU26 CPU Module
> Function CALL SP does not behave as expected
> Description When the intention is to execute code from the stack, a CALL SP
> instruction skips the
> first piece of data (instruction) on the stack. The second piece of data at
> SP + 2 is used
> as the first executable instruction.
> Workaround Write the op code for a NOP as the first instruction on the stack.
> Begin the intended
> subroutine at address SP + 2.
which actually counteracts the effect that SP is decremented. Well, I'm not
sure whether it just counteracts this effect or even calls mem+2. My guess is
that it has to do with the 430X instruction set.
Nevertheless, you can easily circumvent the problem by changing your code to
unsigned char mem[102];
register void (*badcall)(void) = (void *)(mem+2);
which gives the (then) expected result
badguy:
sub #102, r1 ; 102, fpn 0
mov r1, r15
add #llo(2), r15
call r15
add #102, r1
ret
The same effect is acquired if you have some more local variables which are
placed on the stack AFTER mem. In this case too, R1 doesn't point to mem
anymore and therefore isn't used for the call.
Or you do it yourself in assembly...
__asm__ __volatile __ ( "mov r1 , r15 \r\n call r1":::"r15");
But after all, I must admit, the compiler should not generate a 'call r1' or
'call sp' instruction (and also not a "call x(sp)" which could be imagined for
a jump table on the stack) at all. So well, one could consider it a
compiler bug. Or rather an optimisation bug. If you disable optimisation, the
compiler will properly generate some much too complex code that does the 'right
thing' too.
JMGross
----- Ursprüngliche Nachricht -----
Von: thilo
An: [email protected]
Gesendet am: 25 Mrz 2010 08:43:25
Betreff: [Mspgcc-users] compiler bug in gcc 3.2.3/msp430 - calling a function
on the local stack will jump to the wrong address *(--sp)
Hello,
is this a known bug ?
The compiler generates wrong code for:
=======
void badguy()
{
unsigned char mem[100];
register void (*badcall)(void) = (void *)mem;
(*badcall)(); // this will call mem[-2]
}
========
The bits it does are:
=======================
badguy:
sub #100, r1 ; 100, fpn 0
/* prologue end (size=2) */
call r1 ; 12 *call_insn/1 [length = 1]
/* epilogue: frame size=100 */
add #100, r1
ret
===============
The msp2274 that I was using, is FIRST decrementing the SP (r1) and then
calling it.
msp430-gcc -O2 -mmcu=msp430x2274 -Werror -dp -S tfun.c
Is 3.2.3 still the latest supported compiler?
thanks
thilo
------------------------------------------------------------------------------
Download Intel® Parallel Studio Eval
Try the new software tools for yourself. Speed compiling, find bugs
proactively, and fine-tune applications for parallel performance.
See why Intel Parallel Studio got high marks during beta.
http://p.sf.net/sfu/intel-sw-dev
_______________________________________________
Mspgcc-users mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/mspgcc-users