Skip to content

runtime/libtock_layout.ld: use FLASH-segment LMAs for all sections#478

Merged
bors[bot] merged 2 commits intotock:masterfrom
lschuermann:dev/linker-loadaddr-flash
Jul 10, 2023
Merged

runtime/libtock_layout.ld: use FLASH-segment LMAs for all sections#478
bors[bot] merged 2 commits intotock:masterfrom
lschuermann:dev/linker-loadaddr-flash

Conversation

@lschuermann
Copy link
Copy Markdown
Member

This change ensures that no ELF-segment will have a PhysAddr which points outside of the FLASH memory region. This is important for ROM-loaders such as elf2tab to reliably produce correct binaries.

Motivation

Previously, .stack and .bss sections were simply instructed to be placed into RAM. Without an explicitly specified load address or load address region, this means that their ELF-segment's PhysAddr will be set to its VirtAddr (and hence point into RAM):

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  LOAD           0x001000 0x20030000 0x20030000 0x00000 0x00060 R   0x1000
  LOAD           0x001060 0x20030060 0x20030060 0x00d64 0x00d64 R E 0x1000
  LOAD           0x001dc4 0x20030dc4 0x20030dc4 0x001ec 0x001ec R   0x1000
  LOAD           0x002000 0x10004000 0x10004000 0x00000 0x00100 RW  0x1000
  GNU_STACK      0x000000 0x00000000 0x00000000 0x00000 0x00000 RW  0

 Section to Segment mapping:
  Segment Sections...
   00     .tbf_header
   01     .start .text
   02     .rodata
   03     .stack
   04

When, for any reason, these segments contain any actual data (FileSiz != 0), for instance under certain alignment
constraints[1], this will cause a ROM-loader such as elf2tab to place them at their specified PhysAddr offset. As a result, if ORIGIN(FLASH) precedes ORIGIN(RAM), the binary is blown up due to padding. If ORIGIN(RAM) precedes ORIGIN(FLASH), the rt_header internal offsets are incorrect because the actual FLASH load address is now offset by ORIGIN(FLASH) - ORIGIN(RAM). With this change, no LOADable segment will have a PhysAddr outside of the FLASH memory region. This does not have any effect on zero-sized sections (they will not increase flash usage):

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  LOAD           0x001000 0x20030000 0x20030000 0x00fb0 0x00fb0 RWE 0x1000
  LOAD           0x000800 0x10004800 0x20030fb0 0x00000 0x00100 RW  0x1000
  GNU_STACK      0x000000 0x00000000 0x00000000 0x00000 0x00000 RW  0x10

 Section to Segment mapping:
  Segment Sections...
   00     .tbf_header .start .text .rodata
   01     .stack
   02

The reason why this worked in the past was that elf2tab skipped segments with a FileSiz == 0, and did so even before calculating paddings. We should probably not rely on such an implementation detail of our loader, which can further break if the linker were to insert any padding into a segment.

[1]: See #477 for an example.

Leon Schuermann added 2 commits June 29, 2023 08:49
There's no reason as to why `.data` should be placed directly after
`.rodata` in FLASH. We can use the `> $VMASEGMENT AT > $LMASEGMENT`
syntax to simply place it at the next well-aligned offset in the FLASH
segment. This reduces the overall complexity of the linker scripts,
and avoids accidentally placing multiple sections at competing
addresses.
Previously, `.stack` and `.bss` sections were simply instructed to be
placed into RAM. Without an explicitly specified load address or load
address region, this means that their ELF-segment's `PhysAddr` will be
set to its `VirtAddr` (and hence point into RAM):

    Program Headers:
      Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
      LOAD           0x001000 0x20030000 0x20030000 0x00000 0x00060 R   0x1000
      LOAD           0x001060 0x20030060 0x20030060 0x00d64 0x00d64 R E 0x1000
      LOAD           0x001dc4 0x20030dc4 0x20030dc4 0x001ec 0x001ec R   0x1000
      LOAD           0x002000 0x10004000 0x10004000 0x00000 0x00100 RW  0x1000
      GNU_STACK      0x000000 0x00000000 0x00000000 0x00000 0x00000 RW  0

     Section to Segment mapping:
      Segment Sections...
       00     .tbf_header
       01     .start .text
       02     .rodata
       03     .stack
       04

When, for any reason, these segments contain any actual
data (`FileSiz` != 0), for instance under certain alignment
constraints[1], this will cause a ROM-loader such as elf2tab to place
them at their specified `PhysAddr` offset. As a result, if
`ORIGIN(FLASH)` precedes `ORIGIN(RAM)`, the binary is blown up due to
padding. If `ORIGIN(RAM)` precedes `ORIGIN(FLASH)`, the `rt_header`
internal offsets are incorrect because the actual FLASH load address
is now offset by `ORIGIN(FLASH) - ORIGIN(RAM)`. With this change, no
`LOAD`able segment will have a `PhysAddr` outside of the `FLASH`
memory region. This does not have any effect on zero-sized
sections (they will not increase flash usage):

    Program Headers:
      Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
      LOAD           0x001000 0x20030000 0x20030000 0x00fb0 0x00fb0 RWE 0x1000
      LOAD           0x000800 0x10004800 0x20030fb0 0x00000 0x00100 RW  0x1000
      GNU_STACK      0x000000 0x00000000 0x00000000 0x00000 0x00000 RW  0x10

     Section to Segment mapping:
      Segment Sections...
       00     .tbf_header .start .text .rodata
       01     .stack
       02

The reason why this worked in the past was that `elf2tab` skipped
segments with a `FileSiz` == 0, and did so even before calculating
paddings. We should probably not rely on such an implementation detail
of our loader, which can further break if the linker were to insert
any padding into a segment.

[1]: See tock#477 for an example.
@lschuermann lschuermann requested a review from jrvanwhy June 29, 2023 13:04
@jrvanwhy
Copy link
Copy Markdown
Collaborator

bors r+

@bors
Copy link
Copy Markdown
Contributor

bors Bot commented Jul 10, 2023

Build succeeded!

The publicly hosted instance of bors-ng is deprecated and will go away soon.

If you want to self-host your own instance, instructions are here.
For more help, visit the forum.

If you want to switch to GitHub's built-in merge queue, visit their help page.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants