This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

MSP430 assembler code vs gdb interface information

Other Parts Discussed in Thread: MSP430G2132

First question here. :)

I have this dumped code from msp430-objdump, the important sections I pasted bellow.

0000f806 <__init_stack>:
    f806:	31 40 80 02 	mov	#640,	r1	;#0x0280

0000f82c <main>:
    f82c:	04 41       	mov	r1,	r4	
    f82e:	24 53       	incd	r4		
    f830:	31 50 fa ff 	add	#-6,	r1	;#0xfffa
    f834:	94 43 f8 ff 	mov	#1,	-8(r4)	;r3 As==01, 0xfff8(r4)
    f838:	a4 43 fa ff 	mov	#2,	-6(r4)	;r3 As==10, 0xfffa(r4)
    f83c:	1f 44 f8 ff 	mov	-8(r4),	r15	;0xfff8(r4)
    f840:	1f 54 fa ff 	add	-6(r4),	r15	;0xfffa(r4)
    f844:	84 4f fc ff 	mov	r15,	-4(r4)	;0xfffc(r4)
    f848:	0f 43       	clr	r15		
    f84a:	31 50 06 00 	add	#6,	r1	;#0x0006

It is a very simple program, just for test of the development flow. What is awkward to me is that when I print the address values

from the variables in the msp430-gdb I get the following:

(gdb) p &a
$5 = (int *) 0x278
(gdb) p &b
$6 = (int *) 0x27a
(gdb) p &c
$7 = (int *) 0x27c
(gdb) 

Taking as example this two lines:

 f834:	94 43 f8 ff 	mov	#1,	-8(r4)	;r3 As==01, 0xfff8(r4)
 f838:	a4 43 fa ff 	mov	#2,	-6(r4)	;r3 As==10, 0xfffa(r4)

We have two mov instructions that are accually loading the constants 1 and 2 into the memory addresses represented

by 0xfff8(r4) and 0xfffa(r4), we know that r4 has the value 0x282 because was first loaded with r1=0x0280 then 

incremented by 2 with incd. But if we add 0xfff8 to 0x0282 we get 0x027A with a carry, which is different from the value

printed in the gdb.

What am I doing wrong here?

  • > add #-6,    sp 

    Should try again without messing around within the stack area, and see what result you get.

    As the code looks useless so what is it you actualy trying to do?
    Did you write the code or is that compiled c code.

     

     

     

  • I wrote a simple c code.

    int main() {
       int a, b, c;
       a = 1;
       b = 2;
       c = a + b;
    }

    I compiled this code with msp430-gcc input -g -O0 -mmcu=msp430g2132 -mdisable-watchdog.

    Then I ran msp430-objdump -d output with the previously generated elf file, to get the assembly code. 

    Inside msp430-gdb, debugging the program, when I run  those commands (p &a.... etc) the returned address isn't maching

    with the address that I calculated from the dumped assembled code.

    I don't know where I'm facing a problem, but pretty sure there is one. 

  • move the int a,b,c; to above main()

    This is what IAR does with the code (had to move INT) 
     
    main:
     001118    4392 0200          mov.w   #0x1,&a
     00111C    43A2 0202          mov.w   #0x2,&b
     001120    421F 0200          mov.w   &a,R15
     001124    521F 0202          add.w   &b,R15
     001128    4F82 0204          mov.w   R15,&c
     00112C    430C               clr.w   R12
     00112E    4130               ret
    

  • Ok this works, but is not the kind of solution I was expecting.

    Can you explain why this error appears? If is an error after all.
  • IAR complained that int c was never used if I put Int declaration inside main{
    So it's the wrong way to code and gcc must been trying to do so using the stack and incorrectly may I say.

  • The assembly code that Rogerio shown in his first posting is using the stack to store variables a, b, and c. Let me try to explain.

    f82c: 04 41 mov r1, r4 ;make a copy of stack pointer in r4
    f82e: 24 53 incd r4 ;add 2 to the copy in r4
    f830: 31 50 fa ff add #-6, r1 ;reserve 6 bytes on top of the stack
    f834: 94 43 f8 ff mov #1, -8(r4) ;r4-8 is pointing to a
    f838: a4 43 fa ff mov #2, -6(r4) ;r4-6 is pointing to b
    f83c: 1f 44 f8 ff mov -8(r4), r15
    f840: 1f 54 fa ff add -6(r4), r15
    f844: 84 4f fc ff mov r15, -4(r4) ;r4-4 is pointing to c
    f848: 0f 43 clr r15
    f84a: 31 50 06 00 add #6, r1 ;release the 6 bytes on top of the stack

    The assembly code is correct but not very efficient. The compiler could have done the equivalent without using r4 and r15.

    sub #6, r1 ;reserve 6 bytes on top of the stack
    mov #1, 0(r1) ;new r1 is pointing to the 2-byte at the top of stack for "a"
    mov #2, 2(r1) ;new r1+2 is pointing to the next 2-byte for "b"
    mov @r1, 4(r1) ;new r1+4 is pointing to the next 2-byte for "c"
    add 2(r1), 4(r1)
    add #6, r1 ;release those 6 bytes on top of the stack

    The assembly code that Tony shown is using fixed locations of RAM to store variables a, b, and c.

    001118 4392 0200 mov.w #0x1,&a
    00111C 43A2 0202 mov.w #0x2,&b
    001120 421F 0200 mov.w &a,R15
    001124 521F 0202 add.w &b,R15
    001128 4F82 0204 mov.w R15,&c
    00112C 430C clr.w R12

    This assembly code is also correct and not very efficient. The compiler could have done the equivalent without using R12 and R15.

    mov.w #0x1,&a
    mov.w #0x2,&b
    mov.w &a,&c
    add.w &b,&c

    Alternatively, one could use registers to store variables a, b, and c. For example, use R12, R13 and R14 respectively.

    mov.w #0x1,R12
    mov.w #0x2,R13
    mov.w R12,R14
    add.w R13,R14

    I understand (but disagree) that the compiler also could have ignored the wishes of the programmer and generate no assembly code for the three assignment statements in the source code. I believe this is called "optimization".
  • gcc also complained about the unused c variable, that is because c is only recieving a value.
    I specifically told gcc to don't use any optimizations, maybe that is the problem, otherwise it could be using registers
    like appointed by old_cow_yellow (nice nickname by the way).

    Thanks anyway.
  • About the correct way to calculate those addresses.

    As I said earlier, we know that r4 has the value 0x282 because it was initialized with r1
    and then incremented. Well this instruction for example:

    f834: 94 43 f8 ff mov #1, -8(r4) ;r3 As==01, 0xfff8(r4)

    The compiler is loading a constant into the memory location (0xfff8 + value(r4)).
    Pretty straightfoward, the only problem is that the msp43-gdb interface is returning a different
    address.

    (gdb) p &a
    $5 = (int *) 0x278

    That address, following the assembly code, should be 0x27a.
    The difference is 2, which is what the incd instruction is doing, adding 2 to r4.
    Why increment 2 in r4? I don't get it
  • I am disappointed that both gcc and IAR cross compilers did not "mov" or "add" memory-to-memory and limit themselves to memory-to-register or register-to-memory. A small difference but could have big impact because this kind of operation is used almost everywhere and almost all the time. These little differences do add up and make the code bigger and slower.
  • In all fairness, C compiler is not gone look for what your future intentions with the INTs are.

    If you in one line state a=1, it's gone do that separate

    you could do c = (a=1) +(b=2)
    And it's the total number of words that counts and not how many lines the asm code use.
    Less words, less code size and faster.
    so if you want to fine-tune you would have to try different way to explain what you want in C
    and look at the complied code to see of it uses less words.
    But as I do 100% asm all the time I don't worry about that and use the msp430 instruction quirks to the max.

     
    main:      // c = (a=1) +(b=2)
     00112E    431F               mov.w   #0x1,R15
     001130    4F82 0200          mov.w   R15,&a
     001134    432E               mov.w   #0x2,R14
     001136    4E82 0202          mov.w   R14,&b
     00113A    5E0F               add.w   R14,R15
     00113C    4F82 0204          mov.w   R15,&c
    
    

  • If you want to be sure that the compiler puts your variable into memory and accesses it exactly as you write, you should declare it static volatile.
    If the variable is not declared static, it is up to the compiler to put it anywhere. The compiler can allocate space for on the stack or hold it in a register, or even discard it if it isn't used.
    Making it static means it has to survive the exit of the function and therefore neither stack nor a CPU register can be used for main storage. The compiler can still copy the content from global memory to a register during the function (and write it back later) if this seems appropriate. Or re-arrange access to it, even discard redundant writes or such.
    Declaring it volatile tells the compiler to perform access to it excactly as often and when the source code accesses it.

    Regarding R4, the MSPGCC uses it as frame pointer. It is the position of the stack pointer at function entry, before allocation of local variable space, storing register or even pushing parameters on the stack.
    It is used used as fixed reference to local variables in case the stack pointer changes during the function course (e.g. backup of status register/GIE bit during multiplications, backup of intermediate results, pushing parameters on the stack for printf or similar functions etc.)

    Analyzing the code, R1 (SP) is set to 0x280, which is the end of ram. I don't know why R4 is incremented, maybe to gain access to the return address (if there were one). Or to prevent it from being optimized away (using 0(sp), 2(sp) and 4(sp) instead)
    However, R1/SP is incremented by 6 to make space for the three variables. Which are now located at 0x27A, 0x27C and 0x27E. Or (as the code correctly uses them) : -8(r4), -6(r4) and -4(r4).
    Tho code works correctly, but I don't know why GDB gives a wrong address.
    When did you ask GDB for the addresses? Since the addresses are not absolute but relative to R4, GDB may give you different results depending on the current value of R4. If you stop before the R4 increment, the calculation does not take it into account.

**Attention** This is a public forum