[lld] [llvm] WIP: [LLD][COFF] Make unresolved symbol search behavior compliant with MSVC link.exe (PR #85290)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Mar 25 11:18:19 PDT 2024
================
@@ -562,25 +565,120 @@ std::pair<Symbol *, bool> SymbolTable::insert(StringRef name, InputFile *file) {
return result;
}
+static LazyIntrusiveNode *lazyNode(Symbol *s) {
+ if (auto *sym = dyn_cast<LazyArchive>(s))
+ return &sym->node;
+ if (auto *sym = dyn_cast<LazyObject>(s))
+ return &sym->node;
+ return nullptr;
+}
+
+static ArchiveFile *lazyParent(InputFile *f) {
+ if (!f)
+ return nullptr;
+ if (auto *obj = dyn_cast<ObjFile>(f))
+ return obj->parent;
+ if (auto *obj = dyn_cast<BitcodeFile>(f))
+ return obj->parent;
+ return nullptr;
+}
+
+static ArchiveFile *lazyArchive(Symbol *s) {
+ if (auto *sym = dyn_cast<LazyArchive>(s))
+ return sym->file;
+ if (auto *sym = dyn_cast<LazyObject>(s))
+ return lazyParent(sym->file);
+ return nullptr;
+}
+
+// The search behavior for undefined symbols is different when the OBJ
+// was pulled from an archive (LIB). This is documented here:
+// https://learn.microsoft.com/en-us/cpp/build/reference/link-input-files?view=msvc-170
+// "Object files on the command line are processed in the order they
+// appear on the command line. Libraries are searched in command line
+// order as well, with the following caveat: Symbols that are unresolved
+// when bringing in an object file from a library are searched for in
+// that library first, and then the following libraries from the command
+// line and /DEFAULTLIB (Specify default library) directives, and then
+// to any libraries at the beginning of the command line."
+static Symbol *searchArchiveSymbol(Symbol *s, ArchiveFile *pivot) {
+ auto &Alloc = getSpecificAllocSingleton<SymbolUnion>().Allocator;
+ Symbol *curr = s;
+ for (;;) {
+ if (lazyArchive(curr)->CmdLineIndex >= pivot->CmdLineIndex)
+ return curr;
+ uint32_t next = lazyNode(curr)->next;
+ if (!next)
+ break;
+ curr = reinterpret_cast<LazyArchive *>(
+ Alloc.fromAlignedIndex<SymbolUnion>(next));
+ }
+ return s;
+}
+
Symbol *SymbolTable::addUndefined(StringRef name, InputFile *f,
bool isWeakAlias) {
auto [s, wasInserted] = insert(name, f);
if (wasInserted || (s->isLazy() && isWeakAlias)) {
replaceSymbol<Undefined>(s, name);
return s;
}
- if (s->isLazy())
+ if (s->isLazy()) {
+ if (s->pendingArchiveLoad)
+ return s;
+ if (ArchiveFile *parent = lazyParent(f)) {
+ // We're placing a undefined symbol from an archive OBJ. The rules are
+ // different than regular OBJs on the command-line.
+ Symbol *selected = searchArchiveSymbol(s, parent);
+ forceLazy(selected);
+ // Now that we have selected a symbol, we don't need the linked list of
+ // `LazyArchive`s anymore. Collapse to the selected symbol.
+ if (s != selected)
+ memcpy(s, selected, sizeof(SymbolUnion));
+ *lazyNode(s) = LazyIntrusiveNode();
+ return s;
+ }
+ // We're placing a undefined symbol from a command-line OBJ.
forceLazy(s);
+ }
return s;
}
+// This creates a linked list of archives where a specific symbol was seen.
+// We later walk that list if a undefined symbol needs to be resolved from an
----------------
sylvain-audi wrote:
typo "if a undefined" -> "if an undefined"
https://github.com/llvm/llvm-project/pull/85290
More information about the llvm-commits
mailing list