Skip to content

Make Xtensa linker scripts compatible with rust-lld - #5582

Merged
MabezDev merged 7 commits into
mainfrom
xtensa-lld-support
Jun 25, 2026
Merged

Make Xtensa linker scripts compatible with rust-lld#5582
MabezDev merged 7 commits into
mainfrom
xtensa-lld-support

Conversation

@MabezDev

@MabezDev MabezDev commented May 17, 2026

Copy link
Copy Markdown
Member

Pure claude work here, but verified by building various examples. The rest of this PR body is claude, but interesting if you want to understand the changes.

GNU ld and LLD interpret bare . = <const> assignments inside an output
section differently — GNU ld treats them as section-relative offsets,
LLD treats them as absolute addresses. The .vectors section in the
exception template relied on the section-relative behaviour, and the
combined *(.literal .text .literal.* .text.*) patterns relied on GNU
ld's pattern-order section sorting, which LLD does not perform.

Rework .vectors to use SUBALIGN(0x40) plus relative . = . + N
padding so the vector slot positions are derived from input section
sizes rather than absolute assignments, and split the combined
literal/text patterns into separate clauses so literals are always
emitted before the code that references them (required because Xtensa
L32R can only address literals at negative PC offsets).

Changelog

esp-hal

xtensa-lx-rt

  • No changelog necessary.

Copilot AI review requested due to automatic review settings May 17, 2026 13:02

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Makes the Xtensa linker scripts work with both GNU ld and rust-lld by removing semantics that differ between the two: bare . = <const> assignments inside output sections (interpreted as section-relative by GNU ld but absolute by LLD) and combined .literal .text patterns whose ordering depended on GNU ld's pattern-position sorting.

Changes:

  • Rewrite .vectors to use SUBALIGN(0x40) and relative . = . + 0x40 padding so vector slots fall at architecturally fixed offsets under both linkers.
  • Split combined *(.literal .text ...) patterns into separate literal-first / text-after clauses so Xtensa L32R (literals must precede code) is satisfied regardless of pattern-position vs input-order sorting.
  • Add per-archive selectors for GCC-built blobs (wifi/phy/bt) in text.x so each archive's per-function literal/text pairs stay grouped together and within the 256 KB L32R reach.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated no comments.

Show a summary per file
File Description
xtensa-lx-rt/exception-esp32.x.template Replace absolute . = 0xNN slot assignments with SUBALIGN(0x40) + . = . + 0x40 gap before DoubleExceptionVector.
xtensa-lx-rt/xtensa.in.x Split combined .literal .text patterns in .text and .rwtext into literal-first/text-after clauses.
esp-hal/ld/sections/text.x Add per-archive selectors for GCC blobs (wifi/phy/bt); split catch-all into separate literal/text clauses.
esp-hal/ld/sections/rwtext.x Split .rwtext literal/text patterns; also split the esp_rom_spiflash.* selector.
esp-hal/ld/sections/rtc_slow.x Split .rtc_slow literal/text patterns.
esp-hal/ld/sections/rtc_fast.x Split .rtc_fast literal/text patterns.

Comment thread xtensa-lx-rt/exception-esp32.x.template
@bugadani

bugadani commented May 17, 2026

Copy link
Copy Markdown
Contributor

CI looks like we don't get away with only this much

@MabezDev

Copy link
Copy Markdown
Member Author

CI looks like we don't get away with only this much

Working on it :D

Copilot AI review requested due to automatic review settings May 17, 2026 14:17

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated 1 comment.

Comment thread xtensa-lx-rt/exception-esp32.x.template
@MabezDev

Copy link
Copy Markdown
Member Author

Whilst CI passes, I think we should do some more thorough testing (mostly with GCC) to ensure this doesn't break tonnes of stuff.

Copilot AI review requested due to automatic review settings May 29, 2026 09:18

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot wasn't able to review this pull request because it exceeds the maximum number of lines (20,000). Try reducing the number of changed lines and requesting a review from Copilot again.

@MabezDev
MabezDev force-pushed the xtensa-lld-support branch from cc8ddb4 to 4f6d6f3 Compare May 29, 2026 09:19
@MabezDev

Copy link
Copy Markdown
Member Author

/hil full

@github-actions

github-actions Bot commented May 29, 2026

Copy link
Copy Markdown

Triggered full HIL run for #5582.

Run: https://github.com/esp-rs/esp-hal/actions/runs/26630574679

Status update: HIL (full) run is still in progress or status unknown.

