avrdudes / avrdude

AVRDUDE is a utility to program AVR microcontrollers
GNU General Public License v2.0
734 stars 136 forks source link

avrdude -U file.elf misses second and following suitable sections in elf segements #1204

Closed stefanrueger closed 1 year ago

stefanrueger commented 1 year ago

Here a zip file morse.zip with an .elf file and the corresponding .hex file for the 16 MHz ATmega328p Uno/ProMini with a LED at B5; it prints Bonjour le monde from .data (57600 baud on USART) then morses this text via the LED; then prints Hello, world from user-defined flash section .progdata and morses this text via the LED.

Uploading morse.elf behaves differently from uploading morse.hex:

$ avrdude -qqU morse.hex && echo OK
OK
$ echo d fl 0x3e0 64| avrdude -qqt
avrdude> d fl 0x3e0 64
03e0  0d 92 41 50 50 40 d8 f7  08 95 f8 94 ff cf 48 65  | .APP@........He|
03f0  6c 6c 6f 2c 20 77 6f 72  6c 64 0a 00 42 6f 6e 6a  |llo, world .Bonj|
0400  6f 75 72 20 6c 65 20 6d  6f 6e 64 65 0a 00 ff ff  |our le monde ...|
0410  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|

$ avrdude -qqU morse.elf && echo OK
OK
$ echo d fl 0x3e0 64| avrdude -qqt
avrdude> d fl 0x3e0 64
03e0  0d 92 41 50 50 40 d8 f7  08 95 f8 94 ff cf ff ff  | .APP@..........|
03f0  ff ff ff ff ff ff ff ff  ff ff ff ff 42 6f 6e 6a  |............Bonj|
0400  6f 75 72 20 6c 65 20 6d  6f 6e 64 65 0a 00 ff ff  |our le monde ...|
0410  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|

Notice the missing "Hello, world" text.

The upload of the avrdude.elf file fails to incorporate the user-defined flash section .progdata, see Section Nr 3 in the following printout:

$ avr-readelf -S morse.elf 
There are 14 section headers, starting at offset 0x1ee4:

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .data             PROGBITS        00800100 000490 000012 00  WA  0   0  1
  [ 2] .text             PROGBITS        00000000 000094 0003ee 00  AX  0   0  2
  [ 3] .progdata         PROGBITS        000003ee 000482 00000e 00   A  0   0  1
  [ 4] .bss              NOBITS          00800112 0004a2 000064 00  WA  0   0  1
  [ 5] .comment          PROGBITS        00000000 0004a2 000011 01  MS  0   0  1
  [ 6] .note.gnu.avr.dev NOTE            00000000 0004b4 000040 00      0   0  4
  [ 7] .debug_info       PROGBITS        00000000 0004f4 0005f4 00      0   0  1
  [ 8] .debug_abbrev     PROGBITS        00000000 000ae8 0005a2 00      0   0  1
  [ 9] .debug_line       PROGBITS        00000000 00108a 00001a 00      0   0  1
  [10] .debug_str        PROGBITS        00000000 0010a4 000208 00      0   0  1
  [11] .shstrtab         STRTAB          00000000 001e58 000089 00      0   0  1
  [12] .symtab           SYMTAB          00000000 0012ac 0006d0 10     13  45  4
  [13] .strtab           STRTAB          00000000 00197c 0004dc 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings)
  I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
  O (extra OS processing required) o (OS specific), p (processor specific)

The expected behaviour of -U morse.elf should be the same as -U morse.hex, which is generated by

$ avr-objcopy -O ihex -R .eeprom morse.elf morse.hex

Only standard avr-toolchain operations were used; the user-defined flash section was generated in the C source using

const uint8_t two[] __attribute__((section (".progdata"))) = {
   'H', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '\n', 0 
};
dl8dtl commented 1 year ago

I'm not so sure whether this is a pilot error or not. ELF files can contain any arbitrary sections. Anyone can define more sections in their setup as they like. The -R .eeprom in the objcopy command says: "Copy all loadable sections except the one named .eeprom".

the user-defined flash section

That's it: it is user defined. It got an arbitrary name defined by the user.

It cannot be easily deduced whether the user wants an arbitrary name to got into flash, EEPROM, or maybe even into any outside storage device (like an SPI-attached flash).

I'm all for adding some kind of knob to tune the decision what is to be considered "flash" contents, but I don't agree that the (gratuitous) definition "anything not named .eeprom is flash" is the generally correct behaviour.

dl8dtl commented 1 year ago

Btw., the normal way to handle this situation is that the linker script categorizes the various input sections into a few output sections, for flash (also includes SRAM initialization data), eeprom, and sram. That's the way the standard linker script handle it for the various flash subsections (vector table, progmem constant data, program code, static RAM initialization data).

The more I think about it, the more it looks like a pilot error on the project to me. Someone invented an arbitrary section, but did not keep up the remaining parts of the toolchain to deal with it.

mcuee commented 1 year ago

So I just did a quick Google search and found a simple article here. https://scienceprog.com/control-memory-sections-using-avr-gcc/

So we need to use linker opton to make sure the .progdata section is located in the Flash.

-Wl,--section-start=.progdata=0x03ee
stefanrueger commented 1 year ago

@dl8dtl Well, something in the avr-toolchain does exatly that! I haven't dreamt that up, and certainly not created my .hex file myself. So someone, who cobbled together the Makefiles for creating a .hex for that avr-toolchain has made that decision that, indeed, anything not named .eeprom should go into hex.

It cannot be easily deduced whether the user wants an arbitrary name to got into flash, EEPROM, or maybe even into any outside storage device (like an SPI-attached flash).

I notice that .eeprom also resides in a different address interval at 0x00810000 according to avr-readelf -S , so maybe the avr-toolchain uses the address range to make that distinction? Guessing here.

$ avr-readelf -S build-uno/morse.elf 
There are 15 section headers, starting at offset 0x1f54:

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .data             PROGBITS        00800100 0004b0 000012 00  WA  0   0  1
  [ 2] .text             PROGBITS        00000000 0000b4 0003ee 00  AX  0   0  2
  [ 3] .progdata         PROGBITS        000003ee 0004a2 00000e 00   A  0   0  1
  [ 4] .bss              NOBITS          00800112 0004c2 000064 00  WA  0   0  1
  [ 5] .eeprom           PROGBITS        00810000 0004c2 000020 00  WA  0   0  1
  [ 6] .comment          PROGBITS        00000000 0004e2 000011 01  MS  0   0  1
  [ 7] .note.gnu.avr.dev NOTE            00000000 0004f4 000040 00      0   0  4
  [ 8] .debug_info       PROGBITS        00000000 000534 0005f4 00      0   0  1
  [ 9] .debug_abbrev     PROGBITS        00000000 000b28 0005a2 00      0   0  1
  [10] .debug_line       PROGBITS        00000000 0010ca 00001a 00      0   0  1
  [11] .debug_str        PROGBITS        00000000 0010e4 000208 00      0   0  1
  [12] .shstrtab         STRTAB          00000000 001ec1 000091 00      0   0  1
  [13] .symtab           SYMTAB          00000000 0012ec 0006f0 10     14  46  4
  [14] .strtab           STRTAB          00000000 0019dc 0004e5 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings)
  I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
  O (extra OS processing required) o (OS specific), p (processor specific)

