Skip to content

Conversation

maribu
Copy link
Member

@maribu maribu commented Aug 31, 2021

Contribution description

The xfa.ld script is incompatible with binutils > 2.35.2 and results in firmwares that wont boot. Sadly, I couldn't figure out an elegant way to fix the issue. Instead, I modified the linker script provided by binutils to also include XFA.

Testing procedure

  • tests/xfa should again still compile, flash, and boot
  • any other application should again compile, flash, and boot

Issues/PRs references

Fixes #16251

@maribu maribu added Platform: AVR Platform: This PR/issue effects AVR-based platforms Type: bug The issue reports a bug / The PR fixes a bug (including spelling errors) labels Aug 31, 2021
@github-actions github-actions bot added Area: build system Area: Build system Area: cpu Area: CPU/MCU ports labels Aug 31, 2021
@maribu maribu added CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR and removed Area: build system Area: Build system Area: cpu Area: CPU/MCU ports labels Aug 31, 2021
@kaspar030
Copy link
Contributor

does this one ldscript work for all our avr8s?

@benpicco
Copy link
Contributor

benpicco commented Sep 1, 2021

@nandojve want to take a look at this?

@maribu
Copy link
Member Author

maribu commented Sep 1, 2021

Maybe @jnohlgard has an idea how to fix the original xfa.ld script instead?

@benpicco benpicco added this to the Release 2021.10 milestone Sep 1, 2021
@benpicco
Copy link
Contributor

benpicco commented Sep 1, 2021

What is the linker script this is based on?

Of course if we can't find a solution that can do with less copy & paste, we should merge this swiftly before the next release.
Better have some code duplication than a broken platform.

@maribu
Copy link
Member Author

maribu commented Sep 1, 2021

What is the linker script this is based on?

The one provided by binutils-avr 2.37-r of Alpine (I think binutils is build unpatched on Alpine):

