Skip to content

Commit c75eac7

Browse files
authored
[LLD][COFF] Don't dllimport from static libraries (#134443)
This reverts commit 6a1bdd9 and re-instate behavior that matches what MSVC link.exe does, that is, error out when trying to dllimport a symbol from a static library. A hint is now displayed in stdout, mentioning that we should rather dllimport the symbol from a import library. Fixes #131807
1 parent 4b90f24 commit c75eac7

6 files changed

+74
-42
lines changed

lld/COFF/Driver.cpp

+2-4
Original file line numberDiff line numberDiff line change
@@ -2663,10 +2663,8 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
26632663
createECExportThunks();
26642664

26652665
// Resolve remaining undefined symbols and warn about imported locals.
2666-
ctx.forEachSymtab([&](SymbolTable &symtab) {
2667-
while (symtab.resolveRemainingUndefines())
2668-
run();
2669-
});
2666+
ctx.forEachSymtab(
2667+
[&](SymbolTable &symtab) { symtab.resolveRemainingUndefines(); });
26702668

26712669
if (errorCount())
26722670
return;

lld/COFF/SymbolTable.cpp

+12-8
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,17 @@ void SymbolTable::reportUndefinedSymbol(const UndefinedDiag &undefDiag) {
231231
}
232232
if (numDisplayedRefs < numRefs)
233233
diag << "\n>>> referenced " << numRefs - numDisplayedRefs << " more times";
234+
235+
// Hints
236+
StringRef name = undefDiag.sym->getName();
237+
if (name.consume_front("__imp_")) {
238+
Symbol *imp = find(name);
239+
if (imp && imp->isLazy()) {
240+
diag << "\nNOTE: a relevant symbol '" << imp->getName()
241+
<< "' is available in " << toString(imp->getFile())
242+
<< " but cannot be used because it is not an import library.";
243+
}
244+
}
234245
}
235246

236247
void SymbolTable::loadMinGWSymbols() {
@@ -432,11 +443,10 @@ void SymbolTable::reportUnresolvable() {
432443
reportProblemSymbols(undefs, /*localImports=*/nullptr, true);
433444
}
434445

435-
bool SymbolTable::resolveRemainingUndefines() {
446+
void SymbolTable::resolveRemainingUndefines() {
436447
llvm::TimeTraceScope timeScope("Resolve remaining undefined symbols");
437448
SmallPtrSet<Symbol *, 8> undefs;
438449
DenseMap<Symbol *, Symbol *> localImports;
439-
bool foundLazy = false;
440450

441451
for (auto &i : symMap) {
442452
Symbol *sym = i.second;
@@ -481,11 +491,6 @@ bool SymbolTable::resolveRemainingUndefines() {
481491
imp = findLocalSym(*mangledName);
482492
}
483493
}
484-
if (imp && imp->isLazy()) {
485-
forceLazy(imp);
486-
foundLazy = true;
487-
continue;
488-
}
489494
if (imp && isa<Defined>(imp)) {
490495
auto *d = cast<Defined>(imp);
491496
replaceSymbol<DefinedLocalImport>(sym, ctx, name, d);
@@ -513,7 +518,6 @@ bool SymbolTable::resolveRemainingUndefines() {
513518
reportProblemSymbols(
514519
undefs, ctx.config.warnLocallyDefinedImported ? &localImports : nullptr,
515520
false);
516-
return foundLazy;
517521
}
518522

519523
std::pair<Symbol *, bool> SymbolTable::insert(StringRef name) {

lld/COFF/SymbolTable.h

+1-4
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,7 @@ class SymbolTable {
6767
// Try to resolve any undefined symbols and update the symbol table
6868
// accordingly, then print an error message for any remaining undefined
6969
// symbols and warn about imported local symbols.
70-
// Returns whether more files might need to be linked in to resolve lazy
71-
// symbols, in which case the caller is expected to call the function again
72-
// after linking those files.
73-
bool resolveRemainingUndefines();
70+
void resolveRemainingUndefines();
7471

7572
// Load lazy objects that are needed for MinGW automatic import and for
7673
// doing stdcall fixups.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# REQUIRES: x86
2+
3+
# Pulling in on both a dllimport symbol and a static symbol should only warn.
4+
# RUN: split-file %s %t.dir
5+
# RUN: llvm-mc --filetype=obj -triple=x86_64-windows-msvc %t.dir/other.s -o %t.other.obj
6+
# RUN: llvm-mc --filetype=obj -triple=x86_64-windows-msvc %t.dir/main.s -o %t.main.obj
7+
# RUN: llvm-lib %t.other.obj -out:%t.other.lib
8+
# RUN: lld-link %t.other.lib %t.main.obj -out:%t.dll -dll 2>&1 | FileCheck %s
9+
10+
CHECK: warning: {{.*}} locally defined symbol imported: foo {{.*}} [LNK4217]
11+
12+
#--- other.s
13+
.text
14+
.globl other
15+
.globl foo
16+
other:
17+
ret
18+
foo:
19+
ret
20+
#--- main.s
21+
.text
22+
.global _DllMainCRTStartup
23+
_DllMainCRTStartup:
24+
call *other(%rip)
25+
call *__imp_foo(%rip)
26+
ret

lld/test/COFF/imports-static-lib.test

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# REQUIRES: x86
2+
3+
# Ensure that we don't import dllimport symbols from static (non-import) libraries
4+
# RUN: split-file %s %t.dir
5+
# RUN: llvm-mc --filetype=obj -triple=x86_64-windows-msvc %t.dir/foo.s -o %t.foo.obj
6+
# RUN: llvm-mc --filetype=obj -triple=x86_64-windows-msvc %t.dir/main.s -o %t.main.obj
7+
# RUN: llvm-lib %t.foo.obj -out:%t.foo.lib
8+
# RUN: not lld-link %t.foo.lib %t.main.obj -out:%t.dll -dll 2>&1 | FileCheck %s
9+
10+
CHECK: error: undefined symbol: __declspec(dllimport) foo
11+
CHECK: NOTE: a relevant symbol 'foo' is available in {{.*}}.foo.lib but cannot be used because it is not an import library.
12+
13+
# Now do the same thing, but import the symbol from a import library.
14+
# RUN: llvm-mc --filetype=obj -triple=x86_64-windows-msvc %t.dir/foo_dll_main.s -o %t.foo_dll_main.obj
15+
# RUN: lld-link /out:%t.dll /dll %t.foo.obj %t.foo_dll_main.obj /export:foo /implib:%t.foo.imp.lib
16+
# RUN: lld-link %t.main.obj %t.foo.imp.lib -out:%t.exe -dll
17+
18+
#--- foo.s
19+
.text
20+
.globl foo
21+
foo:
22+
ret
23+
#--- foo_dll_main.s
24+
.text
25+
.global _DllMainCRTStartup
26+
_DllMainCRTStartup:
27+
ret
28+
#--- main.s
29+
.text
30+
.global _DllMainCRTStartup
31+
_DllMainCRTStartup:
32+
call *__imp_foo(%rip)
33+
ret

lld/test/COFF/undefined_lazy.test

-26
This file was deleted.

0 commit comments

Comments
 (0)