[RFC] Standardizing undefined symbol relocation retention in ELF ld.bfd

Hakan Candar hakancandar@protonmail.com
Tue Jul 1 21:10:31 GMT 2025


Hi all,

Just to clarify - the key issue here is whether unresolved symbols are being retained as dynamic relocations at link time, enabling them to be resolved at runtime (e.g., via LD_PRELOAD or shared libraries). This impacts use cases like symbol interposition and modular runtime loading, and my goal is to make this behavior more consistent and controllable across backends.

Best regards,
Hakan Candar


-------- Original Message --------
On 01/07/2025 23:52, Hakan Candar <hakancandar@protonmail.com> wrote:

>  Hi all,
>  
>  I've been working with ELF dynamic symbol resolution in ld.bfd and came
>  across some surprising inconsistencies when it comes to how undefined
>  symbols - both weak and strong - are handled across different backends
>  and versions.
>  
>  Currently, the behavior of undefined symbol retention varies not only
>  across architectures, but even across different binutils versions of the
>  same architecture. This leads to situations where the same source and
>  linker flags behave differently depending on target and toolchain
>  version, making it difficult for users to write portable and predictable
>  link lines.
>  
>  Here's a summary of the behavior I observed:
>  (Strong symbols were tested with --unresolved-symbols=ignore-all)
>  
>  Target     | Version | Keeps Weak | Keeps Strong | Accepts -z dynamic-undefined-weak
>  -----------+---------+------------+--------------+----------------------------------
>  x86-64     | 2.41+   | Yes        | No*          | Yes
>  aarch64    | 2.41    | Yes        | No           | No (warns)
>  aarch64    | 2.43    | Yes        | Yes          | No (warns)
>  aarch64    | 2.45    | Yes        | No           | No (warns)
>  riscv64    | 2.41    | Broken**   | Broken**     | No (warns)
>  riscv64    | 2.44    | Yes        | Yes          | No (warns)
>  ppc64le    | 2.41+   | Yes        | Yes          | Yes
>  m68k       | 2.40    | No***      | No***        | No (warns)
>  
>  *: Unresolved strong symbol can be retained with --export-dynamic, but not -fPIE -pie.
>  
>  **: The linker retained unresolved symbol relocations as dynamic relocations, correctly
>      emitted .got/.got.plt entries and the @plt thunk; however, the function call
>      erroneously jumped to address 0 instead of the expected func@plt stub.
>  
>  ***: Unresolved strong symbol can be retained with -fPIE -pie, but with --export-dynamic.
>  
>  To the best of my knowledge, the behavior described above reflects the
>  state of each backend as tested or inspected in the relevant binutils
>  versions. However, due to the evolving nature of these implementations,
>  some edge cases or version-specific nuances may differ slightly. I'm
>  happy to be corrected on any of these observations if needed.
>  
>  The flag `-z dynamic-undefined-weak` is supported only by a few
>  backends (e.g., x86-64, ppc64), while others warn or ignore it. Even
>  without the flag, some backends retain weak and/or strong undefined
>  symbols by default, leading to divergence in behavior.
>  
>  This inconsistency makes it difficult to reason about dynamic linking,
>  runtime symbol resolution (e.g., via LD_PRELOAD), or symbol stubbing
>  scenarios, especially across targets.
>  
>  **Proposal**
>  
>  I would like to propose centralizing the undefined symbol retention
>  policy for ELF targets inside `elflink.c`, and treating flags like
>  `-z dynamic-undefined-weak` (and a potential new flag `-z
>  dynamic-undefined` for strong symbols) in a uniform, target-agnostic
>  way.
>  
>  This would involve:
>    - Moving the decision logic for retaining undefined symbols to shared
>      code (e.g., elflink.c)
>    - Respecting per-backend defaults via a new backend flag
>    - Honoring user-specified flags to override the default (without
>      warnings)
>    - Adding test coverage for undefined weak/strong symbol handling on
>      multiple targets
>    - Avoiding behavior regressions by preserving current behavior unless
>      the user opts in
>  
>  This should not impact existing behavior unless flags are explicitly
>  used. The goal is to make ld.bfd more predictable and consistent across
>  targets, especially for projects relying on undefined symbol behavior
>  for runtime linking or modular design.
>  
>  I’d be happy to write and send an initial patch series implementing this
>  logic along with backend defaults, and a basic test suite to cover key cases.
>  I’m also open to feedback on flag naming, scope, or alternative approaches
>  if preferred.
>  
>  Please let me know if this direction makes sense, or if there are
>  concerns that I should be aware of before submitting patches.
>  
>  Best regards,  
>  Hakan Candar


More information about the Binutils mailing list