$ diff /usr/avr/lib/ldscripts/avr6.xn avr8.ld 
--- /usr/avr/lib/ldscripts/avr6.xn
+++ avr8.ld
@@ -173,7 +173,9 @@
   {
      PROVIDE (__data_start = .) ;
     *(.data)
-     *(.data*)
+    *(.data*)
+    KEEP (*(SORT(.roxfa.*)))
+    KEEP (*(SORT(.xfa.*)))
     *(.gnu.linkonce.d*)
     *(.rodata)  /* We need to include .rodata here if gcc is used */
     *(.rodata*) /* with -fdata-sections.  */

@benpicco
Copy link
Contributor

benpicco commented Sep 1, 2021

That's a pleasantly small change. Better mark that in the linker script to ease future updates.

@github-actions github-actions bot added Area: build system Area: Build system Area: cpu Area: CPU/MCU ports labels Sep 1, 2021
@benpicco
Copy link
Contributor

benpicco commented Sep 1, 2021

feel free to squash

@nandojve
Copy link
Contributor

nandojve commented Sep 2, 2021

Hi, I noted below from /usr/lib/avr/lib/ldscripts/avrxmega7.x. It'll be require some investigation yet, just to make sure we can live without it, or not :D

diff --git a/cpu/avr8_common/ldscripts/avr8.ld b/cpu/avr8_common/ldscripts/avr8.ld
index 0ac95e9505..bed30592ae 100644
--- a/cpu/avr8_common/ldscripts/avr8.ld
+++ b/cpu/avr8_common/ldscripts/avr8.ld
@@ -101,6 +101,10 @@ SECTIONS
     *libc.a:*(.progmem.data)
     *(.progmem.*)
     . = ALIGN(2);
+    /* For future tablejump instruction arrays for 3 byte pc devices.
+       We don't relax jump/call instructions within these sections.  */
+    *(.jumptables)
+     *(.jumptables*)
     /* For code that needs to reside in the lower 128k progmem.  */
     *(.lowtext)
     *(.lowtext*)
@@ -226,6 +230,10 @@ SECTIONS
   {
     KEEP(*(.signature*))
   }  > signature
+  .user_signatures  :
+  {
+    KEEP(*(.user_signatures*))
+  }  > user_signatures
   /* Stabs debugging sections.  */
   .stab 0 : { *(.stab) }
   .stabstr 0 : { *(.stabstr) }

@jnohlgard
Copy link
Member

Did you figure out what the difference is between the working binary and the broken one?

@maribu
Copy link
Member Author

maribu commented Sep 2, 2021

@jnohlgard: The .data sections are now longer merged and the .text section gets a wrong offset.

Old binutils (working):

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .text             PROGBITS        00000000 000094 002bf2 00  AX  0   0  2
  [ 2] .data             PROGBITS        00800200 002c86 00092c 00  WA  0   0  1
  [ 3] .bss              NOBITS          00800b2c 0035b2 0003cd 00  WA  0   0  1
  [ 4] .noinit           NOBITS          00800ef9 0035b2 000002 00  WA  0   0  1
  [ 5] .comment          PROGBITS        00000000 0035b2 00002c 01  MS  0   0  1
  [ 6] .note.gnu.av[...] NOTE            00000000 0035e0 000040 00      0   0  4
  [ 7] .debug_aranges    PROGBITS        00000000 003620 0007f0 00      0   0  1
  [ 8] .debug_info       PROGBITS        00000000 003e10 00d4bd 00      0   0  1
  [ 9] .debug_abbrev     PROGBITS        00000000 0112cd 005141 00      0   0  1
  [10] .debug_line       PROGBITS        00000000 01640e 011d3e 00      0   0  1
  [11] .debug_frame      PROGBITS        00000000 02814c 001634 00      0   0  4
  [12] .debug_str        PROGBITS        00000000 029780 014785 00      0   0  1
  [13] .debug_loc        PROGBITS        00000000 03df05 006aaa 00      0   0  1
  [14] .debug_ranges     PROGBITS        00000000 0449af 000aa8 00      0   0  1
  [15] .debug_macro      PROGBITS        00000000 045457 023d6b 00      0   0  1
  [16] .symtab           SYMTAB          00000000 0691c4 002330 10     17 360  4
  [17] .strtab           STRTAB          00000000 06b4f4 000db8 00      0   0  1
  [18] .shstrtab         STRTAB          00000000 06c2ac 0000c9 00      0   0  1

New binutils (broken):

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .text             PROGBITS        00000000 0000b4 002bf2 00  AX  0   0  2
  [ 2] .data             PROGBITS        00800200 0035d2 000000 00  WA  0   0  1
  [ 3] .data             PROGBITS        00800200 002ca6 00092c 00  WA  0   0  1
  [ 4] .bss              NOBITS          00800200 0035d2 0003cd 00  WA  0   0  1
  [ 5] .noinit           NOBITS          008005cd 0035d2 000002 00  WA  0   0  1
  [ 6] .comment          PROGBITS        00000000 0035d2 00002c 01  MS  0   0  1
  [ 7] .note.gnu.av[...] NOTE            00000000 003600 000040 00      0   0  4
  [ 8] .debug_aranges    PROGBITS        00000000 003640 0007f0 00      0   0  1
  [ 9] .debug_info       PROGBITS        00000000 003e30 00d4bd 00      0   0  1
  [10] .debug_abbrev     PROGBITS        00000000 0112ed 005141 00      0   0  1
  [11] .debug_line       PROGBITS        00000000 01642e 011d3e 00      0   0  1
  [12] .debug_frame      PROGBITS        00000000 02816c 001634 00      0   0  4
  [13] .debug_str        PROGBITS        00000000 0297a0 014785 00      0   0  1
  [14] .debug_loc        PROGBITS        00000000 03df25 006aaa 00      0   0  1
  [15] .debug_ranges     PROGBITS        00000000 0449cf 000aa8 00      0   0  1
  [16] .debug_macro      PROGBITS        00000000 045477 023d6b 00      0   0  1
  [17] .symtab           SYMTAB          00000000 0691e4 002340 10     18 361  4
  [18] .strtab           STRTAB          00000000 06b524 000db8 00      0   0  1
  [19] .shstrtab         STRTAB          00000000 06c2dc 0000c9 00      0   0  1

@jnohlgard
Copy link
Member

Which ld variant are you using? (gold, bfd, lld?)

@maribu
Copy link
Member Author

maribu commented Sep 6, 2021

the binutils linker

@benpicco benpicco added CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR and removed CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR labels Sep 14, 2021
@benpicco
Copy link
Contributor

Murdock does not like it.

@maribu
Copy link
Member Author

maribu commented Sep 15, 2021

Murdock does not like it.

Seems like the new linker script is not compatible with the toolchain in the docker container. Maybe diffing the to scripts could also give a clue why xfa.ld stopped working in the first place.

Anyway, I will have to resume looking into this after my vacation. Feel free to take over, if this is an itch you care to scratch.

@maribu maribu force-pushed the cpu/avr8_common/ldscripts branch from b2c59c9 to ce65c34 Compare September 28, 2021 09:09
@maribu
Copy link
Member Author

maribu commented Sep 28, 2021

does this one ldscript work for all our avr8s?

Almost.

--- avr51.xn
+++ avr6.xn
@@ -4,9 +4,9 @@
    are permitted in any medium without royalty provided the copyright
    notice and this notice are preserved.  */
 OUTPUT_FORMAT("elf32-avr","elf32-avr","elf32-avr")
-OUTPUT_ARCH(avr:51)
-__TEXT_REGION_LENGTH__ = DEFINED(__TEXT_REGION_LENGTH__) ? __TEXT_REGION_LENGTH__ : 128K;
-__DATA_REGION_LENGTH__ = DEFINED(__DATA_REGION_LENGTH__) ? __DATA_REGION_LENGTH__ : 0xff00;
+OUTPUT_ARCH(avr:6)
+__TEXT_REGION_LENGTH__ = DEFINED(__TEXT_REGION_LENGTH__) ? __TEXT_REGION_LENGTH__ : 1024K;
+__DATA_REGION_LENGTH__ = DEFINED(__DATA_REGION_LENGTH__) ? __DATA_REGION_LENGTH__ : 0xfe00;
 __EEPROM_REGION_LENGTH__ = DEFINED(__EEPROM_REGION_LENGTH__) ? __EEPROM_REGION_LENGTH__ : 64K;
 __FUSE_REGION_LENGTH__ = DEFINED(__FUSE_REGION_LENGTH__) ? __FUSE_REGION_LENGTH__ : 1K;
 __LOCK_REGION_LENGTH__ = DEFINED(__LOCK_REGION_LENGTH__) ? __LOCK_REGION_LENGTH__ : 1K;
@@ -15,7 +15,7 @@
 MEMORY
 {
   text   (rx)   : ORIGIN = 0, LENGTH = __TEXT_REGION_LENGTH__
-  data   (rw!x) : ORIGIN = 0x800100, LENGTH = __DATA_REGION_LENGTH__
+  data   (rw!x) : ORIGIN = 0x800200, LENGTH = __DATA_REGION_LENGTH__
   eeprom (rw!x) : ORIGIN = 0x810000, LENGTH = __EEPROM_REGION_LENGTH__
   fuse      (rw!x) : ORIGIN = 0x820000, LENGTH = __FUSE_REGION_LENGTH__
   lock      (rw!x) : ORIGIN = 0x830000, LENGTH = __LOCK_REGION_LENGTH__
--- avr51.xn
+++ avrxmega6.xn
@@ -4,9 +4,9 @@
    are permitted in any medium without royalty provided the copyright
    notice and this notice are preserved.  */
 OUTPUT_FORMAT("elf32-avr","elf32-avr","elf32-avr")
-OUTPUT_ARCH(avr:51)
-__TEXT_REGION_LENGTH__ = DEFINED(__TEXT_REGION_LENGTH__) ? __TEXT_REGION_LENGTH__ : 128K;
-__DATA_REGION_LENGTH__ = DEFINED(__DATA_REGION_LENGTH__) ? __DATA_REGION_LENGTH__ : 0xff00;
+OUTPUT_ARCH(avr:106)
+__TEXT_REGION_LENGTH__ = DEFINED(__TEXT_REGION_LENGTH__) ? __TEXT_REGION_LENGTH__ : 1024K;
+__DATA_REGION_LENGTH__ = DEFINED(__DATA_REGION_LENGTH__) ? __DATA_REGION_LENGTH__ : 0xffa0;
 __EEPROM_REGION_LENGTH__ = DEFINED(__EEPROM_REGION_LENGTH__) ? __EEPROM_REGION_LENGTH__ : 64K;
 __FUSE_REGION_LENGTH__ = DEFINED(__FUSE_REGION_LENGTH__) ? __FUSE_REGION_LENGTH__ : 1K;
 __LOCK_REGION_LENGTH__ = DEFINED(__LOCK_REGION_LENGTH__) ? __LOCK_REGION_LENGTH__ : 1K;
@@ -15,7 +15,7 @@
 MEMORY
 {
   text   (rx)   : ORIGIN = 0, LENGTH = __TEXT_REGION_LENGTH__
-  data   (rw!x) : ORIGIN = 0x800100, LENGTH = __DATA_REGION_LENGTH__
+  data   (rw!x) : ORIGIN = 0x802000, LENGTH = __DATA_REGION_LENGTH__
   eeprom (rw!x) : ORIGIN = 0x810000, LENGTH = __EEPROM_REGION_LENGTH__
   fuse      (rw!x) : ORIGIN = 0x820000, LENGTH = __FUSE_REGION_LENGTH__
   lock      (rw!x) : ORIGIN = 0x830000, LENGTH = __LOCK_REGION_LENGTH__
--- avr51.xn
+++ avrxmega7.xn
@@ -4,9 +4,9 @@
    are permitted in any medium without royalty provided the copyright
    notice and this notice are preserved.  */
 OUTPUT_FORMAT("elf32-avr","elf32-avr","elf32-avr")
-OUTPUT_ARCH(avr:51)
-__TEXT_REGION_LENGTH__ = DEFINED(__TEXT_REGION_LENGTH__) ? __TEXT_REGION_LENGTH__ : 128K;
-__DATA_REGION_LENGTH__ = DEFINED(__DATA_REGION_LENGTH__) ? __DATA_REGION_LENGTH__ : 0xff00;
+OUTPUT_ARCH(avr:107)
+__TEXT_REGION_LENGTH__ = DEFINED(__TEXT_REGION_LENGTH__) ? __TEXT_REGION_LENGTH__ : 1024K;
+__DATA_REGION_LENGTH__ = DEFINED(__DATA_REGION_LENGTH__) ? __DATA_REGION_LENGTH__ : 0xffa0;
 __EEPROM_REGION_LENGTH__ = DEFINED(__EEPROM_REGION_LENGTH__) ? __EEPROM_REGION_LENGTH__ : 64K;
 __FUSE_REGION_LENGTH__ = DEFINED(__FUSE_REGION_LENGTH__) ? __FUSE_REGION_LENGTH__ : 1K;
 __LOCK_REGION_LENGTH__ = DEFINED(__LOCK_REGION_LENGTH__) ? __LOCK_REGION_LENGTH__ : 1K;
@@ -15,7 +15,7 @@
 MEMORY
 {
   text   (rx)   : ORIGIN = 0, LENGTH = __TEXT_REGION_LENGTH__
-  data   (rw!x) : ORIGIN = 0x800100, LENGTH = __DATA_REGION_LENGTH__
+  data   (rw!x) : ORIGIN = 0x802000, LENGTH = __DATA_REGION_LENGTH__
   eeprom (rw!x) : ORIGIN = 0x810000, LENGTH = __EEPROM_REGION_LENGTH__
   fuse      (rw!x) : ORIGIN = 0x820000, LENGTH = __FUSE_REGION_LENGTH__
   lock      (rw!x) : ORIGIN = 0x830000, LENGTH = __LOCK_REGION_LENGTH__

The main part of the LD scripts are completely identical, so I just added a common avr_common.ld for the arch specific linker scripts to include, which only set up the memory layout according to what the arch expects.

@nandojve
Copy link
Contributor

Hi @maribu ,

Nice work! I noted that it is missing "user_signature" entries at avr_common.ld. See, #16790 (comment)

@maribu
Copy link
Member Author

maribu commented Sep 28, 2021

I noted that it is missing "user_signature"

That section was dropped upstream. The linker scripts are identical to the ones a current AVR toolchain contains, execpt for:

  1. Deduplication of the main, common part by splitting it out
  2. Addition of XFA

(See #16790 (comment) - there is indeed no extra section in at ATXmega script comared to the ATmega script. It really only is about memory sizes/origin and output arch.)

I think it will be easier to maintain of the linker scripts remain as close to upstream as possible. But if there is a feature to gain from adding it, I would certainly do so.

@nandojve
Copy link
Contributor

I think it will be easier to maintain of the linker scripts remain as close to upstream as possible. But if there is a feature to gain from adding it, I would certainly do so.

Indeed there is, please check XMEGA-A manual 4.3.5 User Signature Row.

In fact, it is defined at memory sizes as

user_signatures (rw!x) : ORIGIN = 0x850000, LENGTH = __USER_SIGNATURE_REGION_LENGTH__

but there is no entry at avr_common.ld.

@maribu
Copy link
Member Author

maribu commented Sep 28, 2021

Are you sure that there is value in adding that section? The horribly outdated toolchain in riot/riotbuild indeed also has a section for the user_signatures memory area:

SECTIONS
{
  [...]
    .user_signatures  :
  {
    KEEP(*(.user_signatures*))
  }  > user_signatures
  [...]
}

But this section has been dropped in upstream, either for a reason or by accident. In any case, no code in RIOT is providing any symbols that get linked into that section and the section is empty, even when using BUILD_IN_DOCKER=1:

$ avr-readelf -S bin/atxmega-a1u-xpro/default.elf 
There are 19 section headers, starting at offset 0x93348:

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .text             PROGBITS        00000000 000094 004064 00  AX  0   0  2
  [ 2] .data             PROGBITS        00802000 0040f8 000bf8 00  WA  0   0  1
  [ 3] .bss              NOBITS          00802bf8 004cf0 0004b1 00  WA  0   0  1
  [ 4] .noinit           NOBITS          008030a9 004cf0 000002 00  WA  0   0  1
  [ 5] .comment          PROGBITS        00000000 004cf0 000011 01  MS  0   0  1
  [ 6] .note.gnu.av[...] NOTE            00000000 004d04 000040 00      0   0  4
  [ 7] .debug_aranges    PROGBITS        00000000 004d44 000960 00      0   0  1
  [ 8] .debug_info       PROGBITS        00000000 0056a4 01b585 00      0   0  1
  [ 9] .debug_abbrev     PROGBITS        00000000 020c29 008a70 00      0   0  1
  [10] .debug_line       PROGBITS        00000000 029699 00b01c 00      0   0  1
  [11] .debug_frame      PROGBITS        00000000 0346b8 00201c 00      0   0  4
  [12] .debug_str        PROGBITS        00000000 0366d4 028bd2 00      0   0  1
  [13] .debug_loc        PROGBITS        00000000 05f2a6 009aa4 00      0   0  1
  [14] .debug_ranges     PROGBITS        00000000 068d4a 0008e8 00      0   0  1
  [15] .debug_macro      PROGBITS        00000000 069632 0254a2 00      0   0  1
  [16] .shstrtab         STRTAB          00000000 09327d 0000c9 00      0   0  1
  [17] .symtab           SYMTAB          00000000 08ead4 0034e0 10     18 556  4
  [18] .strtab           STRTAB          00000000 091fb4 0012c9 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)

So adding that section will - with the current code in RIOT - not change the ELF file in any way.

I also think it does make sense that upstream dropped it. The user signature seems to be something that you don't want to flash together with your firmware, but rather once during commissioning. Not having the section might prevent some mistakes from happening here.

But in any case: Since the ld scripts are an exact copy of the upstream version (except for the XFA addition and the deduplication), this is IMO unrelated to the PR. That section has also not been present for quite a few release, so any code relying on this will already be broken in master for many RIOT users.

@nandojve
Copy link
Contributor

Are you sure that there is value in adding that section?

I don't have a use case for it. I'm just warning what users may not have access since you are touching LD script topic.
I'll support your decision.

Copy link
Contributor

@benpicco benpicco left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please squash.

I think those avr51, avr6, … could eventually be modeled as CPU_CORE just like we do on Cortex-M.

@benpicco benpicco added the Process: needs backport Integration Process: The PR is required to be backported to a release or feature branch label Oct 13, 2021
@benpicco
Copy link
Contributor

@maribu ping 😉

The xfa.ld script is incompatible with binutils > 2.35.2 and results
in firmwares that wont boot. Sadly, I couldn't figure out an elegant
way to fix the issue. Instead, I modified the linker script provided
by binutils to also include XFA.
@maribu maribu force-pushed the cpu/avr8_common/ldscripts branch from 454c8e1 to 62d6a56 Compare October 13, 2021 14:37
@maribu
Copy link
Member Author

maribu commented Oct 14, 2021

I'm not really happy with this, as understanding and maintaining the original linker script was quite a lot easier than this. But I guess until we have a better fix, we should get this in.

So if nobody speaks up now, I hit the green button soonish.

@maribu maribu merged commit 32be742 into RIOT-OS:master Oct 15, 2021
@maribu maribu deleted the cpu/avr8_common/ldscripts branch October 15, 2021 07:59
@maribu
Copy link
Member Author

maribu commented Oct 15, 2021

Thanks for the reviews!

@maribu
Copy link
Member Author

maribu commented Oct 15, 2021

Backport provided in #16990

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area: build system Area: Build system Area: cpu Area: CPU/MCU ports CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR Platform: AVR Platform: This PR/issue effects AVR-based platforms Process: needs backport Integration Process: The PR is required to be backported to a release or feature branch Type: bug The issue reports a bug / The PR fixes a bug (including spelling errors)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

XFA support on AVR and MSP430 broken with binutils 2.36.1
6 participants