-Wl,--section-start=.progdata=0x03ee

@mcuee If I explicitly use that linker option, avr-readelf gives me exactly the same output for the .progdata section. So, I am assuming that is what the toolchain has implicitly decided to do?

all for adding some kind of knob to tune the decision what is to be considered "flash" contents

And what could that be? Address ranges? Name conventions? What the toolchain does?

stefanrueger commented 1 year ago

So with the surprises-the-user hat on it is surprising that avrdude -U flash:w:file.elf:e should behave differently from avrdude -U flash:w:file.hex:i as both are spit out by the same toolchain.

stefanrueger commented 1 year ago

I'm not so sure whether this is a pilot error or not.

And if this is a pilot error as you suspect, what would the correct command be to create the .hex from the .elf?

stefanrueger commented 1 year ago

I notice that .eeprom also resides in a different address interval at 0x00810000 according to avr-readelf -S , so maybe the avr-toolchain uses the address range to make that distinction? Guessing here.

The article above that @mcuee found confirms my guess: They write

The memory space “seen” by AVRGCC runs from addresses:

0x00000000 up to 0x0007FFFF for Flash memory,
0x00800000 up to 0x0080FFFF for RAM, and
0x00810000 up to 0x0081FFFF for EEPROM.

So, looking at the output of avr-readelf the section .progdata must reside in flash. And AVRDUDE is wrong not to do so.

stefanrueger commented 1 year ago

Someone invented an arbitrary section

Just to be clear, if it isn't from my description before, the .progdata name comes from my very own source code:

const uint8_t two[] __attribute__((section (".progdata"))) = {
   'H', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '\n', 0 
};

I could have chosen the name .arewenothavingfuntoday and apart from cutting off the name in the avr-readelf output

  [ 3] .arewenothavingfu PROGBITS        000003ee 0004a2 00000e 00   A  0   0  1

the result is the same. I assume the compiler saw the global variable const uint8_t two[] with the section name, packed it into flash (because const) and gave it its own section, so linker scripts can reason about that. All looks sane to me.

stefanrueger commented 1 year ago

So key observation is that it's not the arbitrary user name that matters here but the (correct) compiler decision that the global const variable needs to reside in flash, which is what the compiler/linker indicates by putting it into the address range [0, 0x 7ffff]. The name is secondary but it gets its own section b/c the user asked for that. The toolchain quite rightly puts that into the .elf and the .hex. And AVRDUDE should respect that, too.

mcuee commented 1 year ago

So key observation is that it's not the arbitrary user name that matters here but the (correct) compiler decision that the global const variable needs to reside in flash, which is what the compiler/linker indicates by putting it into the address range [0, 0x 7ffff]. The name is secondary but it gets its own section b/c the user asked for that. The toolchain quite rightly puts that into the .elf and the .hex. And AVRDUDE should respect that, too.

Good summary.

So from my quick read (I know very little of avr-gcc toolchain), avr-gcc toolchain is correct, avr-objcopy correctly understand that .progdata is located in Flash (address range is within Flash are) and generate the correct hex file.

The issue here is that avrdude seems to only include .text section and .data section when programming flash.

From here: https://github.com/avrdudes/avrdude/pull/1195#issuecomment-1331020497

This already works in the existing code, but there is no check for sections, as a result, data from other sectors, not .text and not .data, will be written immediately after them to flash.

@dl8dtl Is this because of avr-libc? https://www.nongnu.org/avr-libc/user-manual/mem_sections.html

mcuee commented 1 year ago

-Wl,--section-start=.progdata=0x03ee

@mcuee If I explicitly use that linker option, avr-readelf gives me exactly the same output for the .progdata section. So, I am assuming that is what the toolchain has implicitly decided to do?

Since I do not have the source codes of the morse project, I am trying to reproduce this issue using Arduino IDE and I do not see the following two in the hex file or elf file.

uint8_t one[] = {
  'B', 'o', 'n', 'j', 'o', 'u', 'r', ' ', 'l', 'e', ' ', 'm', 'o', 'n', 'd', 'e', '\n', 0 
};

const uint8_t two[] __attribute__((section (".progdata"))) = {
   'H', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '\n', 0 
};
dl8dtl commented 1 year ago

Just to be clear, if it isn't from my description before, the .progdata name comes from my very own source code:

Exactly. That's why it is also your responsibility to handle it in the linker script if you invent sections by your own.

If you had named it .progmem (as anyone else is doing, and avr-libc has support macros for), the default linker script would already do it for you.

avr-objcopy correctly understand that .progdata is located in Flash

No, avr-objcopy doesn't know anything about flash or anything else like that. It's just the user who called avr-objcopy with the -R .eeprom argument who told it to include all loaded sections except .eeprom.

dl8dtl commented 1 year ago

Btw., I suspect that this avr-objcopy -R .eeprom inadvertently gets your .hex file two copies of the .data section. The default linkerscript knows that one copy of .data needs to go into the flash (from where the startup code can pick it up at initialization time). But then, the objcopy copying everything but .eeprom will pull a second copy of it.

mcuee commented 1 year ago

@dl8dtl and @stefanrueger

I can reproduce what @stefanrueger gets.

Base blinking program using avr-gcc. https://github.com/tderflinger/arduino-blink-purec

My simple patch:

$ git diff
diff --git a/Makefile b/Makefile
index 7dd1853..11240f8 100644
--- a/Makefile
+++ b/Makefile
@@ -5,10 +5,10 @@ ARDUINO_USB ?= /dev/ttyUSB0

 all: led.hex

-led.hex: led
-       avr-objcopy -O ihex -R .eeprom led led.hex
+led.hex: led.elf
+       avr-objcopy -O ihex -R .eeprom led.elf led.hex

-led: led.o
+led.elf: led.o
        avr-gcc $(LDFLAGS) -o $@ $^

 led.o: led.c
@@ -18,6 +18,6 @@ deploy: led.hex
        avrdude -F -V -c arduino -p ATMEGA328p -P ${ARDUINO_USB} -b 115200 -U flash:w:led.hex

 clean: FRC
-       rm -f led.elf led.hex led.o led
+       rm -f led.elf led.hex led.o

-FRC:
\ No newline at end of file
+FRC:
diff --git a/led.c b/led.c
index 6c476ad..bd4b43d 100644
--- a/led.c
+++ b/led.c
@@ -1,10 +1,18 @@
 #include <avr/io.h>

 #define F_CPU 16000000
-#define BLINK_DELAY_MS 5000
+#define BLINK_DELAY_MS 500

 #include <util/delay.h>

+uint8_t one[] = {
+  'B', 'o', 'n', 'j', 'o', 'u', 'r', ' ', 'l', 'e', ' ', 'm', 'o', 'n', 'd', 'e', '\n', 0
+};
+
+const uint8_t two[] __attribute__((section (".progdata"))) = {
+   'H', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '\n', 0
+};
+
 int main (void)
 {
   // Arduino digital pin 13 (pin 5 of PORTB) for output
@@ -19,4 +27,4 @@ int main (void)
     PORTB &= ~ 0B100000; // PORTB5
     _delay_ms(BLINK_DELAY_MS);
   }
-}
\ No newline at end of file
+}

Results.

$ make
avr-gcc -Os -DF_APU=16000000UL -mmcu=atmega328p -c -o led.o led.c
avr-gcc -mmcu=atmega328p -o led.elf led.o
avr-objcopy -O ihex -R .eeprom led.elf led.hex

$ avr-readelf -S led.elf
There are 13 section headers, starting at offset 0x22ec:

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .data             PROGBITS        00800100 000148 000012 00  WA  0   0  1
  [ 2] .text             PROGBITS        00000000 000074 0000c6 00  AX  0   0  2
  [ 3] .progdata         PROGBITS        000000c6 00013a 00000e 00   A  0   0  1
  [ 4] .comment          PROGBITS        00000000 00015a 000011 01  MS  0   0  1
  [ 5] .note.gnu.av[...] NOTE            00000000 00016c 000040 00      0   0  4
  [ 6] .debug_info       PROGBITS        00000000 0001ac 0005f4 00      0   0  1
  [ 7] .debug_abbrev     PROGBITS        00000000 0007a0 0005a2 00      0   0  1
  [ 8] .debug_line       PROGBITS        00000000 000d42 00001d 00      0   0  1
  [ 9] .debug_str        PROGBITS        00000000 000d5f 000208 00      0   0  1
  [10] .symtab           SYMTAB          00000000 000f68 000bf0 10     11 133  4
  [11] .strtab           STRTAB          00000000 001b58 00070f 00      0   0  1
  [12] .shstrtab         STRTAB          00000000 002267 000084 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  L (link order), O (extra OS processing required), G (group), T (TLS),
  C (compressed), x (unknown), o (OS specific), E (exclude),
  D (mbind), p (processor specific)

$ avrdude -c usbasp -p m328p -U ./led.elf -q

avrdude: AVR device initialized and ready to accept instructions
avrdude: device signature = 0x1e950f (probably m328p)
avrdude: Note: flash memory has been specified, an erase cycle will be performed.
         To disable this feature, specify the -D option.
avrdude: erasing chip
avrdude: reading input file ./led.elf for flash
         with 216 bytes in 2 sections within [0, 0xe5]
         using 2 pages and 40 pad bytes
avrdude: writing 216 bytes flash ...
avrdude: 216 bytes of flash written
avrdude: verifying flash memory against ./led.elf
avrdude: 216 bytes of flash verified

avrdude done.  Thank you.

$ avrdude -c usbasp -p m328p -qqt
avrdude> dump flash
>>> dump flash
0000  0c 94 34 00 0c 94 49 00  0c 94 49 00 0c 94 49 00  | .4. .I. .I. .I.|
0010  0c 94 49 00 0c 94 49 00  0c 94 49 00 0c 94 49 00  | .I. .I. .I. .I.|
0020  0c 94 49 00 0c 94 49 00  0c 94 49 00 0c 94 49 00  | .I. .I. .I. .I.|
0030  0c 94 49 00 0c 94 49 00  0c 94 49 00 0c 94 49 00  | .I. .I. .I. .I.|
0040  0c 94 49 00 0c 94 49 00  0c 94 49 00 0c 94 49 00  | .I. .I. .I. .I.|
0050  0c 94 49 00 0c 94 49 00  0c 94 49 00 0c 94 49 00  | .I. .I. .I. .I.|
0060  0c 94 49 00 0c 94 49 00  11 24 1f be cf ef d8 e0  | .I. .I..$......|
0070  de bf cd bf 11 e0 a0 e0  b1 e0 e4 ed f0 e0 02 c0  |................|
0080  05 90 0d 92 a2 31 b1 07  d9 f7 0e 94 4b 00 0c 94  |.. ..1......K. .|
0090  61 00 0c 94 00 00 25 9a  2d 9a 2f ef 89 e6 98 e1  |a. ...%.-./.....|
00a0  21 50 80 40 90 40 e1 f7  00 c0 00 00 2d 98 2f ef  |!P.@.@......-./.|
00b0  89 e6 98 e1 21 50 80 40  90 40 e1 f7 00 c0 00 00  |....!P.@.@......|
00c0  eb cf f8 94 ff cf ff ff  ff ff ff ff ff ff ff ff  |................|
00d0  ff ff ff ff 42 6f 6e 6a  6f 75 72 20 6c 65 20 6d  |....Bonjour le m|
00e0  6f 6e 64 65 0a 00 ff ff  ff ff ff ff ff ff ff ff  |onde ...........|
00f0  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|

avrdude> quit
>>> quit
avrdude>
mcuee commented 1 year ago

Btw., I suspect that this avr-objcopy -R .eeprom inadvertently gets your .hex file two copies of the .data section. The default linkerscript knows that one copy of .data needs to go into the flash (from where the startup code can pick it up at initialization time). But then, the objcopy copying everything but .eeprom will pull a second copy of it.

Actually not true. I have removed -R .eeprom from the Makefile and it is still the same.

$ make clean
rm -f led.elf led.hex led.o

$ make
avr-gcc -Os -DF_APU=16000000UL -mmcu=atmega328p -c -o led.o led.c
avr-gcc -mmcu=atmega328p -o led.elf led.o
avr-objcopy -O ihex led.elf led.hex

xiaof@LAPTOP-913SIMUD MINGW64 /c/work/avr/avrdude_test/arduino-blink-purec
$ avr-readelf -S led.elf
There are 13 section headers, starting at offset 0x22ec:

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .data             PROGBITS        00800100 000148 000012 00  WA  0   0  1
  [ 2] .text             PROGBITS        00000000 000074 0000c6 00  AX  0   0  2
  [ 3] .progdata         PROGBITS        000000c6 00013a 00000e 00   A  0   0  1
  [ 4] .comment          PROGBITS        00000000 00015a 000011 01  MS  0   0  1
  [ 5] .note.gnu.av[...] NOTE            00000000 00016c 000040 00      0   0  4
  [ 6] .debug_info       PROGBITS        00000000 0001ac 0005f4 00      0   0  1
  [ 7] .debug_abbrev     PROGBITS        00000000 0007a0 0005a2 00      0   0  1
  [ 8] .debug_line       PROGBITS        00000000 000d42 00001d 00      0   0  1
  [ 9] .debug_str        PROGBITS        00000000 000d5f 000208 00      0   0  1
  [10] .symtab           SYMTAB          00000000 000f68 000bf0 10     11 133  4
  [11] .strtab           STRTAB          00000000 001b58 00070f 00      0   0  1
  [12] .shstrtab         STRTAB          00000000 002267 000084 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  L (link order), O (extra OS processing required), G (group), T (TLS),
  C (compressed), x (unknown), o (OS specific), E (exclude),
  D (mbind), p (processor specific)

$ avrdude -c usbasp -p m328p -U ./led.hex -q