Copilot AI review requested due to automatic review settings May 29, 2026 10:04

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated no new comments.

@github-actions github-actions Bot added the merge-conflict Merge conflict detected. Automatically added/removed by CI. label May 29, 2026
@github-actions

Copy link
Copy Markdown

New commits in main have made this PR unmergeable. Please resolve the conflicts.

@MabezDev
MabezDev force-pushed the xtensa-lld-support branch from 72af832 to cda5f74 Compare May 29, 2026 19:39
@github-actions github-actions Bot removed the merge-conflict Merge conflict detected. Automatically added/removed by CI. label May 29, 2026
@MabezDev
MabezDev force-pushed the xtensa-lld-support branch from cda5f74 to 4134725 Compare June 3, 2026 12:42
Copilot AI review requested due to automatic review settings June 3, 2026 12:42

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated 1 comment.

Comment thread xtensa-lx-rt/exception-esp32.x.template
@MabezDev
MabezDev force-pushed the xtensa-lld-support branch from 4134725 to 96f8702 Compare June 3, 2026 13:08

@bjoernQ bjoernQ left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

the two examples which failed before now work

not sure if we should test a few more non-trivial examples?

@MabezDev

MabezDev commented Jun 3, 2026

Copy link
Copy Markdown
Member Author

/hil full

@github-actions

github-actions Bot commented Jun 3, 2026

Copy link
Copy Markdown

Triggered full HIL run for #5582.

Run: https://github.com/esp-rs/esp-hal/actions/runs/26630574679

Status update: ❌ HIL (full) run failed (conclusion: failure).

@MabezDev

Copy link
Copy Markdown
Member Author

/hil full

@github-actions

github-actions Bot commented Jun 23, 2026

Copy link
Copy Markdown

Triggered full HIL run for #5582.

Run: https://github.com/esp-rs/esp-hal/actions/runs/28029882302

Status update: HIL (full) run is still in progress or status unknown.

Copilot AI review requested due to automatic review settings June 23, 2026 15:04
@MabezDev
MabezDev force-pushed the xtensa-lld-support branch from 4972b97 to 0d1a0c1 Compare June 23, 2026 15:06
@MabezDev

Copy link
Copy Markdown
Member Author

/hil full

@github-actions

github-actions Bot commented Jun 23, 2026

Copy link
Copy Markdown

Triggered full HIL run for #5582.

Run: https://github.com/esp-rs/esp-hal/actions/runs/28036050239

Status update: HIL (full) run is still in progress or status unknown.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated 4 comments.

Comment thread xtensa-lx-rt/xtensa.in.x Outdated
Comment thread xtensa-lx-rt/exception-esp32.x.template
Comment thread esp-hal/ld/sections/rwtext.x
Comment thread .github/workflows/ci.yml
Copilot AI review requested due to automatic review settings June 23, 2026 15:17

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.

Comment thread xtensa-lx-rt/xtensa.in.x Outdated
Comment thread xtensa-lx-rt/xtensa.in.x Outdated
MabezDev added 6 commits June 25, 2026 13:04
GNU ld and LLD interpret bare `. = <const>` assignments inside an output
section differently — GNU ld treats them as section-relative offsets,
LLD treats them as absolute addresses. The `.vectors` section in the
exception template relied on the section-relative behaviour, and the
combined `*(.literal .text .literal.* .text.*)` patterns relied on GNU
ld's pattern-order section sorting, which LLD does not perform.

Rework `.vectors` to use SUBALIGN(0x40) plus relative `. = . + N`
padding so the vector slot positions are derived from input section
sizes rather than absolute assignments, and split the combined
literal/text patterns into separate clauses so literals are always
emitted before the code that references them (required because Xtensa
L32R can only address literals at negative PC offsets).

The resulting binaries flash to the same load addresses and produce the
same number of esptool segments under both linkers.
With the previous split `*(.literal .literal.*) *(.text .text.*)`, every
literal pool across every archive was emitted before any code, so once
the wifi/BT blobs were linked the per-function `.literal.<f>` pools
ended up >256 KB from their own `.text.<f>` — past the L32R PC-relative
range — and the link failed with `R_XTENSA_SLOT0_OP out of range`.

Pull each Espressif archive in as its own block using the combined
`(.literal .text .literal.* .text.*)` pattern. Both GNU ld and LLD
preserve input-file order within a single pattern group, so GCC's
per-function literal/text pairs stay adjacent and every L32R inside an
archive resolves regardless of total image size. The catch-all keeps
the split form because rustc's Xtensa backend emits its `.literal`
after the function `.text.*` sections in each object.

