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
This commit is contained in:
Rui Ueyama 2015-08-17 08:30:31 +00:00
parent e73e418bb4
commit d157088adb
6 changed files with 94 additions and 18 deletions

View File

@ -78,6 +78,7 @@ struct Configuration {
StringRef Implib;
std::vector<Export> Exports;
std::set<std::string> DelayLoads;
std::map<StringRef, int> DLLOrder;
Undefined *DelayLoadHelper = nullptr;
// Used for SafeSEH.

View File

@ -124,14 +124,19 @@ private:
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 @@ binImports(const std::vector<DefinedImportData *> &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<Chunk *> IdataContents::getChunks() {
}
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 @@ uint64_t DelayLoadContents::getDirSize() {
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))

View File

@ -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:

View File

@ -186,6 +186,7 @@ public:
DefinedImportData *ImpSym = nullptr;
DefinedImportThunk *ThunkSym = nullptr;
std::string DLLName;
private:
void parse() override;

View File

@ -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()) {

View File

@ -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
...