Electronic – From C to Assembly

assemblyavrc

Suppose that we have the following piece of C code for an avr-8bit:

int v1=1;
int v2=2;
v2=v2+v1;

I expected the following disassemble

ldi r18, 1;
ldi r19, 2;
add r19, r18;

but after I ran:

avr-gcc -mmcu=atmega2560 Test.c -o Test.elf

and

avr-objdump -S Test.elf > Test.lss

I got the following disassemble

    ldi r24, 0x01   ; 1
    ldi r25, 0x00   ; 0
    std Y+2, r25    ; 0x02
    std Y+1, r24    ; 0x01
    ldi r24, 0x02   ; 2
    ldi r25, 0x00   ; 0
    std Y+4, r25    ; 0x04
    std Y+3, r24    ; 0x03
    ldd r18, Y+3    ; 0x03
    ldd r19, Y+4    ; 0x04
    ldd r24, Y+1    ; 0x01
    ldd r25, Y+2    ; 0x02
    add r24, r18
    adc r25, r19
    std Y+4, r25    ; 0x04
    std Y+3, r24    ; 0x03

is there anyone that can help me to understand the result of the disassembler?

Edit:
Using char the assembly become:

ldi r24, 0x01
std Y+1, r24
ldi r24, 0x02
std Y+2, r24
ldd r25, Y+2
ldd r24, Y+1
add r24, r25
std Y+2, r24

When is there std instruction?

Best Answer

Short answer: your registers are 8-bit and your values are 16-bit. It's therefore handling them in two pieces.

Long answer:

    ldi r24, 0x01   ; 1
    ldi r25, 0x00   ; 0

Store the 16-bit value 1 in 8-bit registers r24,r25.

    std Y+2, r25    ; 0x02
    std Y+1, r24    ; 0x01

Store it at stack locations Y+1, Y+2.

    ldi r24, 0x02   ; 2
    ldi r25, 0x00   ; 0

Store the 16-bit value 2 in 8-bit registers r24,r25.

    std Y+4, r25    ; 0x04
    std Y+3, r24    ; 0x03

Store it at stack locations Y+3, Y+4.

    ldd r18, Y+3    ; 0x03
    ldd r19, Y+4    ; 0x04
    ldd r24, Y+1    ; 0x01
    ldd r25, Y+2    ; 0x02

Copy them back from the stack to (r18,r19) and (r24,r25)

    add r24, r18
    adc r25, r19

Add (r18,r19) to (r24,r25), including the carry on the second addition

    std Y+4, r25    ; 0x04
    std Y+3, r24    ; 0x03

Store it back on the stack.

To get your original assembly, try two things:

  • use "char" variables
  • use "-O2" compiler option

Edit: the reason the compiler stores variables to the stack rather than keeping them in registers is because they're stored with the default "auto" storage type. It may optimise them into registers but it doesn't have to, even if you declare them with "register" storage class.

While this isn't a strict requirement of the language it's normal compiler behaviour. If at some point you take the address of v1 then it must be assigned a storage location, and saved back there whenever the value of "v1" changes. So to save the bookkeeping of whether or not v1 should be stored in a register or on the stack, it keeps it on the stack and treats each line of code separately.