mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-25 03:56:06 +00:00
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:
parent
e73e418bb4
commit
d157088adb
@ -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.
|
||||
|
@ -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))
|
||||
|
@ -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:
|
||||
|
@ -186,6 +186,7 @@ public:
|
||||
|
||||
DefinedImportData *ImpSym = nullptr;
|
||||
DefinedImportThunk *ThunkSym = nullptr;
|
||||
std::string DLLName;
|
||||
|
||||
private:
|
||||
void parse() override;
|
||||
|
@ -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()) {
|
||||
|
64
lld/test/COFF/dllorder.test
Normal file
64
lld/test/COFF/dllorder.test
Normal 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
|
||||
...
|
Loading…
x
Reference in New Issue
Block a user