buserror / simavr

simavr is a lean, mean and hackable AVR simulator for linux & OSX
GNU General Public License v3.0
1.56k stars 365 forks source link

simavr not loading .data correctly when avr_mmcu_vcd_trace_t is present. #307

Open ali1234 opened 5 years ago

ali1234 commented 5 years ago

Test one:

#include <avr/io.h>

unsigned char myvar = 0xab;

void main(void)
{
    PORTB = myvar;
}

Compile and run it in simavr:

avr-gcc -g -mmcu=atmega168 -DF_CPU=16000000UL   -c -o test.o test.c
avr-gcc -g -mmcu=atmega168 -DF_CPU=16000000UL -o test.elf test.o

Check the contents of the data section:

$ avr-objdump -s -j .data test.elf

test.elf:     file format elf32-avr

Contents of section .data:
 800100 ab00                                 ..     

Run it in simavr:

$ run_avr -g -m atmega168 -f 16000000 test.elf
Loaded 182 .text at address 0x0
Loaded 2 .data
avr_gdb_init listening on port 1234

Debug with gdb:

(gdb) target remote :1234
Remote debugging using :1234
0x00000000 in __vectors ()
(gdb) break main
Note: breakpoints 1 and 2 also set at pc 0x9e.
Breakpoint 3 at 0x9e: file test.c, line 7.
(gdb) continue
Continuing.

Breakpoint 1, main () at test.c:7
7       PORTB = myvar;
(gdb) disassemble
Dump of assembler code for function main:
   0x00000096 <+0>: push    r28
   0x00000098 <+2>: push    r29
   0x0000009a <+4>: in  r28, 0x3d   ; 61
   0x0000009c <+6>: in  r29, 0x3e   ; 62
=> 0x0000009e <+8>: ldi r24, 0x25   ; 37
   0x000000a0 <+10>:    ldi r25, 0x00   ; 0
   0x000000a2 <+12>:    lds r18, 0x0100
   0x000000a6 <+16>:    movw    r30, r24
   0x000000a8 <+18>:    st  Z, r18
   0x000000aa <+20>:    nop
   0x000000ac <+22>:    pop r29
   0x000000ae <+24>:    pop r28
   0x000000b0 <+26>:    ret
End of assembler dump.
(gdb) x 0x100
0x800100 <myvar>:   0x000000ab

Test two:

Source code:

#include <avr/io.h>
#include "avr_mcu_section.h"

/* trace struct for simavr */

const struct avr_mmcu_vcd_trace_t _mytrace[]  _MMCU_ = {
    { AVR_MCU_VCD_SYMBOL("B0"), .mask = (1 << 0), .what = (void*)&PORTB, },
    { AVR_MCU_VCD_SYMBOL("B1"), .mask = (1 << 1), .what = (void*)&PORTB, },
    { AVR_MCU_VCD_SYMBOL("B2"), .mask = (1 << 2), .what = (void*)&PORTB, },
    { AVR_MCU_VCD_SYMBOL("B3"), .mask = (1 << 3), .what = (void*)&PORTB, },
    { AVR_MCU_VCD_SYMBOL("B4"), .mask = (1 << 4), .what = (void*)&PORTB, },
    { AVR_MCU_VCD_SYMBOL("B5"), .mask = (1 << 5), .what = (void*)&PORTB, },
    { AVR_MCU_VCD_SYMBOL("B6"), .mask = (1 << 6), .what = (void*)&PORTB, },
    { AVR_MCU_VCD_SYMBOL("B7"), .mask = (1 << 7), .what = (void*)&PORTB, },

};

unsigned char myvar = 0xab;

void main(void)
{
    PORTB = myvar;
}

Compile and run as before. Verify the data section again with objdump to confirm it is the same.

Run it in gdb:

(gdb) target remote :1234
Remote debugging using :1234
0x00000000 in __vectors ()
(gdb) break main
Breakpoint 1 at 0x9e: file test.c, line 24.
(gdb) continue
Continuing.
Note: automatically using hardware breakpoints for read-only addresses.

Breakpoint 1, main () at test.c:24
24      PORTB = myvar;
(gdb) disassemble
Dump of assembler code for function main:
   0x00000096 <+0>: push    r28
   0x00000098 <+2>: push    r29
   0x0000009a <+4>: in  r28, 0x3d   ; 61
   0x0000009c <+6>: in  r29, 0x3e   ; 62
=> 0x0000009e <+8>: ldi r24, 0x25   ; 37
   0x000000a0 <+10>:    ldi r25, 0x00   ; 0
   0x000000a2 <+12>:    lds r18, 0x0100
   0x000000a6 <+16>:    movw    r30, r24
   0x000000a8 <+18>:    st  Z, r18
   0x000000aa <+20>:    nop
   0x000000ac <+22>:    pop r29
   0x000000ae <+24>:    pop r28
   0x000000b0 <+26>:    ret
End of assembler dump.
(gdb) x 0x100
0x800100 <myvar>:   0x0000ffff

Result: myvar is now 0xff instead of 0xab, but the data section has not changed according to objdump.

ali1234 commented 5 years ago

Including the link flags "-Wl,--undefined=_mmcu,--section-start=.mmcu=0x910000" makes this work, but I don't see why it should be necessary given that objdump can find the intact .data section just fine without it.

Matir commented 3 years ago

I realize this is quite old news, but this occurs because of section ordering. It's possible that the .mmcu section appears between .text and .data, but simavr loads .text and .data immediately adjacent to each other. This means the offsets in __do_copy_data (a stub inserted by libgcc) don't match the flash memory map simulated by simavr. Moving the section start address ensures it is not mapped between the two other sections.