Skip to content

Commit f2d6d74

Browse files
authored
[llvm-dlltool] Fix renamed imports without a separate regular import entry (#98229)
Normally, when doing renamed imports, we do this by providing a weak alias, towards another regular import, for the symbol we want to actually import. In a def file, this looks like this: regularfunc renamedfunc == regularfunc However, if we want to link against a function in a DLL, where we (intentionally) don't provide a regular import for that symbol with the name in its DLL, doing the renamed import with a weak alias doesn't work, as there's no symbol that the weak alias can point towards. We can't make up such an import either, as we may intentionally not want to provide a regular import for that name. This situation can either be resolved by using the "long" import library format (as e.g. produced by GNU dlltool), or by using the new short import library name type "export as". This patch implements it by using the "export as" name type. When producing a renamed import, defer emitting it until all regular imports have been produced. If the renamed import refers to a symbol that does exist as a regular import entry, produce a weak alias, just as before. (This implementation also avoids needing to know whether the symbol that the alias points towards actually is prefixed or not, too.) If the renamed import points at a symbol that isn't otherwise available (or is available as a renamed symbol itself), generate an "export as" import entry. This name type is new, and is normally used in ARM64EC import libraries, but can also be used for other architectures.
1 parent 4469650 commit f2d6d74

File tree

7 files changed

+96
-32
lines changed

7 files changed

+96
-32
lines changed

lld/test/COFF/lib.test

+8-8
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
11
# RUN: lld-link /machine:x64 /def:%S/Inputs/library.def /out:%t.lib
22
# RUN: llvm-nm %t.lib | FileCheck %s
33

4+
CHECK: 00000000 R __imp_constant
5+
CHECK: 00000000 R constant
6+
7+
CHECK: 00000000 D __imp_data
8+
9+
CHECK: 00000000 T __imp_function
10+
CHECK: 00000000 T function
11+
412
CHECK: 00000000 a @comp.id
513
CHECK: 00000000 a @feat.00
614
CHECK: 00000000 W alias
@@ -11,11 +19,3 @@ CHECK: 00000000 a @feat.00
1119
CHECK: 00000000 W __imp_alias
1220
CHECK: U __imp_function
1321

14-
CHECK: 00000000 R __imp_constant
15-
CHECK: 00000000 R constant
16-
17-
CHECK: 00000000 D __imp_data
18-
19-
CHECK: 00000000 T __imp_function
20-
CHECK: 00000000 T function
21-

llvm/include/llvm/Object/COFFImportFile.h

+4-5
Original file line numberDiff line numberDiff line change
@@ -135,11 +135,10 @@ struct COFFShortExport {
135135
/// linking both ARM64EC and pure ARM64 objects, and the linker will pick only
136136
/// the exports relevant to the target platform. For non-hybrid targets,
137137
/// the NativeExports parameter should not be used.
138-
Error writeImportLibrary(StringRef ImportName, StringRef Path,
139-
ArrayRef<COFFShortExport> Exports,
140-
COFF::MachineTypes Machine, bool MinGW,
141-
ArrayRef<COFFShortExport> NativeExports = std::nullopt,
142-
bool AddUnderscores = true);
138+
Error writeImportLibrary(
139+
StringRef ImportName, StringRef Path, ArrayRef<COFFShortExport> Exports,
140+
COFF::MachineTypes Machine, bool MinGW,
141+
ArrayRef<COFFShortExport> NativeExports = std::nullopt);
143142

144143
} // namespace object
145144
} // namespace llvm

llvm/lib/Object/COFFImportFile.cpp

+31-11
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212

