[RFC] Standardizing undefined symbol relocation retention in ELF ld.bfd
Hakan Candar
hakancandar@protonmail.com
Wed Jul 2 07:09:31 GMT 2025
Thanks for the detailed breakdown and the links, I really appreciate it.
Below are the simple commands I used to reproduce the inconsistencies
across back-ends and versions. Feel free to tweak or expand them as
needed.
--------------------------------- strong ---------------------------------
/* strong.c */
extern void somefunc (void);
int main () { somefunc (); return 0; }
/* link & inspect */
gcc strong.c \
-Wl,--unresolved-symbols=ignore-all \
-Wl,-z,dynamic-undefined-weak \
-o strong
objdump -R strong | grep somefunc # relocation retained?
objdump --disassemble=main strong # plt called correctly?
---------------------------------- weak ----------------------------------
/* weak.c */
extern void __attribute__((weak)) somefunc (void);
int main () { somefunc (); return 0; }
/* link & inspect */
gcc weak.c \
-Wl,--unresolved-symbols=ignore-all \
-Wl,-z,dynamic-undefined-weak \
-o weak
objdump -R weak | grep somefunc
objdump --disassemble=main weak
--------------------------- runtime verification -------------------------
/* stub.c */
void somefunc (void) { }
/* build preload stub */
gcc -shared -fPIC stub.c -o libstub.so
# native run (in my case, x86-64 host)
LD_PRELOAD=./libstub.so ./strong
LD_PRELOAD=./libstub.so ./weak
# cross-run (riscv64, aarch64, ppc64le, m68k)
LD_PRELOAD=./libstub.so qemu-user-<arch> ./strong
LD_PRELOAD=./libstub.so qemu-user-<arch> ./weak
---------------------------------------------------------------------------
With older riscv64 (binutils-2.41) the PLT/GOT entries existed but the
call in main jumped to 0 instead of somefunc@plt. In 2.44 this is fixed.
x86-64 prunes strong undefineds unless
--export-dynamic is used, while ppc64le keeps both weak and strong.
m68k prunes both strong and weak unless -fPIE and -pie is specified.
Please let me know if you need additional repro steps or if there are
edge cases I’ve missed. Happy to iterate.
Best regards,
Hakan Candar
On 02/07/2025 07:20, Fangrui Song <maskray@sourceware.org> wrote:
> Thanks for the table. Could you share the command used for testing?
> I explored the behavior when writing
> https://maskray.me/blog/2021-04-25-weak-symbol and recently revisited
> it, confirming the inconsistency.
>
> For LLD I recently added -z [no]dynamic-undefined-weak for all
> supported targets.
>
> * Static -no-pie: no-op
> * Dynamic -no-pie: nodynamic-undefined-weak suppresses GLOB_DAT/JUMP_SLOT
> * Static -pie: dynamic-undefined-weak generates
> ABS/GLOB_DAT/JUMP_SLOT.
> https://discourse.llvm.org/t/lld-weak-undefined-symbols-in-vdso-only/86749
> * Dynamic -pie: nodynamic-undefined-weak suppresses ABS/GLOB_DAT/JUMP_SLOT
>
> Dynamic: -shared is specified, or there is at least one link-time shared object.
>
> (The -no-pie (!ctx.arg.isPic in isStaticLinkTimeConstant) behavior
> will likely change in the future.)
>
> LLD treats undefined non-weak symbols the same as undefined weak
> symbols. If we ever add -z dynamic-undefined, it will be an alias for
> -z dynamic-undefined-weak.
>
More information about the Binutils
mailing list