[PATCH 0/3] ELF: Improve undefined symbol retention for strong symbols

Hakan Candar hakan@envs.net
Wed Jul 16 16:03:20 GMT 2025


Hi all,

This patch series improves undefined symbol retention in ELF links for
strong symbols, specifically when `-z dynamic-undefined-weak` is given.

Today, `ld.bfd` inconsistently handles undefined strong symbols across
targets, even with `--unresolved-symbols=ignore-all` and 
`-z dynamic-undefined-weak`. While some targets treat strong undefineds
like weaks (emitting dynamic relocations), others prune them completely.
This behavior differs from LLD, which consistently retains both.

After an earlier RFC [1] and a round of testing, I’ve narrowed the scope
of the patch significantly. Rather than centralizing backend behavior
entirely, we now only:

  1. Move `-z dynamic-undefined-weak` flag handling into ELF shared code
     (from individual emulparams).
  2. Extend undefined symbol retention logic in `elflink.c` to include
     strong undefineds (in addition to weaks).
  3. Add a test case to ensure that strong undefined symbols are
     preserved when explicitly allowed.

This change has no effect unless `-z dynamic-undefined-weak` is used,
and does not touch backend-specific pruning logic.

To validate the patch, I tested symbol retention under various targets.
The table below shows behavior when the flag is explicitly passed:

Target        | Version            | Keeps Weak (-z dyn)  | Keeps Strong (-z dyn)  | Keeps Weak (-z nodyn)  | Keeps Strong (-z nodyn)  | Accepts -z dyn-und-weak
--------------+--------------------+----------------------+------------------------+------------------------+--------------------------+-------------------------
x86_64        | 2.44.50.20250716   | Yes                  | Yes                    | No                     | No                       | Yes
i386          | 2.44.50.20250716   | Yes                  | Yes                    | No                     | No                       | Yes
aarch64       | 2.44.50.20250716   | Yes                  | Yes                    | No                     | No                       | Yes
arm           | 2.44.50.20250716   | Yes                  | Yes                    | No                     | No                       | Yes
ppc64le       | 2.44.50.20250716   | Yes                  | Yes                    | No                     | No                       | Yes
ppc           | 2.44.50.20250716   | Yes                  | Yes                    | No                     | No                       | Yes
riscv64       | 2.44.50.20250716   | Yes                  | Yes                    | No                     | No                       | Yes
mips64        | 2.44.50.20250716   | Yes                  | Yes                    | Fail* (--shared)       | Fail* (--shared)         | Yes
hppa          | 2.44.50.20250716   | Yes                  | Yes                    | No                     | Fail**                   | Yes
ia64          | 2.44.50.20250716   | Yes                  | Broken**               | No                     | No                       | Yes
m68k          | 2.44.50.20250716   | No                   | No                     | No                     | No                       | Yes
sh4           | 2.44.50.20250716   | No                   | No                     | No                     | No                       | Yes

*: MIPS asserts and exits when it comes across a relocation against
   an undefined symbol, only when generating a shared library and
   -z nodynamic-undefined-weak is specified.

**: HPPA currently errors out on non-dynamic strong undefined symbol,
    whereas it should have resolved to zero. This will later be addressed.

*** IA-64 generates PLT for strong undefined symbol, and the dynamic
    relocation is preserved, but the PLT is not called.

Notably, `m68k`, and `sh4` prune symbols even when the user
explicitly requests retention. This contradicts the intent of the `-z`
flag and the gABI. I investigated `sh4` in particular and managed to
correct retention locally, but encountered unrelated regressions in the
testsuite, so I’ve moved that fix out of scope for now. I plan to send
incremental patches for those backends after this series.

This patch is intentionally minimal and should be low-risk. It brings
`ld.bfd` behavior closer to LLD and improves consistency for developers
relying on dynamic symbol resolution across targets.

Thanks for your time and feedback.

Best regards,
Hakan Candar

[1] https://sourceware.org/pipermail/binutils/2025-July/142081.html


Hakan Candar (3):
  ld/ELF: Move -z dynamic-undefined-weak flag handling to elf.em
  bfd/ELF: Retain strong undefined symbols under -z
    dynamic-undefined-weak
  ld/testsuite: Add shared test logic for undefined symbol retention

 bfd/bfd-in2.h                              |  8 ++
 bfd/elf-bfd.h                              | 10 +++
 bfd/elflink.c                              |  2 +-
 bfd/linker.c                               |  9 ++
 ld/NEWS                                    | 10 +++
 ld/emulparams/dynamic_undefined_weak.sh    | 15 ----
 ld/emulparams/elf32_x86_64.sh              |  1 -
 ld/emulparams/elf32ppccommon.sh            |  1 -
 ld/emulparams/elf_i386.sh                  |  1 -
 ld/emulparams/elf_i386_be.sh               |  1 -
 ld/emulparams/elf_i386_ldso.sh             |  1 -
 ld/emulparams/elf_i386_vxworks.sh          |  1 -
 ld/emulparams/elf_iamcu.sh                 |  1 -
 ld/emulparams/elf_x86_64.sh                |  1 -
 ld/emultempl/elf.em                        |  7 ++
 ld/ld.texi                                 |  9 +-
 ld/lexsup.c                                |  3 +
 ld/testsuite/ld-undefined/fundef.s         |  4 +
 ld/testsuite/ld-undefined/undef-common.tcl | 96 ++++++++++++++++++++++
 ld/testsuite/ld-undefined/undefined.exp    | 73 ++++++++++++----
 ld/testsuite/ld-undefined/weak-fundef.s    |  3 +
 ld/testsuite/ld-undefined/weak-undef.exp   | 94 ++++-----------------
 22 files changed, 231 insertions(+), 120 deletions(-)
 delete mode 100644 ld/emulparams/dynamic_undefined_weak.sh
 create mode 100644 ld/testsuite/ld-undefined/undef-common.tcl

-- 
2.47.0



More information about the Binutils mailing list