diff --git a/lld/COFF/Config.h b/lld/COFF/Config.h index 643c4939a43b..4c1d90db60dc 100644 --- a/lld/COFF/Config.h +++ b/lld/COFF/Config.h @@ -78,6 +78,7 @@ struct Configuration { StringRef Implib; std::vector Exports; std::set DelayLoads; + std::map DLLOrder; Undefined *DelayLoadHelper = nullptr; // Used for SafeSEH. diff --git a/lld/COFF/DLL.cpp b/lld/COFF/DLL.cpp index 5d6c136bc92d..f71801d97fcf 100644 --- a/lld/COFF/DLL.cpp +++ b/lld/COFF/DLL.cpp @@ -124,14 +124,19 @@ private: size_t Size; }; -static std::map> +static std::vector> binImports(const std::vector &Imports) { // Group DLL-imported symbols by DLL name because that's how // symbols are layed out in the import descriptor table. - std::map> M; + auto Less = [](StringRef A, StringRef B) { + return Config->DLLOrder[A] < Config->DLLOrder[B]; + }; + std::map, + bool(*)(StringRef, StringRef)> M(Less); for (DefinedImportData *Sym : Imports) M[Sym->getDLLName()].push_back(Sym); + std::vector> V; for (auto &P : M) { // Sort symbols by name for each group. std::vector &Syms = P.second; @@ -139,8 +144,9 @@ binImports(const std::vector &Imports) { [](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 @@ std::vector IdataContents::getChunks() { } void IdataContents::create() { - std::map> Map = - binImports(Imports); + std::vector> V = binImports(Imports); // Create .idata contents for each DLL. - for (auto &P : Map) { - StringRef Name = P.first; - std::vector &Syms = P.second; + for (std::vector &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 @@ uint64_t DelayLoadContents::getDirSize() { void DelayLoadContents::create(Defined *H) { Helper = H; - std::map> Map = - binImports(Imports); + std::vector> V = binImports(Imports); // Create .didat contents for each DLL. - for (auto &P : Map) { - StringRef Name = P.first; - std::vector &Syms = P.second; + for (std::vector &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 871c40c8423f..1113c5e4af0d 100644 --- a/lld/COFF/InputFiles.cpp +++ b/lld/COFF/InputFiles.cpp @@ -281,7 +281,8 @@ void ImportFile::parse() { // 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 e2e80f11e573..0d1144646725 100644 --- a/lld/COFF/InputFiles.h +++ b/lld/COFF/InputFiles.h @@ -186,6 +186,7 @@ public: 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 deceb6078db2..3923d9f84ae1 100644 --- a/lld/COFF/Writer.cpp +++ b/lld/COFF/Writer.cpp @@ -365,15 +365,22 @@ void Writer::createMiscChunks() { 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 000000000000..7c30b11a13e8 --- /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 +...