Skip to content

Make Xtensa linker scripts compatible with rust-lld#5582

Open
MabezDev wants to merge 4 commits into
mainfrom
xtensa-lld-support
Open

Make Xtensa linker scripts compatible with rust-lld#5582
MabezDev wants to merge 4 commits into
mainfrom
xtensa-lld-support

Conversation

@MabezDev
Copy link
Copy Markdown
Member

@MabezDev MabezDev commented May 17, 2026

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
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

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.

SECTIONS {

.vectors :
.vectors : SUBALIGN(0x40)
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Literally would have never found this by myself, makes what we want to do here a lot easier!

@bugadani
Copy link
Copy Markdown
Contributor

bugadani commented May 17, 2026

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
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

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
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

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
Copy link
Copy Markdown

github-actions Bot commented May 29, 2026

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
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

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 added 4 commits May 29, 2026 20:34
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.
@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
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.

3 participants