1313
#include "llvm/Object/COFFImportFile.h"
1414
#include "llvm/ADT/ArrayRef.h"
15+
#include "llvm/ADT/SmallVector.h"
16+
#include "llvm/ADT/StringMap.h"
1517
#include "llvm/ADT/Twine.h"
1618
#include "llvm/Object/Archive.h"
1719
#include "llvm/Object/ArchiveWriter.h"
@@ -657,8 +659,7 @@ NewArchiveMember ObjectFactory::createWeakExternal(StringRef Sym,
657659
Error writeImportLibrary(StringRef ImportName, StringRef Path,
658660
ArrayRef<COFFShortExport> Exports,
659661
MachineTypes Machine, bool MinGW,
660-
ArrayRef<COFFShortExport> NativeExports,
661-
bool AddUnderscores) {
662+
ArrayRef<COFFShortExport> NativeExports) {
662663

663664
MachineTypes NativeMachine = Machine;
664665
if (isArm64EC(Machine)) {
@@ -680,6 +681,13 @@ Error writeImportLibrary(StringRef ImportName, StringRef Path,
680681

681682
auto addExports = [&](ArrayRef<COFFShortExport> Exp,
682683
MachineTypes M) -> Error {
684+
StringMap<std::string> RegularImports;
685+
struct Deferred {
686+
std::string Name;
687+
ImportType ImpType;
688+
const COFFShortExport *Export;
689+
};
690+
SmallVector<Deferred, 0> Renames;
683691
for (const COFFShortExport &E : Exp) {
684692
if (E.Private)
685693
continue;
@@ -724,15 +732,11 @@ Error writeImportLibrary(StringRef ImportName, StringRef Path,
724732
else if (Name == E.ImportName)
725733
NameType = IMPORT_NAME;
726734
else {
727-
StringRef Prefix = "";
728-
if (Machine == IMAGE_FILE_MACHINE_I386 && AddUnderscores)
729-
Prefix = "_";
730-
731-
if (ImportType == IMPORT_CODE)
732-
Members.push_back(OF.createWeakExternal(
733-
(Prefix + E.ImportName).str(), Name, false, M));
734-
Members.push_back(OF.createWeakExternal((Prefix + E.ImportName).str(),
735-
Name, true, M));
735+
Deferred D;
736+
D.Name = Name;
737+
D.ImpType = ImportType;
738+
D.Export = &E;
739+
Renames.push_back(D);
736740
continue;
737741
}
738742
} else {
@@ -754,9 +758,25 @@ Error writeImportLibrary(StringRef ImportName, StringRef Path,
754758
}
755759
}
756760

761+
RegularImports[applyNameType(NameType, Name)] = Name;
757762
Members.push_back(OF.createShortImport(Name, E.Ordinal, ImportType,
758763
NameType, ExportName, M));
759764
}
765+
for (const auto &D : Renames) {
766+
auto It = RegularImports.find(D.Export->ImportName);
767+
if (It != RegularImports.end()) {
768+
// We have a regular import entry for a symbol with the name we
769+
// want to reference; produce an alias pointing at that.
770+
StringRef Symbol = It->second;
771+
if (D.ImpType == IMPORT_CODE)
772+
Members.push_back(OF.createWeakExternal(Symbol, D.Name, false, M));
773+
Members.push_back(OF.createWeakExternal(Symbol, D.Name, true, M));
774+
} else {
775+
Members.push_back(OF.createShortImport(D.Name, D.Export->Ordinal,
776+
D.ImpType, IMPORT_NAME_EXPORTAS,
777+
D.Export->ImportName, M));
778+
}
779+
}
760780
return Error::success();
761781
};
762782

llvm/lib/ToolDrivers/llvm-dlltool/DlltoolDriver.cpp

+2-3
Original file line numberDiff line numberDiff line change
@@ -243,9 +243,8 @@ int llvm::dlltoolDriverMain(llvm::ArrayRef<const char *> ArgsArr) {
243243
}
244244

245245
std::string Path = std::string(Args.getLastArgValue(OPT_l));
246-
if (!Path.empty() &&
247-
writeImportLibrary(OutputFile, Path, Exports, Machine,
248-
/*MinGW=*/true, NativeExports, AddUnderscores))
246+
if (!Path.empty() && writeImportLibrary(OutputFile, Path, Exports, Machine,
247+
/*MinGW=*/true, NativeExports))
249248
return 1;
250249
return 0;
251250
}

llvm/test/tools/llvm-dlltool/coff-decorated.def

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ EXPORTS
77
CdeclFunction
88
StdcallFunction@4
99
@FastcallFunction@4
10-
StdcallAlias@4==StdcallFunction@4
10+
StdcallAlias@4==StdcallFunction
1111
??_7exception@@6B@
1212
StdcallExportName@4=StdcallInternalFunction@4
1313
OtherStdcallExportName@4=CdeclInternalFunction

llvm/test/tools/llvm-dlltool/coff-weak-exports.def

+11-4
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55

66
LIBRARY test.dll
77
EXPORTS
8+
AltTestFunction
9+
AltTestFunction2
10+
AltTestData
811
TestFunction==AltTestFunction
912
TestData DATA == AltTestData
1013
; When creating an import library, the DLL internal function name of
@@ -17,21 +20,25 @@ ImpLibName2 = Implementation2 == AltTestFunction2
1720
; matter for the import library
1821
ImpLibName3 = kernel32.Sleep
1922

23+
; CHECK: T AltTestFunction
24+
; CHECK-NEXT: T __imp_AltTestFunction
25+
; CHECK: T AltTestFunction2
26+
; CHECK-NEXT: T __imp_AltTestFunction2
27+
; CHECK: T ImpLibName
28+
; CHECK-NEXT: T __imp_ImpLibName
29+
; CHECK: T ImpLibName3
30+
; CHECK-NEXT: T __imp_ImpLibName3
2031
; CHECK: U AltTestFunction
2132
; CHECK-NEXT: W TestFunction
2233
; CHECK: U __imp_AltTestFunction
2334
; CHECK-NEXT: W __imp_TestFunction
2435
; CHECK-NOT: W TestData
2536
; CHECK: U __imp_AltTestData
2637
; CHECK-NEXT: W __imp_TestData
27-
; CHECK: T ImpLibName
28-
; CHECK-NEXT: T __imp_ImpLibName
2938
; CHECK: U AltTestFunction2
3039
; CHECK-NEXT: W ImpLibName2
3140
; CHECK: U __imp_AltTestFunction2
3241
; CHECK-NEXT: W __imp_ImpLibName2
33-
; CHECK: T ImpLibName3
34-
; CHECK-NEXT: T __imp_ImpLibName3
3542

3643
; ARCH-NOT: unknown arch
3744

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
; RUN: llvm-dlltool -k -m i386 --input-def %s --output-lib %t.a
2+
; RUN: llvm-readobj %t.a | FileCheck %s
3+
; RUN: llvm-nm %t.a | FileCheck %s -check-prefix=CHECK-NM
4+
5+
LIBRARY test.dll
6+
EXPORTS
7+
8+
symbolname == actualimport
9+
10+
dataname DATA == actualdata
11+
12+
_wcstok == wcstok
13+
wcstok == wcstok_s
14+
15+
; CHECK-NM-NOT: actualimport
16+
; CHECK-NM-NOT: actualdata
17+
18+
; CHECK: Type: code
19+
; CHECK-NEXT: Name type: export as
20+
; CHECK-NEXT: Export name: actualimport
21+
; CHECK-NEXT: Symbol: __imp__symbolname
22+
; CHECK-NEXT: Symbol: _symbolname
23+
24+
; CHECK: Type: data
25+
; CHECK-NEXT: Name type: export as
26+
; CHECK-NEXT: Export name: actualdata
27+
; CHECK-NEXT: Symbol: __imp__dataname
28+
29+
; CHECK: Type: code
30+
; CHECK-NEXT: Name type: export as
31+
; CHECK-NEXT: Export name: wcstok
32+
; CHECK-NEXT: Symbol: __imp___wcstok
33+
; CHECK-NEXT: Symbol: __wcstok
34+
35+
; CHECK: Type: code
36+
; CHECK-NEXT: Name type: export as
37+
; CHECK-NEXT: Export name: wcstok_s
38+
; CHECK-NEXT: Symbol: __imp__wcstok
39+
; CHECK-NEXT: Symbol: _wcstok

0 commit comments

Comments
 (0)