LLD- and GCC-linked images of a minimal embassy_net + esp-radio app are
now byte-structure identical (same 6 esptool segments, same load
addresses, same sizes).
The split catch-all bunched all literals at the start of .text, pushing
late code past the 256 KB L32R window in large (radio) images. Use a
combined `*(...)` group so each function's literal pool stays adjacent to
its code, and pull the boot code's bare `.literal` pool and its two
consumers (`__pre_init` / `__post_init`) to the front so their L32R loads
stay in reach regardless of image size.
The comment claimed the trailing pad to 0x400 was expressed with
. = . + N, but no such pad exists — only the gap before
DoubleExceptionVector is padded. Correct the comment to match.
The SUBALIGN(0x40) rewrite of .vectors dropped the trailing pad, leaving
SIZEOF(.vectors) at 0x3c6 instead of 0x400. On ESP32-S3, esp32s3.x's
.rwdata_dummy reserves a DRAM hole of SIZEOF(.vectors) to keep IRAM code
off its physical DRAM mirror; under-reserving ~0x3a bytes let .data
overlap the SRAM mirror of .rwtext/vectors and corrupt memory at runtime.

Re-add the pad as `. = ALIGN(0x400)` (not the original bare `. = 0x400`,
which is absolute in LLD but section-relative in GNU ld). vectors_seg
origin is 0x400-aligned on every Xtensa chip, so ALIGN(0x400) yields a
0x400-byte .vectors identically under GNU ld and rust-lld.
- exception-esp32.x.template: ASSERT(SIZEOF(.vectors) == 0x400) restores the
  link-time overflow check the fixed `. = 0x40/0x80/...` offsets provided
  before the SUBALIGN switch; an oversized vector now fails the link instead
  of silently growing .vectors past its 0x400 slot.
- rwtext.x: remove trailing spaces on the blank line before _rwtext_start.
@MabezDev
MabezDev force-pushed the xtensa-lld-support branch from 89267a8 to b8242d8 Compare June 25, 2026 12:05
@MabezDev

Copy link
Copy Markdown
Member Author

/hil full --chips esp32,esp32s2,esp32s3

@github-actions

github-actions Bot commented Jun 25, 2026

Copy link
Copy Markdown

Triggered full HIL run for #5582.

Run: https://github.com/esp-rs/esp-hal/actions/runs/28169029481

Status update: HIL (full) run is still in progress or status unknown.

The .text catch-all in `text.x` already uses a single combined
`*(.literal .text .literal.* .text.*)` group so each object's literal
pool stays adjacent to its code, keeping every L32R load within the
256 KB window regardless of image size. The other Xtensa sections still
used the older split form (`*(.literal ...)` then `*(.text ...)`), which
bunches all literals at the section start.

Recombine them for consistency with `text.x`:
  - xtensa-lx-rt/xtensa.in.x: .text and .rwtext
  - esp-hal rwtext.x: .rwtext and the esp_rom_spiflash patch selectors
  - esp-hal rtc_fast.x / rtc_slow.x: .rtc_*.text

The rwtext/rtc segments are small RAM regions that never approach the
L32R window in practice, so this is correctness-by-construction rather
than a fix for an observed failure. The combined form links identically
under both GNU ld and LLD (both preserve input-file order within a
single group); the full xtensa-lld CI matrix (hello_world, embassy_dhcp,
bas_peripheral on esp32/s2/s3) links cleanly with rust-lld.
Copilot AI review requested due to automatic review settings June 25, 2026 12:30

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated 4 comments.

Comment thread .github/workflows/ci.yml
Comment thread .github/workflows/ci.yml
Comment thread .github/workflows/ci.yml
Comment thread .github/workflows/ci.yml
@MabezDev

Copy link
Copy Markdown
Member Author

/hil esp32 esp32s2 esp32s3

@github-actions

github-actions Bot commented Jun 25, 2026

Copy link
Copy Markdown

Triggered HIL run for #5582 (chips: esp32 esp32s2 esp32s3).

Run: https://github.com/esp-rs/esp-hal/actions/runs/28173502693

Status update: HIL (per-chip) run is still in progress or status unknown.

@MabezDev

Copy link
Copy Markdown
Member Author

S2 & S3 are green across the board, lets finally land this.

@MabezDev
MabezDev added this pull request to the merge queue Jun 25, 2026
Merged via the queue into main with commit 0d04588 Jun 25, 2026
25 checks passed
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.

4 participants