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
behavior?

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
archive.

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