COFF: Fix the order of the DLL import entry.
There are some DLLs whose initializers depends on other DLLs'
initializers. The initialization order matters for them.
MSVC linker uses the order of the libraries from the command line.
LLD used ASCII-betical order. So they were incompatible.
This patch makes LLD compatible with MSVC.
llvm-svn: 245201
diff --git a/lld/COFF/Config.h b/lld/COFF/Config.h
index 643c493..4c1d90d 100644
--- a/lld/COFF/Config.h
+++ b/lld/COFF/Config.h
@@ -78,6 +78,7 @@
StringRef Implib;
std::vector<Export> Exports;
std::set<std::string> DelayLoads;
+ std::map<StringRef, int> DLLOrder;
Undefined *DelayLoadHelper = nullptr;
// Used for SafeSEH.
diff --git a/lld/COFF/DLL.cpp b/lld/COFF/DLL.cpp
index 5d6c136..f71801d 100644
--- a/lld/COFF/DLL.cpp
+++ b/lld/COFF/DLL.cpp
@@ -124,14 +124,19 @@
size_t Size;
};
-static std::map<StringRef, std::vector<DefinedImportData *>>
+static std::vector<std::vector<DefinedImportData *>>
binImports(const std::vector<DefinedImportData *> &Imports) {
// Group DLL-imported symbols by DLL name because that's how
// symbols are layed out in the import descriptor table.
- std::map<StringRef, std::vector<DefinedImportData *>> M;
+ auto Less = [](StringRef A, StringRef B) {
+ return Config->DLLOrder[A] < Config->DLLOrder[B];
+ };
+ std::map<StringRef, std::vector<DefinedImportData *>,
+ bool(*)(StringRef, StringRef)> M(Less);
for (DefinedImportData *Sym : Imports)
M[Sym->getDLLName()].push_back(Sym);
+ std::vector<std::vector<DefinedImportData *>> V;
for (auto &P : M) {
// Sort symbols by name for each group.
std::vector<DefinedImportData *> &Syms = P.second;
@@ -139,8 +144,9 @@
[](DefinedImportData *A, DefinedImportData *B) {
return A->getName() < B->getName();
});
+ V.push_back(std::move(Syms));
}
- return M;
+ return V;
}
// Export table
@@ -393,13 +399,11 @@
}
void IdataContents::create() {
- std::map<StringRef, std::vector<DefinedImportData *>> Map =
- binImports(Imports);
+ std::vector<std::vector<DefinedImportData *>> V = binImports(Imports);
// Create .idata contents for each DLL.
- for (auto &P : Map) {
- StringRef Name = P.first;
- std::vector<DefinedImportData *> &Syms = P.second;
+ for (std::vector<DefinedImportData *> &Syms : V) {
+ StringRef Name = Syms[0]->getDLLName();
// Create lookup and address tables. If they have external names,
// we need to create HintName chunks to store the names.
@@ -467,13 +471,11 @@
void DelayLoadContents::create(Defined *H) {
Helper = H;
- std::map<StringRef, std::vector<DefinedImportData *>> Map =
- binImports(Imports);
+ std::vector<std::vector<DefinedImportData *>> V = binImports(Imports);
// Create .didat contents for each DLL.
- for (auto &P : Map) {
- StringRef Name = P.first;
- std::vector<DefinedImportData *> &Syms = P.second;
+ for (std::vector<DefinedImportData *> &Syms : V) {
+ StringRef Name = Syms[0]->getDLLName();
// Create the delay import table header.
if (!DLLNames.count(Name))
diff --git a/lld/COFF/InputFiles.cpp b/lld/COFF/InputFiles.cpp
index 871c40c..1113c5e 100644
--- a/lld/COFF/InputFiles.cpp
+++ b/lld/COFF/InputFiles.cpp
@@ -281,7 +281,8 @@
// Read names and create an __imp_ symbol.
StringRef Name = StringAlloc.save(StringRef(Buf + sizeof(*Hdr)));
StringRef ImpName = StringAlloc.save(Twine("__imp_") + Name);
- StringRef DLLName(Buf + sizeof(coff_import_header) + Name.size() + 1);
+ const char *NameStart = Buf + sizeof(coff_import_header) + Name.size() + 1;
+ DLLName = StringRef(NameStart).lower();
StringRef ExtName;
switch (Hdr->getNameType()) {
case IMPORT_ORDINAL:
diff --git a/lld/COFF/InputFiles.h b/lld/COFF/InputFiles.h
index e2e80f1..0d11446 100644
--- a/lld/COFF/InputFiles.h
+++ b/lld/COFF/InputFiles.h
@@ -186,6 +186,7 @@
DefinedImportData *ImpSym = nullptr;
DefinedImportThunk *ThunkSym = nullptr;
+ std::string DLLName;
private:
void parse() override;
diff --git a/lld/COFF/Writer.cpp b/lld/COFF/Writer.cpp
index deceb60..3923d9f 100644
--- a/lld/COFF/Writer.cpp
+++ b/lld/COFF/Writer.cpp
@@ -365,15 +365,22 @@
void Writer::createImportTables() {
if (Symtab->ImportFiles.empty())
return;
+
+ // Initialize DLLOrder so that import entries are ordered in
+ // the same order as in the command line. (That affects DLL
+ // initialization order, and this ordering is MSVC-compatible.)
+ for (ImportFile *File : Symtab->ImportFiles)
+ if (Config->DLLOrder.count(File->DLLName) == 0)
+ Config->DLLOrder[File->DLLName] = Config->DLLOrder.size();
+
OutputSection *Text = createSection(".text");
for (ImportFile *File : Symtab->ImportFiles) {
if (DefinedImportThunk *Thunk = File->ThunkSym)
Text->addChunk(Thunk->getChunk());
- DefinedImportData *Imp = File->ImpSym;
- if (Config->DelayLoads.count(Imp->getDLLName().lower())) {
- DelayIdata.add(Imp);
+ if (Config->DelayLoads.count(File->DLLName)) {
+ DelayIdata.add(File->ImpSym);
} else {
- Idata.add(Imp);
+ Idata.add(File->ImpSym);
}
}
if (!Idata.empty()) {
diff --git a/lld/test/COFF/dllorder.test b/lld/test/COFF/dllorder.test
new file mode 100644
index 0000000..7c30b11
--- /dev/null
+++ b/lld/test/COFF/dllorder.test
@@ -0,0 +1,64 @@
+# REQUIRES: winlib
+
+# RUN: yaml2obj < %s > %t.obj
+# RUN: mkdir -p %tlib
+
+# RUN: echo EXPORTS sym1 > %t1.def
+# RUN: lib /nologo /def:%t1.def /out:%tlib\\lib1.lib > /dev/null
+
+# RUN: echo EXPORTS sym2 > %t2.def
+# RUN: lib /nologo /def:%t2.def /out:%tlib\\lib2.lib > /dev/null
+
+# RUN: lld-link /out:%t1.exe /entry:main /libpath:%tlib %t.obj /defaultlib:lib1 /defaultlib:lib2
+# RUN: lld-link /out:%t2.exe /entry:main /libpath:%tlib %t.obj /defaultlib:lib2 /defaultlib:lib1
+
+# RUN: llvm-readobj -coff-imports %t1.exe | FileCheck -check-prefix=CHECK1 %s
+# RUN: llvm-readobj -coff-imports %t2.exe | FileCheck -check-prefix=CHECK2 %s
+
+# CHECK1: Name: dllorder.test.tmp1.dll
+# CHECK1: Name: dllorder.test.tmp2.dll
+
+# CHECK2: Name: dllorder.test.tmp2.dll
+# CHECK2: Name: dllorder.test.tmp1.dll
+
+---
+header:
+ Machine: IMAGE_FILE_MACHINE_AMD64
+ Characteristics: []
+sections:
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 4096
+ SectionData: 0000000000000000
+symbols:
+ - Name: .text
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 8
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+ - Name: main
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: __imp_sym1
+ Value: 0
+ SectionNumber: 0
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: __imp_sym2
+ Value: 0
+ SectionNumber: 0
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...