Skip to content

boards/sim: skip -no-pie on HOST_ARM64 to fix sim:nsh link on aarch64…#18888

Open
cjj66619 wants to merge 1 commit into
apache:masterfrom
cjj66619:patch-2
Open

boards/sim: skip -no-pie on HOST_ARM64 to fix sim:nsh link on aarch64…#18888
cjj66619 wants to merge 1 commit into
apache:masterfrom
cjj66619:patch-2

Conversation

@cjj66619
Copy link
Copy Markdown
Contributor

… host

boards/sim: skip -no-pie on HOST_ARM64 to fix sim:nsh link on aarch64 host

boards/sim/sim/sim/scripts/Make.defs adds -no-pie to ARCHCFLAGS / ARCHPICFLAGS / LDFLAGS for every 64-bit non-Mac sim build. The original comment ("To compile 64-bit Sim, adding no-pie is necessary to prevent linking errors but this may cause other issues on Ubuntu 20.") already flagged the workaround as fragile.

On HOST_ARM64 the option is in fact actively harmful. When gcc is asked to produce a non-PIE executable on aarch64 it switches the libgcc resolution path from the dynamic library
libgcc_s.so.1 to the static archive libgcc_s.a. Ubuntu's arm64 toolchain (and Debian / Raspbian arm64) does not ship libgcc_s.a (only libgcc_s.so.1), so the link aborts with:

/usr/bin/ld: cannot find -lgcc_s
/usr/bin/ld: cannot find -lgcc_s   (push-state / as-needed both fail)
collect2: error: ld returned 1 exit status

ld --verbose shows ld searching 20+ paths for libgcc_s.a, finding only libgcc_s.so (a linker script pointing at libgcc_s.so.1) which is invalid in non-PIE mode.

x86_64 Linux is unaffected because Ubuntu ships the static libgcc_s.a (or a compatible static-fallback library) in its amd64 libgcc-N-dev packaging. macOS, Windows and Cygwin go through completely different code paths and never reach this branch.

Gate the existing -no-pie block with ifneq ($(CONFIG_HOST_ARM64),y) so aarch64 hosts fall through to gcc's default PIE-aware link path, which works correctly. The default text-segment placement -Ttext-segment=0x40000000 and -Wl,--gc-sections (set in the common LDFLAGS just above this block) are honored regardless of PIE / non-PIE.

Verified on NVIDIA Jetson Orin (Ubuntu 20.04 L4T, GCC 9.4) and Raspberry Pi 4B (Debian 13 trixie, GCC 14.2):

$ ./build.sh sim:nsh -j$(nproc)
$ ./nuttx
NuttShell (NSH)
nsh> ostest
... [38 user_main stages, 14 PASS, 0 FAIL] ...
ostest_main: Exiting with status 0

x86_64 Linux behaviour is unchanged (the ifneq is false there, so the block is taken exactly as before).

Companion patch: arch/sim: rename nuttx libc memchr to avoid host glibc collision (independent fix needed on the same aarch64 hosts).

Summary

boards/sim/sim/sim/scripts/Make.defs unconditionally adds -no-pie / -Wl,-no-pie to every 64-bit non-macOS sim build (line 322-328). The block's own comment already flags it as fragile: "To compile 64-bit Sim, adding no-pie is necessary to prevent linking errors but this may cause other issues on Ubuntu 20." On Ubuntu / Debian aarch64 hosts this workaround is in fact actively broken — the build cannot link because gcc switches to looking for the static libgcc_s.a library which the Ubuntu/Debian arm64 toolchain does not ship.

This PR gates the existing -no-pie block on !CONFIG_HOST_ARM64, restoring sim:nsh build / run capability on aarch64 Linux hosts. x86_64 behaviour is byte-identical.

Impact

  • Affects every sim defconfig (sim:nsh, sim:nsh2, sim:smp, sim:bluetooth, sim:binder, sim:matter, ...) on a Linux aarch64 host.
  • Concrete environments reproduced: Ubuntu 20.04 L4T (NVIDIA Jetson Orin) and Debian 13 trixie (Raspberry Pi 4B).
  • ARM64-based developer workstations (Apple M1/M2 running Linux VMs, Ampere Altra, AWS Graviton, etc.) are also affected.

Root Cause

  1. Make.defs:322-328 adds ARCHCFLAGS += -no-pie, ARCHPICFLAGS += -no-pie, LDFLAGS += -Wl,-no-pie whenever (a) sim is 64-bit, (b) host is not macOS.
  2. -no-pie causes gcc's collect2 spec to inject the libgcc resolution from the non-PIE branch of the spec — which on aarch64 attempts to link against the static libgcc_s.a.
  3. Ubuntu / Debian arm64 packaging ships only the dynamic library (libgcc_s.so.1) and a linker-script alias (/usr/lib/gcc/aarch64-linux-gnu/9/libgcc_s.soGROUP ( libgcc_s.so.1 -lgcc )). There is no libgcc_s.a.
  4. The link fails with cannot find -lgcc_s after ld searches 20+ standard paths.
