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

Jan Beulich jbeulich@suse.com
Wed Jul 2 07:59:09 GMT 2025


On 01.07.2025 22:52, Hakan Candar wrote:
> 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)

As a general comment - for what actions to take, the state of the present
master branch is what matters. Older versions' behaviors are of only
academic interest from that perspective. Hence the (perhaps nit-picky)
comments on some of the table entries below.

> 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)

I.e. there's a regression here? Unless this was a deliberate move back to
earlier behavior, I think this would better be taken care of before 2.45
goes out. Cc-ing Nick and the Arm64 maintainers.

> riscv64    | 2.41    | Broken**   | Broken**     | No (warns)
> riscv64    | 2.44    | Yes        | Yes          | No (warns)

I expect you mean 2.44+ here, following the spelling used for other
targets? Or is there yet something else wrong in current master?

> ppc64le    | 2.41+   | Yes        | Yes          | Yes
> m68k       | 2.40    | No***      | No***        | No (warns)

And again presumably 2.40+?

> *: 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.

Absolutely. Target specific code should come into play here only if a
psABI deliberately overrides gABI.

> 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

I'm not sure about this one - anything violating involved gABI rules
(hopefully they don't leave room for interpretation) would better be
fixed as default behavior, if necessary providing options to revert to
prior (bogus) behavior.

Jan


More information about the Binutils mailing list