avrdude: AVR device initialized and ready to accept instructions
avrdude: device signature = 0x1e950f (probably m328p)
avrdude: Note: flash memory has been specified, an erase cycle will be performed.
         To disable this feature, specify the -D option.
avrdude: erasing chip
avrdude: reading input file ./led.hex for flash
         with 230 bytes in 1 section within [0, 0xe5]
         using 2 pages and 26 pad bytes
avrdude: writing 230 bytes flash ...
avrdude: 230 bytes of flash written
avrdude: verifying flash memory against ./led.hex
avrdude: 230 bytes of flash verified

avrdude done.  Thank you.

$ avrdude -c usbasp -p m328p -qqt
avrdude> dump flash
>>> dump flash
0000  0c 94 34 00 0c 94 49 00  0c 94 49 00 0c 94 49 00  | .4. .I. .I. .I.|
0010  0c 94 49 00 0c 94 49 00  0c 94 49 00 0c 94 49 00  | .I. .I. .I. .I.|
0020  0c 94 49 00 0c 94 49 00  0c 94 49 00 0c 94 49 00  | .I. .I. .I. .I.|
0030  0c 94 49 00 0c 94 49 00  0c 94 49 00 0c 94 49 00  | .I. .I. .I. .I.|
0040  0c 94 49 00 0c 94 49 00  0c 94 49 00 0c 94 49 00  | .I. .I. .I. .I.|
0050  0c 94 49 00 0c 94 49 00  0c 94 49 00 0c 94 49 00  | .I. .I. .I. .I.|
0060  0c 94 49 00 0c 94 49 00  11 24 1f be cf ef d8 e0  | .I. .I..$......|
0070  de bf cd bf 11 e0 a0 e0  b1 e0 e4 ed f0 e0 02 c0  |................|
0080  05 90 0d 92 a2 31 b1 07  d9 f7 0e 94 4b 00 0c 94  |.. ..1......K. .|
0090  61 00 0c 94 00 00 25 9a  2d 9a 2f ef 89 e6 98 e1  |a. ...%.-./.....|
00a0  21 50 80 40 90 40 e1 f7  00 c0 00 00 2d 98 2f ef  |!P.@.@......-./.|
00b0  89 e6 98 e1 21 50 80 40  90 40 e1 f7 00 c0 00 00  |....!P.@.@......|
00c0  eb cf f8 94 ff cf 48 65  6c 6c 6f 2c 20 77 6f 72  |......Hello, wor|
00d0  6c 64 0a 00 42 6f 6e 6a  6f 75 72 20 6c 65 20 6d  |ld .Bonjour le m|
00e0  6f 6e 64 65 0a 00 ff ff  ff ff ff ff ff ff ff ff  |onde ...........|
00f0  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|

avrdude> quit
>>> quit
avrdude>

$ avrdude -c usbasp -p m328p -U ./led.elf -q

avrdude: AVR device initialized and ready to accept instructions
avrdude: device signature = 0x1e950f (probably m328p)
avrdude: Note: flash memory has been specified, an erase cycle will be performed.
         To disable this feature, specify the -D option.
avrdude: erasing chip
avrdude: reading input file ./led.elf for flash
         with 216 bytes in 2 sections within [0, 0xe5]
         using 2 pages and 40 pad bytes
avrdude: writing 216 bytes flash ...
avrdude: 216 bytes of flash written
avrdude: verifying flash memory against ./led.elf
avrdude: 216 bytes of flash verified

avrdude done.  Thank you.

$ avrdude -c usbasp -p m328p -qqt
avrdude> dump flash
>>> dump flash
0000  0c 94 34 00 0c 94 49 00  0c 94 49 00 0c 94 49 00  | .4. .I. .I. .I.|
0010  0c 94 49 00 0c 94 49 00  0c 94 49 00 0c 94 49 00  | .I. .I. .I. .I.|
0020  0c 94 49 00 0c 94 49 00  0c 94 49 00 0c 94 49 00  | .I. .I. .I. .I.|
0030  0c 94 49 00 0c 94 49 00  0c 94 49 00 0c 94 49 00  | .I. .I. .I. .I.|
0040  0c 94 49 00 0c 94 49 00  0c 94 49 00 0c 94 49 00  | .I. .I. .I. .I.|
0050  0c 94 49 00 0c 94 49 00  0c 94 49 00 0c 94 49 00  | .I. .I. .I. .I.|
0060  0c 94 49 00 0c 94 49 00  11 24 1f be cf ef d8 e0  | .I. .I..$......|
0070  de bf cd bf 11 e0 a0 e0  b1 e0 e4 ed f0 e0 02 c0  |................|
0080  05 90 0d 92 a2 31 b1 07  d9 f7 0e 94 4b 00 0c 94  |.. ..1......K. .|
0090  61 00 0c 94 00 00 25 9a  2d 9a 2f ef 89 e6 98 e1  |a. ...%.-./.....|
00a0  21 50 80 40 90 40 e1 f7  00 c0 00 00 2d 98 2f ef  |!P.@.@......-./.|
00b0  89 e6 98 e1 21 50 80 40  90 40 e1 f7 00 c0 00 00  |....!P.@.@......|
00c0  eb cf f8 94 ff cf ff ff  ff ff ff ff ff ff ff ff  |................|
00d0  ff ff ff ff 42 6f 6e 6a  6f 75 72 20 6c 65 20 6d  |....Bonjour le m|
00e0  6f 6e 64 65 0a 00 ff ff  ff ff ff ff ff ff ff ff  |onde ...........|
00f0  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|

avrdude> quit
>>> quit
avrdude>
mcuee commented 1 year ago

If you had named it .progmem (as anyone else is doing, and avr-libc has support macros for), the default linker script would already do it for you.

@dl8dtl

That does not seem to help in my testing, no matter what I called that section, .progmem, progmem and PROGMEM. Does this mean my avr-gcc (from MSYS2) is broken?

$ avr-gcc -v
Using built-in specs.
Reading specs from c:/msys64/mingw64/bin/../lib/gcc/avr/8.5.0/device-specs/specs-avr2
COLLECT_GCC=C:\msys64\mingw64\bin\avr-gcc.exe
COLLECT_LTO_WRAPPER=c:/msys64/mingw64/bin/../libexec/gcc/avr/8.5.0/lto-wrapper.exe
Target: avr
Configured with: ../gcc-8.5.0/configure --build=x86_64-w64-mingw32 --prefix=/mingw64 --target=avr --enable-languages=c,c++ --disable-nls --disable-libssp --disable-shared --disable-threads --disable-libgomp --disable-libada --with-dwarf2 --enable-mingw-wildcard
Thread model: single
gcc version 8.5.0 (GCC)
dl8dtl commented 1 year ago

I have removed -R .eeprom from the Makefile and it is still the same.

Sure, you don't have EEPROM initialization data anyway in that project. ;-) But OK, it's indeed there only once, my assumption was wrong.

no matter what I called that section, .progmem, progmem and PROGMEM

Well, the normal AVR way is to use __attribute__((__progmem__)). This is what the <avr/pgmspace.h> macros are using. I looked into the generated assembly, that eventually translates into a section name .progmem.data. If you use that in your example, everything "magically" works: there is no longer a section by that name in the resulting ELF file, everything gets integrated into the .text section.