$ cc -v -fno-pic -mcmodel=large -Wl,-no-pie -o dummy dummy.c
... (collect2 invocation includes -lgcc_s but ld can't find static .a)
/usr/bin/ld: cannot find -lgcc_s
/usr/bin/ld: cannot find -lgcc_s
collect2: error: ld returned 1 exit status

Same cc command without -Wl,-no-pie succeeds and produces a valid PIE executable.

Fix

Wrap the existing 3-line block in ifneq ($(CONFIG_HOST_ARM64),y), with a comment explaining the aarch64-host packaging mismatch:

 else ifeq ($(CONFIG_HOST_MACOS),)
+ifneq ($(CONFIG_HOST_ARM64),y)
   # To compile 64-bit Sim, adding no-pie is necessary to prevent linking errors
   # but this may cause other issues on Ubuntu 20.
+  # NOTE: On HOST_ARM64 (Ubuntu aarch64), -no-pie forces ld to look for the
+  # static libgcc_s.a which is not packaged on Ubuntu's arm64 toolchain
+  # (only the shared libgcc_s.so.1 ships).  Skipping -no-pie lets gcc use
+  # the default PIE link path which works correctly on aarch64.
   ARCHCFLAGS += -no-pie
   ARCHPICFLAGS += -no-pie
   LDFLAGS += -Wl,-no-pie
 endif
+endif

After the patch aarch64 hosts fall through to gcc's default PIE link path, which works correctly. The default text-segment placement -Ttext-segment=0x40000000 and -Wl,--gc-sections (set in the common LDFLAGS above) are honored regardless of PIE / non-PIE.

Test results

Platform Status
NVIDIA Jetson Orin (Ubuntu 20.04 L4T aarch64, GCC 9.4) sim:nsh clean build, NSH prompt, 18.2 ms median boot, ostest 38 stages PASS
Raspberry Pi 4B (Debian 13 trixie aarch64, GCC 14.2) Jetson binary cross-runs ✅, ostest 38 stages PASS
x86_64 Linux ifneq is false → block taken unchanged → behaviour byte-identical

Detailed reproduction log + ld trace + bytecount diff in test-report.md.

Companion patch

This patch alone is not sufficient to build sim:nsh on Ubuntu aarch64 hosts; the nuttx.rel link also collides on the unrenamed nuttx-libc memchr. See companion PR: arch/sim: rename nuttx libc memchr to avoid host glibc collision (single-line addition to arch/sim/src/nuttx-names.in).

The two PRs are independently mergeable — each fix is a strict subset narrowing of an existing failure mode — but on aarch64 hosts you need both to get a working sim binary.

checkpatch

tools/checkpatch.sh -f boards/sim/sim/sim/scripts/Make.defs → ✔️ All checks pass.

@github-actions github-actions Bot added Size: XS The size of the change in this PR is very small Board: simulator labels May 16, 2026
Comment thread boards/sim/sim/sim/scripts/Make.defs Outdated
… host

boards/sim/sim/sim/scripts/Make.defs adds `-no-pie` to ARCHCFLAGS /
ARCHPICFLAGS / LDFLAGS for every 64-bit non-Mac sim build.  The
original comment ("To compile 64-bit Sim, adding no-pie is necessary
to prevent linking errors but this may cause other issues on
Ubuntu 20.") already flagged the workaround as fragile.

On HOST_ARM64 the option is in fact actively harmful.  When gcc is
asked to produce a non-PIE executable on aarch64 it switches the
libgcc resolution path from the dynamic library
`libgcc_s.so.1` to the static archive `libgcc_s.a`.  Ubuntu's
arm64 toolchain (and Debian / Raspbian arm64) **does not ship**
`libgcc_s.a` (only `libgcc_s.so.1`), so the link aborts with:

    /usr/bin/ld: cannot find -lgcc_s
    /usr/bin/ld: cannot find -lgcc_s   (push-state / as-needed both fail)
    collect2: error: ld returned 1 exit status

`ld --verbose` shows ld searching 20+ paths for `libgcc_s.a`,
finding only `libgcc_s.so` (a linker script pointing at
`libgcc_s.so.1`) which is invalid in non-PIE mode.

x86_64 Linux is unaffected because Ubuntu ships the static
`libgcc_s.a` (or a compatible static-fallback library) in its
amd64 libgcc-N-dev packaging.  macOS, Windows and Cygwin go
through completely different code paths and never reach this
branch.

Extend the existing `else ifeq ($(CONFIG_HOST_MACOS),)` exclusion
to also cover HOST_ARM64 by concatenating the two variables in the
condition: `else ifeq ($(CONFIG_HOST_MACOS)$(CONFIG_HOST_ARM64),)`.
The condition is true only when both variables are empty (i.e. on
a 64-bit non-macOS non-aarch64 Linux host), so aarch64 hosts fall
through to gcc's default PIE-aware link path, which works
correctly.  This concatenation idiom matches the style already
used elsewhere in the file (suggested by @xiaoxiang781216 in
review).  The default text-segment placement
`-Ttext-segment=0x40000000` and `-Wl,--gc-sections` (set in the
common LDFLAGS just above this block) are honored regardless of
PIE / non-PIE.

Verified on NVIDIA Jetson Orin (Ubuntu 20.04 L4T, GCC 9.4) and
Raspberry Pi 4B (Debian 13 trixie, GCC 14.2):

  $ ./build.sh sim:nsh -j$(nproc)
  $ ./nuttx
  NuttShell (NSH)
  nsh> ostest
  ... [38 user_main stages, 14 PASS, 0 FAIL] ...
  ostest_main: Exiting with status 0

x86_64 Linux behaviour is unchanged (the concatenation is empty
there, so the block is taken exactly as before).

Companion patch: arch/sim: rename nuttx libc memchr to avoid host
glibc collision (independent fix needed on the same aarch64 hosts).

Signed-off-by: Jinji Cui <113000688+cjj66619@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Board: simulator Size: XS The size of the change in this PR is very small

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants