Skip to content

[lld][coff] undefined symbols from lazy-loaded archives #107365

Open
@glandium

Description

@glandium

STR:

Expected result:

  • Linkage fails because of a missing file (-reproduce didn't store the manifest file, you may want to edit the response file to remove the manifest-related flags, in which case the expected result is a successful link)

Actual result:

lld-link: error: undefined symbol: __declspec(dllimport) _wassert
>>> referenced by /tmp/g/third_party/rust/whatsys/c/windows.c:38
>>>               libwhatsys-f4cc7b72e53ee839.rlib(db3b6bfb95261072-windows.o):(get_os_release)

lld-link: error: undefined symbol: __declspec(dllimport) wcscpy
>>> referenced by /tmp/g/third_party/rust/lmdb-rkv-sys/lmdb/libraries/liblmdb/mdb.c:4238
>>>               liblmdb_sys-564cd906496499b4.rlib(7b4e66c3aa61e8a8-mdb.o):(mdb_fopen)

lld-link: error: undefined symbol: __declspec(dllimport) _aligned_malloc
>>> referenced by /tmp/g/third_party/rust/lmdb-rkv-sys/lmdb/libraries/liblmdb/mdb.c:9324
>>>               liblmdb_sys-564cd906496499b4.rlib(7b4e66c3aa61e8a8-mdb.o):(mdb_env_copyfd1)

lld-link: error: undefined symbol: __declspec(dllimport) _aligned_free
>>> referenced by /tmp/g/third_party/rust/lmdb-rkv-sys/lmdb/libraries/liblmdb/mdb.c:9425
>>>               liblmdb_sys-564cd906496499b4.rlib(7b4e66c3aa61e8a8-mdb.o):(mdb_env_copyfd1)

What happens is that the symbols, by the time resolveRemainingUndefines is called, are still undefined, but isLazy() is true for them, and resolveRemainingUndefines doesn't handle that case.

A crude retry, like the following, works around the issue:

diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp
index 3ef9fa3f65c6..46307a386328 100644
--- a/lld/COFF/Driver.cpp
+++ b/lld/COFF/Driver.cpp
@@ -2595,6 +2595,8 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
 
   // Resolve remaining undefined symbols and warn about imported locals.
   ctx.symtab.resolveRemainingUndefines();
+  run();
+  ctx.symtab.resolveRemainingUndefines();
   if (errorCount())
     return;
 
diff --git a/lld/COFF/SymbolTable.cpp b/lld/COFF/SymbolTable.cpp
index bb7583bb9a7d..5301a7af9c92 100644
--- a/lld/COFF/SymbolTable.cpp
+++ b/lld/COFF/SymbolTable.cpp
@@ -501,6 +501,10 @@ void SymbolTable::resolveRemainingUndefines() {
     // This odd rule is for compatibility with MSVC linker.
     if (name.starts_with("__imp_")) {
       Symbol *imp = find(name.substr(strlen("__imp_")));
+      if (imp && imp->isLazy()) {
+        forceLazy(imp);
+        continue;
+      }
       if (imp && isa<Defined>(imp)) {
         auto *d = cast<Defined>(imp);
         replaceSymbol<DefinedLocalImport>(sym, ctx, name, d);

But somehow, there is some non-determinism, as when running the command repeatedly, sometimes, it fails with strdup marked as undefined symbol.

Cc: @mstorsjo

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions