Hi!

I found 2 bugs in msp430-gcc compiled from CVS checkout from 09.06.2005
running at Solaris 5.8 that have something to do with the handling of types
char and long long. MSP430-GCC is invoked with
msp430-gcc -g -O2 -mmcu=msp430x149 infile.c -o outfile.elf

------------------------------------
BUG 1 - char to long long conversion
MSP430-GCC crashes with segmentation fault running the following code: (Note
that I use some dummy copy functionts, to avoid too much optimisation.)
/******************************************************************/
#include <stdlib.h>
#include <msp430x14x.h>

unsigned char copyc(unsigned char in);
unsigned long long int copylli(unsigned long long int in);

int main (void) {
        unsigned long long int val, op;
        unsigned char op_char;
        unsigned int op_int;

        op_char = copyc(1);
        op = (unsigned long long int)op_char; /*segmentation fault*/
        // BEGIN WORKAROUND
        // op_int = (unsigned int)op_char;
        // op = (unsigned long long int)op_int;
        // END WORKAROUND
        val = copylli(op);
        P1OUT = (char)val + (char)((int)val >> 8);
        return CPUOFF;
}

unsigned char copyc(unsigned char in) {
        return in;
}

unsigned long long int copylli(unsigned long long int in) {
        return in;
}
/******************************************************************/
There is a workaround for this problem: Convert a char variable to an
intermediate int variable and then to long long as shown commented in the
source code.
------------------------------------

------------------------------------
BUG2 long long to char conversion
MSP430-GCC produces buggy output with the following code.
/******************************************************************/
#include <stdlib.h>
#include <msp430x14x.h>

unsigned long long int ulltest
(unsigned long long int a, unsigned long long int b);

int main (void) {
        unsigned long long int val;

        val = ulltest(0xfedcba9876543210, 0x0123456789abcdef);
        P1OUT = (char)val + (char)((int)val >> 8);
        return CPUOFF;
}

unsigned long long int ulltest
(unsigned long long int a, unsigned long long int b) {
        unsigned char a_char = (unsigned char)a;
        unsigned char b_char = (unsigned char)b;/*bug*/
        
        if (a_char & b_char) {
                return a;
        } else {
                return -b;
        }
}
/******************************************************************/
In function ulltest parameter a is a register parameter and parameter b is
passed via stack. Extracting b from stack and computing the value of b_char
is wrong. Let's see a part of the the listfile generated by MSP430-OBJDUMP:
msp430-objdump -DS outfile.elf > listfile.lst:
/******************************************************************/
unsigned long long int ulltest
(unsigned long long int a, unsigned long long int b) {
    1186:       0b 12           push    r11             ;
    1188:       0a 12           push    r10             ;
    118a:       09 12           push    r9              ;
    118c:       08 12           push    r8              ;
    118e:       07 12           push    r7              ;
    1190:       06 12           push    r6              ;
    1192:       3b 40 0e 00     mov     #14,    r11     ;#0x000e
    1196:       0b 51           add     r1,     r11     ;
    1198:       06 4c           mov     r12,    r6      ;
    119a:       07 4d           mov     r13,    r7      ;
    119c:       08 4e           mov     r14,    r8      ;
    119e:       09 4f           mov     r15,    r9      ;
    11a0:       1d 4b 06 00     mov     6(r11), r13     ;
    11a4:       1c 4b 04 00     mov     4(r11), r12     ;
    11a8:       1b 4b 02 00     mov     2(r11), r11     ; <- BUG!
    11ac:       2a 4b           mov     @r11,   r10     ;
        unsigned char a_char = (unsigned char)a;
    11ae:       4f 46           mov.b   r6,     r15     ;
        unsigned char b_char = (unsigned char)b;/*bug*/
/******************************************************************/
As can be seen R11 carries the modified SP and is used to access stack
parameter b. Intermediate registers R10 to R13 are used to store b while R10
will finally carry b_char. While doing this the pointer R11 destroys itself.
I have no workaround for this at the moment.

Note: Function ulltest is invoked with parameter b beeing chosen, that R11
will be overwritten with value 0x89ab at address 0x11a8 (bug-address).
Therefore at address 0x11ac a word read access to an odd address is
performed.

Comment: If it would be possible for the compiler to use SP for accessing
the stack parameter b, this would save unnessecary overhead and would avoid
the bug. No intermediate pointer like the one in R11 is needed. The
following manually typed assembler code could replace the code from address
0x1192 to 0x11ac:
/******************************************************************/
        mov     r12,    r6
        mov     r13,    r7
        mov     r14,    r8
        mov     r15,    r9
        mov     20(r1), r13
        mov     18(r1), r12
        mov     16(r1), r11
        mov     14(r1), r10
/******************************************************************/
------------------------------------


Ralf

Reply via email to