Extract an archive member to satisfy a DSO undef

Fangrui Song i@maskray.me
Fri Aug 13 19:11:01 GMT 2021

ELF linkers extract an archive member to satisfy an undefined symbol from a
shared object. (Do Unix linkers have this behavior?) Here is an example:

   echo '.globl _start; _start: call bb' > a.s
   echo '.globl bb; bb: call cc' > b.s
   echo '.globl cc; cc: nop' > c.s
   cc -c a.s b.s c.s
   rm -f c.a && ar rc c.a c.o
   ld -shared -z defs c.o -o c.so
   ld -shared -z defs b.o ./c.so -o b.so
   ld -rpath=. a.o b.so c.a

a.out defines cc. ld.bfd, gold, and ld.lld have the same behavior.

This behavior intrigued me because link.exe (PE/COFF) and ld64 (Mach-O) don't
inspect undefined symbols in DLL/dylib for symbol resolution.

   # On macOS
   echo '.globl _main; _main: call bb' > a.s
   echo '.globl bb; bb: call cc' > b.s
   echo '.globl cc; cc: nop' > c.s
   clang --target=x86_64-apple-darwin -c a.s b.s c.s
   rm -f c.a && ar rc c.a c.o
   clang -dynamiclib c.o -o c.dylib
   clang -dynamiclib b.o c.dylib -o b.dylib
   clang a.o b.dylib c.a
   # a.out doesn't define or reference cc

Does anyone know the design consideration behind having or not having this

Below lists some thoughts of mine.
You probably want to think for a few minutes before looking at mine:) I want
different thoughts.


We know that an undef from a DSO can interact with a .o definition.  The .o
definition needs to be exported to .dynsym in case the DSO relies on symbols in
the executable. (PE/COFF and Mach-O don't need/have the behavior.)

This does not necessarily generalize to the interaction between a DSO and an

If a DSO linked into the final executable has incomplete DT_NEEDED entries, I
can imagine that not extracting archive members to satisfy a DSO undef can cause
ld.so "unresolved symbol" errors. (--no-allow-shlib-undefined can flag similar
fragile links.) However, if every DSO is linked with -z defs (--no-undefined),
not extracting archive members appears to be very robust. (My summary of [1].)


In my `ld -rpath=. a.o b.so c.a` ELF example, if we make c.so DF_SYMBOLIC,
a.out will have definitions trying to interpose c.so definitions in vain.
Linkers seem to have no ability detect such one definition rule violation.
(One definition rule is C++'s, but we can reuse the concept: multiple
definitions have more or less unreliability.)


In [2], I raised the point that it can be difficult to make --no-undefined happy
because all linkers as I know don't support an option listing allowed undefined
symbols. Mach-O ld64 defaults to `-undefined error` but can switch to
`-undefined suppress` for an ELFish behavior.

Related discussions:

[1] https://bugs.llvm.org/show_bug.cgi?id=43554
[2] https://reviews.llvm.org/D108006 (propose --no-search-static-libs-for-shlib-undefined to ld.lld)

More information about the Binutils mailing list