That's the way how it is supposed to work. Anything deviating from that default scheme needs to provide a custom linker script that deals with the self-declared sections, taking care of properly transferring all flash data to the output section .text.

stefanrueger commented 1 year ago

That's why it is also your responsibility to handle it in the linker script if you invent sections by your own.

Well, the avr-gcc compiler, linker and/or default linker scripts seem to disagree with you @dl8dtl! They automagically do the right thing and squeeze the .progdata section between .text and .data. I suspect it is because the avr compiler saw a global variable with a const modifier, and therefore decided it must be put in flash and told the linker so.

I want the .progdata section in high flash. Had the compiler/linker not done that out of their own volition, I would have gone to the trouble learning about linker scripts making sure that .progdata is moved into high flash. Either way, (with or without my responsibility) it ended up in the right address space [0, 0x7ffff].

avr-objcopy -R .eeprom inadvertently gets your .hex file two copies of the .data section

It does not. I checked: .data is there only once (count the 'Bonjour`s in the .hex); have a look yourself: morse.zip; I used the avr-toolchain 5.4.0. Or try it yourself with your favourite avr-toolchain. Would be interesting to see what you get!

If you had named it .progmem (as anyone else is doing, and avr-libc has support macros for)

.progmem does the wrong thing for me: it puts the data into low flash. I need them in high flash after .text.

It is useful to store certain data at the top of a large flash memory, particularly when PROGMEM data threaten to flow beyond the bottom 64 kB space. In this case PROGMEM data are not guaranteed to be reachable by *_P() functions. Not all *_P() functions have a *_PF() equivalent (that reaches beyond 64 kB) in the avr-libc library. Hence, it makes sense to put all those data at the top of the sketch that only need be processed by *_PF() functions. This leaves (more of) the remaining PROGMEM data in reach of *_P() functions.

Alternatively, could have used __attribute__((section (".text"))) but then my data would be word-aligned, which can result in unwanted pad bytes (I may be known for many things but certainly not for gratuitous waste of flash :)

Summarising, everyone seems to think the little .progdata section belongs in flash: the compiler, the linker (positioning it between .text and .data), perhaps even the default linker script, the generated .elf file (asserted through address space [0, 0x7ffff]), the .hex file, the avr- set. Well, everyone except AVRDUDE that is.

dl8dtl commented 1 year ago

Well, no. The compiler doesn't know anything about your .progdata details at all. It just copies the section over into the output file, and depending on the section order, objcopy copies it from there into the hex file. This might or might not be the correct place … You could name your section .foobar, and it will go into the output file as well.

Btw., the reason the default .progmem.data section is located as low as possible is that the LPM instruction can only handle data within the first 64 KiB of flash. The difference is, for 128 KiB devices, all instructions can automatically handle everything up to 128 KiB (since the PC addresses in 16-bit words), but LPM addresses byte addressed data, and is thus restricted on the lower half of that flash. (For devices beyond 128 KiB, things get worse though, and for devices with at most 64 KiB, it doesn't matter at all.)

If you want your flash data go on top of the normal instructions, call the section .progmemx.data. That one is correctly handled by the default linker script.

dl8dtl commented 1 year ago

Note that <avr/pgmspace.h> also offers macros to access flash data beyond 64 KiB, but it's getting more cumbersome then.

stefanrueger commented 1 year ago

[must use] custom linker script

The produced .elf does not know whether a custom linker script was used. Neither does AVRDUDE. I think the .elf file is correct. And still think AVRDUDE is wrong when it interprets the elf. @dl8dtl Tell me what is wrong with the .elf. Which bit in the data is wrong? The sections don't overlap. The .progdata section is of type PROGBITS. It is in the flash region [0, 0x7ffff]. It has the ALLOC attribute set. What more could a custom linker script have done?

top of the normal instructions, call the section .progmemx.data

Alas, that doesn't seem to work in my avr-toolchain 5.4.0: puts the data below the instructions (like PROGMEM) and is probably word aligned (bad).

stefanrueger commented 1 year ago

<avr/pgmspace.h> also offers macros to access flash data beyond 64 KiB

I know. The problem is that avr-libc has asymmetric support of beyond 64 kB data. Le me repeat my above use case (please read it this time): It is useful to store certain data at the top of a large flash memory, particularly when PROGMEM data threaten to flow beyond the bottom 64 kB space. In this case PROGMEM data are not guaranteed to be reachable by _P() functions. Not all _P() functions have a _PF() equivalent (that reaches beyond 64 kB) in the avr-libc library. Hence, it makes sense to put all those data at the top of the sketch that only need be processed by _PF() functions. This leaves (more of) the remaining PROGMEM data in reach of *_P() functions.

dl8dtl commented 1 year ago

Well, then your toolchain is too old.

Btw. before AVRDUDE could handle ELF files at all, the recommended way to produce the hex file was avr-objcopy -i .text -i .data. With that, your example would lose as well. Just kicking out the EEPROM section is basically a poor abuse only. This gets immediately obvious if your program code also contains initialization values for fuses (<avr/fuse.h>). -R .eeprom would also copy them to flash as well. Certainly, it's just a few bytes, but would you consider that technically correct then?

Your entire example does not work by design but only by incident (since the default of the linker is to just copy all unprocessed input section to output sections, and since that poorly designed objcopy just copies everything it finds to the output file).

The problem is that avr-libc has asymmetric support of beyond 64 kB data.

No, the AVR itself has asymmetric support for it. LPM can only handle 64 KiB, even though the PC on 128 KiB devices can handle more. avr-libc can only work on top of these instructions.

It is useful to store certain data at the top of a large flash memory,

That's the reason why the toolchain was then taught to handle .progmemx.*.

I did design the ELF file handling in AVRDUDE many years ago, and I designed it in a way to match the remaining toolchain elements. I refuse to consider this a bug, sorry.

dl8dtl commented 1 year ago

Regarding missing _PF functions in avr-libc: I could accept that as an enhancement request though. ;-)

mcuee commented 1 year ago

__attribute__((__progmem__))

This does work.

mcuee@UbuntuSwift3:~/build/avr/arduino-blink-purec$ cat led.c
#include <avr/io.h>

#define F_CPU 16000000
#define BLINK_DELAY_MS 500

#include <util/delay.h>

#define _EEMEM  __attribute__((__used__, __section__ (".eeprom")))
#define _EEPROM uint8_t __eeprom[32] _EEMEM
_EEPROM = { "Hello World!" };

FUSES = { 0xF7, 0xD6, 0xFD }; // lfuse, hfuse, efuse

const uint8_t one[] __attribute__((__progmem__)) = {
  'B', 'o', 'n', 'j', 'o', 'u', 'r', ' ', 'l', 'e', ' ', 'm', 'o', 'n', 'd', 'e', '\n', 0 };

const uint8_t two[] __attribute__((__progmem__)) = {
   'H', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '\n', 0 };

int main (void)
{
  // Arduino digital pin 13 (pin 5 of PORTB) for output
  DDRB |= 0B100000; // PORTB5

  while(1) {
    // turn LED on
    PORTB |= 0B100000; // PORTB5
    _delay_ms(BLINK_DELAY_MS);

    // turn LED off
    PORTB &= ~ 0B100000; // PORTB5
    _delay_ms(BLINK_DELAY_MS);
  }
}

mcuee@UbuntuSwift3:~/build/avr/arduino-blink-purec$ make clean
rm -f led.elf led.hex led.o led
mcuee@UbuntuSwift3:~/build/avr/arduino-blink-purec$ make
avr-gcc -Os -DF_APU=16000000UL -mmcu=atmega328p -c -o led.o led.c
avr-gcc -mmcu=atmega328p -o led.elf led.o
avr-objcopy -O ihex -R .eeprom led.elf led.hex
mcuee@UbuntuSwift3:~/build/avr/arduino-blink-purec$ avrdude -c usbasp -p m328p -U led.elf

avrdude: AVR device initialized and ready to accept instructions
avrdude: device signature = 0x1e950f (probably m328p)
avrdude: Note: flash memory has been specified, an erase cycle will be performed.
         To disable this feature, specify the -D option.
avrdude: erasing chip
avrdude: reading input file led.elf for flash
         with 208 bytes in 1 section within [0, 0xcf]
         using 2 pages and 48 pad bytes
avrdude: writing 208 bytes flash ...

Writing | ################################################## | 100% 0.09 s 

avrdude: 208 bytes of flash written
avrdude: verifying flash memory against led.elf

Reading | ################################################## | 100% 0.04 s 

avrdude: 208 bytes of flash verified

avrdude done.  Thank you.

mcuee@UbuntuSwift3:~/build/avr/arduino-blink-purec$ avrdude -c usbasp -p m328p -qqt
avrdude> dump flash
0000  0c 94 44 00 0c 94 4e 00  0c 94 4e 00 0c 94 4e 00  | .D. .N. .N. .N.|
0010  0c 94 4e 00 0c 94 4e 00  0c 94 4e 00 0c 94 4e 00  | .N. .N. .N. .N.|
0020  0c 94 4e 00 0c 94 4e 00  0c 94 4e 00 0c 94 4e 00  | .N. .N. .N. .N.|
0030  0c 94 4e 00 0c 94 4e 00  0c 94 4e 00 0c 94 4e 00  | .N. .N. .N. .N.|
0040  0c 94 4e 00 0c 94 4e 00  0c 94 4e 00 0c 94 4e 00  | .N. .N. .N. .N.|
0050  0c 94 4e 00 0c 94 4e 00  0c 94 4e 00 0c 94 4e 00  | .N. .N. .N. .N.|
0060  0c 94 4e 00 0c 94 4e 00  48 65 6c 6c 6f 2c 20 77  | .N. .N.Hello, w|
0070  6f 72 6c 64 0a 00 42 6f  6e 6a 6f 75 72 20 6c 65  |orld .Bonjour le|
0080  20 6d 6f 6e 64 65 0a 00  11 24 1f be cf ef d8 e0  | monde ..$......|
0090  de bf cd bf 0e 94 50 00  0c 94 66 00 0c 94 00 00  |......P. .f. ...|
00a0  25 9a 2d 9a 2f ef 89 e6  98 e1 21 50 80 40 90 40  |%.-./.....!P.@.@|
00b0  e1 f7 00 c0 00 00 2d 98  2f ef 89 e6 98 e1 21 50  |......-./.....!P|
00c0  80 40 90 40 e1 f7 00 c0  00 00 eb cf f8 94 ff cf  |.@.@............|
00d0  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
00e0  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
00f0  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|

avrdude> quit
avrdude> 
dl8dtl commented 1 year ago

Regarding a possible enhancement option, we could teach the -U option which ELF sections to use, somehow. I'm only afraid that makes the syntax and possible ambiguities of the syntax even worse – we already have the issue with Windows filenames that contain a colon, where the heuristics fail, and the user is required to supply all four syntax elements after -U.

mcuee commented 1 year ago

@dl8dtl

What is the right syntax to define the attribute .progmemx.*.? Thanks.

stefanrueger commented 1 year ago

Just kicking out the EEPROM section is basically a poor abuse only.

You don't need to kick out the EEPROM section in objcopy. It is the address space that makes things right.

Again, what is wrong with the following .elf? In terms of attributes? In terms of addresses? In terms of types?

$ readelf -S morse.elf
There are 15 section headers, starting at offset 0x1f54:

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .data             PROGBITS        00800100 0004b0 000012 00  WA  0   0  1
  [ 2] .text             PROGBITS        00000000 0000b4 0003ee 00  AX  0   0  2
  [ 3] .progdata         PROGBITS        000003ee 0004a2 00000e 00   A  0   0  1
  [ 4] .bss              NOBITS          00800112 0004c2 000064 00  WA  0   0  1
  [ 5] .eeprom           PROGBITS        00810000 0004c2 000020 00  WA  0   0  1
  [ 6] .comment          PROGBITS        00000000 0004e2 000011 01  MS  0   0  1
  [ 7] .note.gnu.avr.dev NOTE            00000000 0004f4 000040 00      0   0  4
  [ 8] .debug_info       PROGBITS        00000000 000534 0005f4 00      0   0  1
  [ 9] .debug_abbrev     PROGBITS        00000000 000b28 0005a2 00      0   0  1
  [10] .debug_line       PROGBITS        00000000 0010ca 00001a 00      0   0  1
  [11] .debug_str        PROGBITS        00000000 0010e4 000208 00      0   0  1
  [12] .shstrtab         STRTAB          00000000 001ec1 000091 00      0   0  1
  [13] .symtab           SYMTAB          00000000 0012ec 0006f0 10     14  46  4
  [14] .strtab           STRTAB          00000000 0019dc 0004e5 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  L (link order), O (extra OS processing required), G (group), T (TLS),
  C (compressed), x (unknown), o (OS specific), E (exclude),
  p (processor specific)

Let me repeat: the .elf does not know whether it was created by an old or a new toolchain or whether you approve of its making (custom linker script or not). What is it that kicks .progdata out?

dl8dtl commented 1 year ago

I don't think there's a separate keyword for that, so you can only declare it with the full section attribute syntax. … __attribute__((__section__((".progmemx.data"))).

dl8dtl commented 1 year ago

Let me repeat: the .elf does not know whether it was created by an old or a new toolchain

It does. If you'd use the newer linker scripts, and .progmemx.data, your data would appear inside .text in the resulting ELF file. That is the big difference, the toolchain design is supposed to have all flash data in .text.

stefanrueger commented 1 year ago

__attribute__((__section__((".progmemx.data")))

That's exactly what I did!

dl8dtl commented 1 year ago

__attribute__((__section__((".progmemx.data")))

That's exactly what I did!

Yep, but with too old linker scripts that don't have the support for .progmemx.* added.

stefanrueger commented 1 year ago

the toolchain design is supposed to have all flash data in .text

and .data

and other sections; why then would the toolchain have left the space between .text and .data and actually considered .progdata to sit between them?

dl8dtl commented 1 year ago

With an up-to-date toolchain, it looks like that:

$ avr-objdump -h led.o

led.o:     file format elf32-avr

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .text         00000000  00000000  00000000  00000034  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .data         00000012  00000000  00000000  00000034  2**0
                  CONTENTS, ALLOC, LOAD, DATA
  2 .bss          00000000  00000000  00000000  00000046  2**0
                  ALLOC
  3 .text.startup 0000002c  00000000  00000000  00000046  2**0
                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
  4 .progmemx.data 0000000e  00000000  00000000  00000072  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  5 .comment      00000013  00000000  00000000  00000080  2**0
                  CONTENTS, READONLY
$ avr-objdump -h led

led:     file format elf32-avr

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .data         00000012  00800100  000000d4  00000148  2**0
                  CONTENTS, ALLOC, LOAD, DATA
  1 .text         000000d4  00000000  00000000  00000074  2**1
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  2 .comment      00000012  00000000  00000000  0000015a  2**0
                  CONTENTS, READONLY
  3 .note.gnu.avr.deviceinfo 00000040  00000000  00000000  0000016c  2**2
                  CONTENTS, READONLY
  4 .debug_info   000005f4  00000000  00000000  000001ac  2**0
                  CONTENTS, READONLY, DEBUGGING
  5 .debug_abbrev 000005a2  00000000  00000000  000007a0  2**0
                  CONTENTS, READONLY, DEBUGGING
  6 .debug_line   0000001d  00000000  00000000  00000d42  2**0
                  CONTENTS, READONLY, DEBUGGING
  7 .debug_str    00000208  00000000  00000000  00000d5f  2**0
                  CONTENTS, READONLY, DEBUGGING

Note that led.o contains .progmemx.data, while the linked ELF file doesn't. It has everything in .text.

mcuee commented 1 year ago

With an up-to-date toolchain, it looks like that:

What is the avr-gcc version you are using? Apparently avr-gcc 7.3 from Atmel does not work.

mcuee@UbuntuSwift3:~/build/avr/arduino-blink-purec$ avr-gcc -v
Using built-in specs.
Reading specs from /home/mcuee/avr8-gnu-toolchain-linux_x86_64/bin/../lib/gcc/avr/7.3.0/device-specs/specs-avr2
COLLECT_GCC=avr-gcc
COLLECT_LTO_WRAPPER=/home/mcuee/avr8-gnu-toolchain-linux_x86_64/bin/../libexec/gcc/avr/7.3.0/lto-wrapper
Target: avr
Configured with: /home/toolsbuild/workspace/avr8-gnu-toolchain/src/gcc/configure LDFLAGS=-L/home/toolsbuild/workspace/avr8-gnu-toolchain/avr8-gnu-toolchain-linux_x86_64-hostlibs/lib CPPFLAGS= --target=avr --host=x86_64-pc-linux-gnu --build=x86_64-pc-linux-gnu --prefix=/home/toolsbuild/workspace/avr8-gnu-toolchain/avr8-gnu-toolchain-linux_x86_64 --libdir=/home/toolsbuild/workspace/avr8-gnu-toolchain/avr8-gnu-toolchain-linux_x86_64/lib --enable-languages=c,c++ --with-dwarf2 --enable-doc --disable-shared --disable-libada --disable-libssp --disable-nls --with-avrlibc=yes --with-mpfr=/home/toolsbuild/workspace/avr8-gnu-toolchain/avr8-gnu-toolchain-linux_x86_64-hostlibs --with-gmp=/home/toolsbuild/workspace/avr8-gnu-toolchain/avr8-gnu-toolchain-linux_x86_64-hostlibs --with-mpc=/home/toolsbuild/workspace/avr8-gnu-toolchain/avr8-gnu-toolchain-linux_x86_64-hostlibs --with-pkgversion=AVR_8_bit_GNU_Toolchain_3.7.0_1796 --with-bugurl=http://www.microchip.com
Thread model: single
gcc version 7.3.0 (AVR_8_bit_GNU_Toolchain_3.7.0_1796) 
dl8dtl commented 1 year ago

the toolchain design is supposed to have all flash data in .text

and .data

No. The linker script takes care of copying the initial values to .text.

dl8dtl commented 1 year ago

With an up-to-date toolchain, it looks like that:

What is the avr-gcc version you are using? Apparently avr-gcc 7.3 from Atmel does not work.

I think it's merely a matter of the binutils version.

Atmel decoupled their stuff from the opensource mainline development many years ago. :-( Basically by the time when they started to put everything into device packs. They no longer use the official avr-libc stuff there, and likely lag behind with a lot of the remaining tool development.

stefanrueger commented 1 year ago

The linker script takes care of copying the initial values to .text.

No. We had that before. The .text section does not contain .data.

dl8dtl commented 1 year ago

The linker script takes care of copying the initial values to .text.

No. We had that before. The .text section does not contain .data.

OK, you're right. Copying that to flash was always considered the job of the postprocessing tool.

dl8dtl commented 1 year ago

But to make nails with heads: let's extend the -U option to allow for explicitly naming ELF sections to include.

dl8dtl commented 1 year ago

I think it's merely a matter of the binutils version.

2017-07-27  Georg-Johann Lay  <gjl@gcc.gnu.org>

        PR ld/21849
        * scripttempl/avr.sc: Split .progmemx.* from .progmem.* and locate
        former at a higher address.

(GNU ld ChangeLog-2017)

stefanrueger commented 1 year ago

The current AVRDUDE code almost gets the sections right (in my sense). It just misses some sections that are mapped into Segments in the elf file. Look closely at Segment 00 in below output from readelf:

$ readelf -l morse.elf
Elf file type is EXEC (Executable file)
Entry point 0x0
There are 4 program headers, starting at offset 52

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  LOAD           0x0000b4 0x00000000 0x00000000 0x003fc 0x003fc R E 0x2
  LOAD           0x0004b0 0x00800100 0x000003fc 0x00012 0x00012 RW  0x1
  LOAD           0x0004c2 0x00800112 0x00800112 0x00000 0x00064 RW  0x1
  LOAD           0x0004c2 0x00810000 0x00810000 0x00020 0x00020 RW  0x1

 Section to Segment mapping:
  Segment Sections...
   00     .text .progdata
   01     .data
   02     .bss
   03     .eeprom

The AVRDUDE scan misses the .progdata section (that has all the right attributes, addresses, types ...) in Section 00

I suggest changing the code to scoop up the remaining sections that are needed for Section 00 of the program. I also suggest @dl8dtl look away for this ;)

dl8dtl commented 1 year ago

I suggest to extend -U instead. ;-)

stefanrueger commented 1 year ago

But to make nails with heads: let's extend the -U option to allow for explicitly naming ELF sections to include.

No that's not needed. A different scan of the .elf segments will do. It's all already there in the segments.

stefanrueger commented 1 year ago

Really, the question is whether we can tell from the .elf file which sections belong to flash and which not. The user does not need to know (and should not need to know, b/c the elf file already does). Here my proposal: Sections that are

are used. Voila. A small step for AVRDUDE. A large step for Mankind.

dl8dtl commented 1 year ago

I'm afraid .data doesn't match your requirements (outside of your address range).

mcuee commented 1 year ago

With an up-to-date toolchain, it looks like that: ... Note that led.o contains .progmemx.data, while the linked ELF file doesn't. It has everything in .text.

@dl8dtl I get the same result as you under MSYS2, Sorry I miss-understood the meaning of "top of the memory" and thought that it did not work.

$ avr-objdump -h led.elf

led.elf:     file format elf32-avr

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .data         00000000  00800100  000000d0  00000184  2**0
                  CONTENTS, ALLOC, LOAD, DATA
  1 .text         000000d0  00000000  00000000  000000b4  2**1
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  2 .eeprom       00000020  00810000  00810000  00000184  2**0
                  CONTENTS, ALLOC, LOAD, DATA
  3 .fuse         00000003  00820000  00820000  000001a4  2**0
                  CONTENTS, ALLOC, LOAD, DATA
  4 .comment      00000011  00000000  00000000  000001a7  2**0
                  CONTENTS, READONLY
  5 .note.gnu.avr.deviceinfo 00000040  00000000  00000000  000001b8  2**2
                  CONTENTS, READONLY, OCTETS
  6 .debug_info   000005f4  00000000  00000000  000001f8  2**0
                  CONTENTS, READONLY, DEBUGGING, OCTETS
  7 .debug_abbrev 000005a2  00000000  00000000  000007ec  2**0
                  CONTENTS, READONLY, DEBUGGING, OCTETS
  8 .debug_line   0000001d  00000000  00000000  00000d8e  2**0
                  CONTENTS, READONLY, DEBUGGING, OCTETS
  9 .debug_str    00000208  00000000  00000000  00000dab  2**0
                  CONTENTS, READONLY, DEBUGGING, OCTETS

$ avrdude -c usbasp -p m328p -U led.elf -q

avrdude: AVR device initialized and ready to accept instructions
avrdude: device signature = 0x1e950f (probably m328p)
avrdude: Note: flash memory has been specified, an erase cycle will be performed.
         To disable this feature, specify the -D option.
avrdude: erasing chip
avrdude: reading input file led.elf for flash
         with 208 bytes in 1 section within [0, 0xcf]
         using 2 pages and 48 pad bytes
avrdude: writing 208 bytes flash ...
avrdude: 208 bytes of flash written
avrdude: verifying flash memory against led.elf
avrdude: 208 bytes of flash verified

avrdude done.  Thank you.

$ avrdude -c usbasp -p m328p -qqt
avrdude> dump flash
>>> dump flash
0000  0c 94 3d 00 0c 94 47 00  0c 94 47 00 0c 94 47 00  | .=. .G. .G. .G.|
0010  0c 94 47 00 0c 94 47 00  0c 94 47 00 0c 94 47 00  | .G. .G. .G. .G.|
0020  0c 94 47 00 0c 94 47 00  0c 94 47 00 0c 94 47 00  | .G. .G. .G. .G.|
0030  0c 94 47 00 0c 94 47 00  0c 94 47 00 0c 94 47 00  | .G. .G. .G. .G.|
0040  0c 94 47 00 0c 94 47 00  0c 94 47 00 0c 94 47 00  | .G. .G. .G. .G.|
0050  0c 94 47 00 0c 94 47 00  0c 94 47 00 0c 94 47 00  | .G. .G. .G. .G.|
0060  0c 94 47 00 0c 94 47 00  42 6f 6e 6a 6f 75 72 20  | .G. .G.Bonjour |
0070  6c 65 20 6d 6f 6e 64 65  0a 00 11 24 1f be cf ef  |le monde ..$....|
0080  d8 e0 de bf cd bf 0e 94  49 00 0c 94 5f 00 0c 94  |........I. ._. .|
0090  00 00 25 9a 2d 9a 2f ef  89 e6 98 e1 21 50 80 40  |..%.-./.....!P.@|
00a0  90 40 e1 f7 00 c0 00 00  2d 98 2f ef 89 e6 98 e1  |.@......-./.....|
00b0  21 50 80 40 90 40 e1 f7  00 c0 00 00 eb cf f8 94  |!P.@.@..........|
00c0  ff cf 48 65 6c 6c 6f 2c  20 77 6f 72 6c 64 0a 00  |..Hello, world .|
00d0  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
00e0  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
00f0  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|

avrdude> quit
>>> quit
avrdude>

Just kicking out the EEPROM section is basically a poor abuse only. This gets immediately obvious if your program code also contains initialization values for fuses (<avr/fuse.h>). -R .eeprom would also copy them to flash as well. Certainly, it's just a few bytes, but would you consider that technically correct then?

And you are absolutely correct about the fuse thingy. I saw this in Arduino IDE and I was thinking it was an Arduino problem. Now I understood. Thanks.

$ cat led.hex
:100000000C943D000C9447000C9447000C9447005E
:100010000C9447000C9447000C9447000C94470044
:100020000C9447000C9447000C9447000C94470034
:100030000C9447000C9447000C9447000C94470024
:100040000C9447000C9447000C9447000C94470014
:100050000C9447000C9447000C9447000C94470004
:100060000C9447000C944700426F6E6A6F757220C3
:100070006C65206D6F6E64650A0011241FBECFEFA2
:10008000D8E0DEBFCDBF0E9449000C945F000C9405
:100090000000259A2D9A2FEF89E698E121508040A3
:1000A0009040E1F700C000002D982FEF89E698E11D
:1000B000215080409040E1F700C00000EBCFF89461
:1000C000FFCF48656C6C6F2C20776F726C640A00F0
:02000004008179
:1000000048656C6C6F20576F726C642100000000B3
:1000100000000000000000000000000000000000E0
:02000004008278
:03000000F7D6FD33
:00000001FF

$ avrdude -c usbasp -p m328p -U led.hex

avrdude: AVR device initialized and ready to accept instructions
avrdude: device signature = 0x1e950f (probably m328p)
avrdude: Note: flash memory has been specified, an erase cycle will be performed.
         To disable this feature, specify the -D option.
avrdude: erasing chip
avrdude error: address 0x810010 out of range at line 15 of led.hex
avrdude error: read from file led.hex failed

avrdude done.  Thank you.
stefanrueger commented 1 year ago

I'm afraid .data doesn't match your requirements (outside of your address range).

You are right! Seems to be even easier: Copy sections that are

mcuee commented 1 year ago

@dl8dtl

I feel it strange that avr-gcc does not create a new section for other memory sections like fuses.

I also feel it strange that we need to create a seperate .eep file for EEPROM. The hex file can already include the EEPROM as its address range is different from the flash.

Take note I was a Microchip PIC guy last time and not that familiar with Atmel AVR (some encouters with USB AVR/AVR32 but not much, thanks to the free AVR Dragon and two demo boards from Atmel many years ago).

The memory space “seen” by AVRGCC runs from addresses:

0x00000000 up to 0x0007FFFF for Flash memory,
0x00800000 up to 0x0080FFFF for RAM, and
0x00810000 up to 0x0081FFFF for EEPROM.
stefanrueger commented 1 year ago

@mcuee In your run, Bonjour le monde appears to be at the bottom of the instructions. Not what's needed.