Hi,
when debugging a program that makes heavy use of function pointers I
noticed that the CALL instruction is sometimes generated with a wrong
offset if the function pointer is stored on the stack.
The following piece of C code can be used to reproduce the problem. It
must be compiled with -ansi -Os with a recent (i.e. not older than about
6 months) mspgcc-3.2.3 version.
/*-------------------------------------------------------------------*/
#define RETTYPE int
#if 0
int vararg_func(int a, ...) { return 0; }
#else
#define vararg_func(a,b,c) do { } while(0)
#endif
RETTYPE call_target(int a) { }
void twoarg(int a, int b) { }
void threearg(int a, int b, int c) { }
void fourarg(int a, int b, int c, int d) { }
volatile int global;
void indirect_call(int x1, int x2, int x3, RETTYPE (*funcptr)(int)) {
/* volatile access to create pressure on register allocator*/
int a = global, b = global, c = global, d = global, e = global;
int f = global, g = global;
threearg(a, b, c);
threearg(d, e, f);
fourarg(a, b, c, g);
vararg_func(a, b, c);
funcptr(x1);
}
int main(void) {
indirect_call(0, 0, 0, call_target);
puts("We survived");
}
/*-------------------------------------------------------------------*/
The problem is also dependent on the return type of the function
pointer: Calls of return type void are always generated wrong. The
following table lists the setting of the #defines in the beginning of
the example program and generated parameter for the call instruction:
define return type expected output from mspgcc
#if 0 void 2(r1) @r1
#if 1 void 8(r1) 6(r1)
#if 0 int 2(r1) @r1
#if 1 int 8(r1) 8(r1)
I have no clue how gcc backends work, but after skimming over the code I
think I found the right things to change. The attached patch should fix
the problem, at least the code for my specific application is generated
correctly with this patch, but I can't guarantee for any unexpected side
effects.
Regards,
Klaus.
diff -Naur msp430_orig/msp430.c msp430/msp430.c
--- msp430_orig/msp430.c 2009-03-22 12:37:31.000000000 +0100
+++ msp430/msp430.c 2009-05-02 16:35:08.000000000 +0200
@@ -1411,6 +1411,9 @@
}
else if (GET_CODE (addr) == REG)
{ /* for X(Rn) */
+ /* shift if the indirect pointer register is the stack pointer */
+ if ((code >= 'M' && code <= 'N') && (REGNO (addr)) == 1)
+ shift = code - 'M';
if (shift || !source_reg)
{
if (shift)
diff -Naur msp430_orig/msp430.md msp430/msp430.md
--- msp430_orig/msp430.md 2006-01-30 09:47:05.000000000 +0100
+++ msp430/msp430.md 2009-05-02 15:32:38.000000000 +0200
@@ -356,7 +356,7 @@
[(call (mem:HI (match_operand:HI 0 "general_operand" "r,P,mi"))
(match_operand:HI 1 "general_operand" "X,X,X"))]
""
-"call\\t%0"
+"call\\t%N0"
[ (set_attr "length" "1,1,2")
(set_attr "cc" "clobber")])