buserror/simavr

simavr fails to run on ELF, but not on HEX

maxgerhardt opened this issue ยท 5 comments

After making adjustments to the build process as per #378 (comment), I now have a .elf file with the needed ELF section .mmcu, however simavr crashes on it.

Running it unde GDB reveals

>gdb --args simavr -v  C:\Users\Max\temp\simavr_test\.pio\build\uno\firmware.elf
[...]
(gdb) r
Starting program: C:\Users\Max\Desktop\simavr_installed\bin\simavr.exe -v C:\Users\Max\temp\simavr_test\.pio\build\uno\firmware.elf
[New Thread 6544.0x20bc]
[New Thread 6544.0x25e8]
Loaded 1600 .text at address 0x0
Loaded 36 .data
avr_sadly_crashed
GDB: Can not bind socket: No errorwarning: Invalid parameter passed to C runtime function.
[Thread 6544.0x20bc exited with code 0]
[Thread 6544.0x25e8 exited with code 0]
[Inferior 1 (process 6544) exited normally]
(gdb) q

That it ends in avr_sadly_crashed.

simavr has no problem running the hex file created from that ELF file...

>C:\Users\Max\.platformio\packages\toolchain-atmelavr\bin\avr-objcopy.exe -O ihex -R .eeprom firmware.elf firmware.hex
>simavr --mcu atmega328p --freq 16000000 -v  firmware.hex
Loaded 1 section of ihex
Load HEX flash 00000000, 1710
Hello, world!..
Hello, world!..
Hello, world!..

Firmware files are attached.

firmwares.zip

I think that the immediate problem is that a different modification to the build is needed. Try removing the previous changes and adding this line from Makefile.common:

-Wl,--undefined=_mmcu,--section-start=.mmcu=0x910000

The first part stops ld from discarding .mmcu and the second places it at an address meaningless to simavr. Without that, .mmcu is placed between .text and .data, using Flash space. Worse, simavr discards it during loading and then loads .data at the wrong address. Then the startup code copies uninitialised Flash into RAM and things go rapidly downhill.

That might fix the problem, but there is a bigger underlying issue: simavr loads only the .text, .data, .eeprom, .fuse and .lock sections and assumes the first two are contiguous. I think code will fail if any statically allocated C++ objects are defined, introducing .ctor and .dtor sections.

I believe the way to fix this would be to use the Program Header Table for loading, as the ELF specification suggests. It seems the Section Table is intended for linkers. Add a helpful warning if .mmcu is included in Flash.

Note you appear to be using standard GDB. It is not directly compatible with AVR-GDB and cannot interpret ELFs correctly for AVR-style executables. I get all kinds of odd issues if I attempt to use it with SimAVR and atmel ELFs.

I haven't had issues loading ELFs from arduino directly with MK404 (just grabbed 'em from the tmp build dir) so I'm inclined to agree this is related to how the ELF is assembled in your case ๐Ÿ‘

Note you appear to be using standard GDB. It is not directly compatible with AVR-GDB and cannot interpret ELFs correctly for AVR-style executables.

I'm using my host GDB to watch the execution of simavr.exe, which is a x86 executable, not an AVR ELF.

-Wl,--undefined=_mmcu,--section-start=.mmcu=0x910000

Thanks, I'll try these options.

D'oh... sorry. I'll crawl back under my rock now ๐Ÿ˜

-Wl,--undefined=_mmcu,--section-start=.mmcu=0x910000

This absolutely fixes the problem, and I don't even need to leave out the lto flags and related anymore. Doing a platformio.ini config of

[env:uno]
platform = atmelavr
board = uno
framework = arduino
build_flags = -Wl,--undefined=_mmcu,--section-start=.mmcu=0x910000

produces a .elf which now loads correctly!

> simavr -v  C:\Users\Max\temp\simavr_test\.pio\build\uno\firmware.elf
Loaded 1600 .text at address 0x0
Loaded 36 .data
Hello, world!..
Hello, world!..
Hello, world!..

and it even runs nicely, although the Arduino code uses Serial which is a statically allocated and constructed C++ object. Looking back in the elf there is however no separate section for ctors and dtors,

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .data         00000024  00800100  00000640  000006f4  2**0
                  CONTENTS, ALLOC, LOAD, DATA
  1 .mmcu         0000004a  00910000  00910000  00000718  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  2 .text         00000640  00000000  00000000  000000b4  2**1
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  3 .bss          000000a6  00800124  00800124  00000718  2**0
                  ALLOC
  4 .comment      00000011  00000000  00000000  00000762  2**0
                  CONTENTS, READONLY
  5 .note.gnu.avr.deviceinfo 00000040  00000000  00000000  00000774  2**2
                  CONTENTS, READONLY, OCTETS
  6 .debug_aranges 000000a0  00000000  00000000  000007b8  2**3
                  CONTENTS, READONLY, DEBUGGING, OCTETS
  7 .debug_info   0000099b  00000000  00000000  00000858  2**0
                  CONTENTS, READONLY, DEBUGGING, OCTETS
  8 .debug_abbrev 00000606  00000000  00000000  000011f3  2**0
                  CONTENTS, READONLY, DEBUGGING, OCTETS
  9 .debug_line   000002a6  00000000  00000000  000017f9  2**0
                  CONTENTS, READONLY, DEBUGGING, OCTETS
 10 .debug_str    00000208  00000000  00000000  00001a9f  2**0
                  CONTENTS, READONLY, DEBUGGING, OCTETS

so it works just out.

Closing as solved, thanks @gatk555!