When parsing an object file, LLD interleaves undefined symbol resolution (which
may recursively fetch other lazy objects) with defined symbol resolution.
This may lead to surprising results, e.g. if an object file defines currently
undefined symbols and references another lazy symbol, we may interleave defined
symbols with the lazy fetch, potentially leading to the defined symbols
resolving to different files.
As an example, if both a.a(a.o) and a.a(b.o) define foo (not in COMDAT
group, or in different COMDAT groups) and __profd_foo (in COMDAT group
__profd_foo). LLD may resolve foo to a.a(a.o) and __profd_foo to
b.a(b.o), i.e. different files.
parse ArchiveFile a.a entry fetches a.a(a.o) parse ObjectFile a.o define entry define foo reference b b fetches a.a(b.o) parse ObjectFile b.o define prevailing __profd_foo define (ignored) non-prevailing __profd_foo
Assuming a set of interconnected symbols are defined all or none in several lazy
objects. Arguably making them resolve to the same file is preferable than making
them resolve to different files (some are lazy objects).
The main argument favoring the new behavior is the stability. The relative order
between a defined symbol and an undefined symbol does not change the symbol
resolution behavior. Only the relative order between two undefined symbols can
affect fetching behaviors.
The real world case is reduced from a Fuchsia PGO usage: a.a(a.o) has a
constructor within COMDAT group C5 while a.a(b.o) has a constructor within
COMDAT group C2. Because they use different group signatures, they are not
de-duplicated. It is not entirely whether Clang behavior is entirely conforming.
LLD selects the PGO counter section (__profd_*) from a.a(b.o) and the
constructor section from a.a(a.o). The __profd_* is a SHF_LINK_ORDER section
linking to its own non-prevailing constructor section, so LLD errors
sh_link points to discarded section. This patch fixes the error.
I've seen quite a few objects with more than 8 undefined symbols, particularly older projects. Is it worth running a quick experiment to see what the distribution is like? For example the undefined symbols per object in a clang/llvm build.