2015-06-07 09:15:04 +08:00
|
|
|
//===- DLL.cpp ------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// The LLVM Linker
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
2015-06-22 06:31:52 +08:00
|
|
|
// This file defines various types of chunks for the DLL import or export
|
|
|
|
// descriptor tables. They are inherently Windows-specific.
|
2015-06-07 09:15:04 +08:00
|
|
|
// You need to read Microsoft PE/COFF spec to understand details
|
|
|
|
// about the data structures.
|
|
|
|
//
|
|
|
|
// If you are not particularly interested in linking against Windows
|
|
|
|
// DLL, you can skip this file, and you should still be able to
|
|
|
|
// understand the rest of the linker.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "Chunks.h"
|
|
|
|
#include "DLL.h"
|
|
|
|
#include "llvm/Object/COFF.h"
|
|
|
|
#include "llvm/Support/Endian.h"
|
2015-06-17 08:16:33 +08:00
|
|
|
#include "llvm/Support/Path.h"
|
2015-06-07 09:15:04 +08:00
|
|
|
|
|
|
|
using namespace llvm;
|
|
|
|
using namespace llvm::object;
|
|
|
|
using namespace llvm::support::endian;
|
|
|
|
using namespace llvm::COFF;
|
|
|
|
|
|
|
|
namespace lld {
|
|
|
|
namespace coff {
|
2015-08-11 07:02:57 +08:00
|
|
|
namespace {
|
2015-06-07 09:15:04 +08:00
|
|
|
|
2015-06-17 08:16:33 +08:00
|
|
|
// Import table
|
|
|
|
|
2015-07-09 08:45:50 +08:00
|
|
|
static int ptrSize() { return Config->is64() ? 8 : 4; }
|
|
|
|
|
2015-06-07 09:15:04 +08:00
|
|
|
// A chunk for the import descriptor table.
|
|
|
|
class HintNameChunk : public Chunk {
|
|
|
|
public:
|
|
|
|
HintNameChunk(StringRef N, uint16_t H) : Name(N), Hint(H) {}
|
|
|
|
|
|
|
|
size_t getSize() const override {
|
|
|
|
// Starts with 2 byte Hint field, followed by a null-terminated string,
|
|
|
|
// ends with 0 or 1 byte padding.
|
2016-01-15 04:53:50 +08:00
|
|
|
return alignTo(Name.size() + 3, 2);
|
2015-06-07 09:15:04 +08:00
|
|
|
}
|
|
|
|
|
2015-09-20 07:28:57 +08:00
|
|
|
void writeTo(uint8_t *Buf) const override {
|
2015-08-14 11:30:59 +08:00
|
|
|
write16le(Buf + OutputSectionOff, Hint);
|
|
|
|
memcpy(Buf + OutputSectionOff + 2, Name.data(), Name.size());
|
2015-06-07 09:15:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
StringRef Name;
|
|
|
|
uint16_t Hint;
|
|
|
|
};
|
|
|
|
|
|
|
|
// A chunk for the import descriptor table.
|
|
|
|
class LookupChunk : public Chunk {
|
|
|
|
public:
|
|
|
|
explicit LookupChunk(Chunk *C) : HintName(C) {}
|
2015-07-09 08:45:50 +08:00
|
|
|
size_t getSize() const override { return ptrSize(); }
|
2015-06-07 09:15:04 +08:00
|
|
|
|
2015-09-20 07:28:57 +08:00
|
|
|
void writeTo(uint8_t *Buf) const override {
|
2015-08-14 11:30:59 +08:00
|
|
|
write32le(Buf + OutputSectionOff, HintName->getRVA());
|
2015-06-07 09:15:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
Chunk *HintName;
|
|
|
|
};
|
|
|
|
|
|
|
|
// A chunk for the import descriptor table.
|
|
|
|
// This chunk represent import-by-ordinal symbols.
|
|
|
|
// See Microsoft PE/COFF spec 7.1. Import Header for details.
|
|
|
|
class OrdinalOnlyChunk : public Chunk {
|
|
|
|
public:
|
|
|
|
explicit OrdinalOnlyChunk(uint16_t V) : Ordinal(V) {}
|
2015-07-09 08:45:50 +08:00
|
|
|
size_t getSize() const override { return ptrSize(); }
|
2015-06-07 09:15:04 +08:00
|
|
|
|
2015-09-20 07:28:57 +08:00
|
|
|
void writeTo(uint8_t *Buf) const override {
|
2015-06-07 09:15:04 +08:00
|
|
|
// An import-by-ordinal slot has MSB 1 to indicate that
|
|
|
|
// this is import-by-ordinal (and not import-by-name).
|
2015-07-09 08:45:50 +08:00
|
|
|
if (Config->is64()) {
|
2015-08-14 11:30:59 +08:00
|
|
|
write64le(Buf + OutputSectionOff, (1ULL << 63) | Ordinal);
|
2015-07-09 08:45:50 +08:00
|
|
|
} else {
|
2015-08-14 11:30:59 +08:00
|
|
|
write32le(Buf + OutputSectionOff, (1ULL << 31) | Ordinal);
|
2015-07-09 08:45:50 +08:00
|
|
|
}
|
2015-06-07 09:15:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
uint16_t Ordinal;
|
|
|
|
};
|
|
|
|
|
|
|
|
// A chunk for the import descriptor table.
|
2015-06-17 08:16:33 +08:00
|
|
|
class ImportDirectoryChunk : public Chunk {
|
2015-06-07 09:15:04 +08:00
|
|
|
public:
|
2015-06-17 08:16:33 +08:00
|
|
|
explicit ImportDirectoryChunk(Chunk *N) : DLLName(N) {}
|
|
|
|
size_t getSize() const override { return sizeof(ImportDirectoryTableEntry); }
|
2015-06-07 09:15:04 +08:00
|
|
|
|
2015-09-20 07:28:57 +08:00
|
|
|
void writeTo(uint8_t *Buf) const override {
|
2015-08-14 11:30:59 +08:00
|
|
|
auto *E = (coff_import_directory_table_entry *)(Buf + OutputSectionOff);
|
2015-06-07 09:15:04 +08:00
|
|
|
E->ImportLookupTableRVA = LookupTab->getRVA();
|
|
|
|
E->NameRVA = DLLName->getRVA();
|
|
|
|
E->ImportAddressTableRVA = AddressTab->getRVA();
|
|
|
|
}
|
|
|
|
|
|
|
|
Chunk *DLLName;
|
|
|
|
Chunk *LookupTab;
|
|
|
|
Chunk *AddressTab;
|
|
|
|
};
|
|
|
|
|
|
|
|
// A chunk representing null terminator in the import table.
|
|
|
|
// Contents of this chunk is always null bytes.
|
|
|
|
class NullChunk : public Chunk {
|
|
|
|
public:
|
|
|
|
explicit NullChunk(size_t N) : Size(N) {}
|
|
|
|
bool hasData() const override { return false; }
|
|
|
|
size_t getSize() const override { return Size; }
|
2015-06-22 06:31:52 +08:00
|
|
|
void setAlign(size_t N) { Align = N; }
|
2015-06-07 09:15:04 +08:00
|
|
|
|
|
|
|
private:
|
|
|
|
size_t Size;
|
|
|
|
};
|
|
|
|
|
2015-08-17 16:30:31 +08:00
|
|
|
static std::vector<std::vector<DefinedImportData *>>
|
2015-06-22 06:31:52 +08:00
|
|
|
binImports(const std::vector<DefinedImportData *> &Imports) {
|
2015-06-07 09:15:04 +08:00
|
|
|
// Group DLL-imported symbols by DLL name because that's how
|
|
|
|
// symbols are layed out in the import descriptor table.
|
2015-09-02 15:27:31 +08:00
|
|
|
auto Less = [](const std::string &A, const std::string &B) {
|
2015-08-17 16:30:31 +08:00
|
|
|
return Config->DLLOrder[A] < Config->DLLOrder[B];
|
|
|
|
};
|
2015-09-02 15:27:31 +08:00
|
|
|
std::map<std::string, std::vector<DefinedImportData *>,
|
|
|
|
bool(*)(const std::string &, const std::string &)> M(Less);
|
2015-06-07 09:15:04 +08:00
|
|
|
for (DefinedImportData *Sym : Imports)
|
2015-09-02 15:27:31 +08:00
|
|
|
M[Sym->getDLLName().lower()].push_back(Sym);
|
2015-06-07 09:15:04 +08:00
|
|
|
|
2015-08-17 16:30:31 +08:00
|
|
|
std::vector<std::vector<DefinedImportData *>> V;
|
2015-06-22 06:31:52 +08:00
|
|
|
for (auto &P : M) {
|
2015-06-07 09:15:04 +08:00
|
|
|
// Sort symbols by name for each group.
|
2015-06-22 06:31:52 +08:00
|
|
|
std::vector<DefinedImportData *> &Syms = P.second;
|
2015-06-07 09:15:04 +08:00
|
|
|
std::sort(Syms.begin(), Syms.end(),
|
|
|
|
[](DefinedImportData *A, DefinedImportData *B) {
|
|
|
|
return A->getName() < B->getName();
|
|
|
|
});
|
2015-08-17 16:30:31 +08:00
|
|
|
V.push_back(std::move(Syms));
|
2015-06-22 06:31:52 +08:00
|
|
|
}
|
2015-08-17 16:30:31 +08:00
|
|
|
return V;
|
2015-06-22 06:31:52 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Export table
|
|
|
|
// See Microsoft PE/COFF spec 4.3 for details.
|
|
|
|
|
|
|
|
// A chunk for the delay import descriptor table etnry.
|
|
|
|
class DelayDirectoryChunk : public Chunk {
|
|
|
|
public:
|
|
|
|
explicit DelayDirectoryChunk(Chunk *N) : DLLName(N) {}
|
|
|
|
|
|
|
|
size_t getSize() const override {
|
|
|
|
return sizeof(delay_import_directory_table_entry);
|
|
|
|
}
|
|
|
|
|
2015-09-20 07:28:57 +08:00
|
|
|
void writeTo(uint8_t *Buf) const override {
|
2015-08-14 11:30:59 +08:00
|
|
|
auto *E = (delay_import_directory_table_entry *)(Buf + OutputSectionOff);
|
2015-06-27 05:40:15 +08:00
|
|
|
E->Attributes = 1;
|
2015-06-22 06:31:52 +08:00
|
|
|
E->Name = DLLName->getRVA();
|
|
|
|
E->ModuleHandle = ModuleHandle->getRVA();
|
|
|
|
E->DelayImportAddressTable = AddressTab->getRVA();
|
|
|
|
E->DelayImportNameTable = NameTab->getRVA();
|
|
|
|
}
|
|
|
|
|
|
|
|
Chunk *DLLName;
|
|
|
|
Chunk *ModuleHandle;
|
|
|
|
Chunk *AddressTab;
|
|
|
|
Chunk *NameTab;
|
|
|
|
};
|
|
|
|
|
|
|
|
// Initial contents for delay-loaded functions.
|
2015-06-23 01:26:27 +08:00
|
|
|
// This code calls __delayLoadHelper2 function to resolve a symbol
|
2015-06-22 06:31:52 +08:00
|
|
|
// and then overwrites its jump table slot with the result
|
|
|
|
// for subsequent function calls.
|
2015-07-16 06:26:57 +08:00
|
|
|
static const uint8_t ThunkX64[] = {
|
2015-06-22 06:31:52 +08:00
|
|
|
0x51, // push rcx
|
|
|
|
0x52, // push rdx
|
|
|
|
0x41, 0x50, // push r8
|
|
|
|
0x41, 0x51, // push r9
|
|
|
|
0x48, 0x83, 0xEC, 0x48, // sub rsp, 48h
|
|
|
|
0x66, 0x0F, 0x7F, 0x04, 0x24, // movdqa xmmword ptr [rsp], xmm0
|
|
|
|
0x66, 0x0F, 0x7F, 0x4C, 0x24, 0x10, // movdqa xmmword ptr [rsp+10h], xmm1
|
|
|
|
0x66, 0x0F, 0x7F, 0x54, 0x24, 0x20, // movdqa xmmword ptr [rsp+20h], xmm2
|
|
|
|
0x66, 0x0F, 0x7F, 0x5C, 0x24, 0x30, // movdqa xmmword ptr [rsp+30h], xmm3
|
|
|
|
0x48, 0x8D, 0x15, 0, 0, 0, 0, // lea rdx, [__imp_<FUNCNAME>]
|
|
|
|
0x48, 0x8D, 0x0D, 0, 0, 0, 0, // lea rcx, [___DELAY_IMPORT_...]
|
|
|
|
0xE8, 0, 0, 0, 0, // call __delayLoadHelper2
|
|
|
|
0x66, 0x0F, 0x6F, 0x04, 0x24, // movdqa xmm0, xmmword ptr [rsp]
|
|
|
|
0x66, 0x0F, 0x6F, 0x4C, 0x24, 0x10, // movdqa xmm1, xmmword ptr [rsp+10h]
|
|
|
|
0x66, 0x0F, 0x6F, 0x54, 0x24, 0x20, // movdqa xmm2, xmmword ptr [rsp+20h]
|
|
|
|
0x66, 0x0F, 0x6F, 0x5C, 0x24, 0x30, // movdqa xmm3, xmmword ptr [rsp+30h]
|
|
|
|
0x48, 0x83, 0xC4, 0x48, // add rsp, 48h
|
|
|
|
0x41, 0x59, // pop r9
|
|
|
|
0x41, 0x58, // pop r8
|
|
|
|
0x5A, // pop rdx
|
|
|
|
0x59, // pop rcx
|
|
|
|
0xFF, 0xE0, // jmp rax
|
|
|
|
};
|
|
|
|
|
2015-07-16 06:26:57 +08:00
|
|
|
static const uint8_t ThunkX86[] = {
|
|
|
|
0x51, // push ecx
|
|
|
|
0x52, // push edx
|
|
|
|
0x68, 0, 0, 0, 0, // push offset ___imp__<FUNCNAME>
|
|
|
|
0x68, 0, 0, 0, 0, // push offset ___DELAY_IMPORT_DESCRIPTOR_<DLLNAME>_dll
|
|
|
|
0xE8, 0, 0, 0, 0, // call ___delayLoadHelper2@8
|
|
|
|
0x5A, // pop edx
|
|
|
|
0x59, // pop ecx
|
|
|
|
0xFF, 0xE0, // jmp eax
|
|
|
|
};
|
|
|
|
|
2015-06-22 06:31:52 +08:00
|
|
|
// A chunk for the delay import thunk.
|
2015-07-16 06:26:57 +08:00
|
|
|
class ThunkChunkX64 : public Chunk {
|
2015-06-22 06:31:52 +08:00
|
|
|
public:
|
2015-07-16 06:26:57 +08:00
|
|
|
ThunkChunkX64(Defined *I, Chunk *D, Defined *H)
|
|
|
|
: Imp(I), Desc(D), Helper(H) {}
|
|
|
|
|
|
|
|
size_t getSize() const override { return sizeof(ThunkX64); }
|
2015-06-22 06:31:52 +08:00
|
|
|
|
2015-09-20 07:28:57 +08:00
|
|
|
void writeTo(uint8_t *Buf) const override {
|
2015-08-14 11:30:59 +08:00
|
|
|
memcpy(Buf + OutputSectionOff, ThunkX64, sizeof(ThunkX64));
|
|
|
|
write32le(Buf + OutputSectionOff + 36, Imp->getRVA() - RVA - 40);
|
|
|
|
write32le(Buf + OutputSectionOff + 43, Desc->getRVA() - RVA - 47);
|
|
|
|
write32le(Buf + OutputSectionOff + 48, Helper->getRVA() - RVA - 52);
|
2015-06-22 06:31:52 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
Defined *Imp = nullptr;
|
|
|
|
Chunk *Desc = nullptr;
|
|
|
|
Defined *Helper = nullptr;
|
|
|
|
};
|
|
|
|
|
2015-07-16 06:26:57 +08:00
|
|
|
class ThunkChunkX86 : public Chunk {
|
|
|
|
public:
|
|
|
|
ThunkChunkX86(Defined *I, Chunk *D, Defined *H)
|
|
|
|
: Imp(I), Desc(D), Helper(H) {}
|
|
|
|
|
|
|
|
size_t getSize() const override { return sizeof(ThunkX86); }
|
|
|
|
|
2015-09-20 07:28:57 +08:00
|
|
|
void writeTo(uint8_t *Buf) const override {
|
2015-08-14 11:30:59 +08:00
|
|
|
memcpy(Buf + OutputSectionOff, ThunkX86, sizeof(ThunkX86));
|
|
|
|
write32le(Buf + OutputSectionOff + 3, Imp->getRVA() + Config->ImageBase);
|
|
|
|
write32le(Buf + OutputSectionOff + 8, Desc->getRVA() + Config->ImageBase);
|
|
|
|
write32le(Buf + OutputSectionOff + 13, Helper->getRVA() - RVA - 17);
|
2015-07-16 06:26:57 +08:00
|
|
|
}
|
|
|
|
|
2015-07-25 09:44:32 +08:00
|
|
|
void getBaserels(std::vector<Baserel> *Res) override {
|
|
|
|
Res->emplace_back(RVA + 3);
|
|
|
|
Res->emplace_back(RVA + 8);
|
2015-07-16 06:26:57 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
Defined *Imp = nullptr;
|
|
|
|
Chunk *Desc = nullptr;
|
|
|
|
Defined *Helper = nullptr;
|
|
|
|
};
|
|
|
|
|
2015-06-27 05:40:15 +08:00
|
|
|
// A chunk for the import descriptor table.
|
|
|
|
class DelayAddressChunk : public Chunk {
|
|
|
|
public:
|
|
|
|
explicit DelayAddressChunk(Chunk *C) : Thunk(C) {}
|
2015-07-28 10:54:18 +08:00
|
|
|
size_t getSize() const override { return ptrSize(); }
|
2015-06-27 05:40:15 +08:00
|
|
|
|
2015-09-20 07:28:57 +08:00
|
|
|
void writeTo(uint8_t *Buf) const override {
|
2015-07-28 10:54:18 +08:00
|
|
|
if (Config->is64()) {
|
2015-08-14 11:30:59 +08:00
|
|
|
write64le(Buf + OutputSectionOff, Thunk->getRVA() + Config->ImageBase);
|
2015-07-28 10:54:18 +08:00
|
|
|
} else {
|
2015-08-14 11:30:59 +08:00
|
|
|
write32le(Buf + OutputSectionOff, Thunk->getRVA() + Config->ImageBase);
|
2015-07-28 10:54:18 +08:00
|
|
|
}
|
2015-06-27 05:40:15 +08:00
|
|
|
}
|
|
|
|
|
2015-07-25 09:44:32 +08:00
|
|
|
void getBaserels(std::vector<Baserel> *Res) override {
|
|
|
|
Res->emplace_back(RVA);
|
2015-06-27 06:05:32 +08:00
|
|
|
}
|
|
|
|
|
2015-06-27 05:40:15 +08:00
|
|
|
Chunk *Thunk;
|
|
|
|
};
|
|
|
|
|
2015-06-17 08:16:33 +08:00
|
|
|
// Export table
|
|
|
|
// Read Microsoft PE/COFF spec 5.3 for details.
|
|
|
|
|
|
|
|
// A chunk for the export descriptor table.
|
|
|
|
class ExportDirectoryChunk : public Chunk {
|
|
|
|
public:
|
|
|
|
ExportDirectoryChunk(int I, int J, Chunk *D, Chunk *A, Chunk *N, Chunk *O)
|
|
|
|
: MaxOrdinal(I), NameTabSize(J), DLLName(D), AddressTab(A), NameTab(N),
|
|
|
|
OrdinalTab(O) {}
|
|
|
|
|
|
|
|
size_t getSize() const override {
|
|
|
|
return sizeof(export_directory_table_entry);
|
|
|
|
}
|
|
|
|
|
2015-09-20 07:28:57 +08:00
|
|
|
void writeTo(uint8_t *Buf) const override {
|
2015-08-14 11:30:59 +08:00
|
|
|
auto *E = (export_directory_table_entry *)(Buf + OutputSectionOff);
|
2015-06-17 08:16:33 +08:00
|
|
|
E->NameRVA = DLLName->getRVA();
|
|
|
|
E->OrdinalBase = 0;
|
|
|
|
E->AddressTableEntries = MaxOrdinal + 1;
|
|
|
|
E->NumberOfNamePointers = NameTabSize;
|
|
|
|
E->ExportAddressTableRVA = AddressTab->getRVA();
|
|
|
|
E->NamePointerRVA = NameTab->getRVA();
|
|
|
|
E->OrdinalTableRVA = OrdinalTab->getRVA();
|
|
|
|
}
|
|
|
|
|
|
|
|
uint16_t MaxOrdinal;
|
|
|
|
uint16_t NameTabSize;
|
|
|
|
Chunk *DLLName;
|
|
|
|
Chunk *AddressTab;
|
|
|
|
Chunk *NameTab;
|
|
|
|
Chunk *OrdinalTab;
|
|
|
|
};
|
|
|
|
|
|
|
|
class AddressTableChunk : public Chunk {
|
|
|
|
public:
|
|
|
|
explicit AddressTableChunk(size_t MaxOrdinal) : Size(MaxOrdinal + 1) {}
|
|
|
|
size_t getSize() const override { return Size * 4; }
|
|
|
|
|
2015-09-20 07:28:57 +08:00
|
|
|
void writeTo(uint8_t *Buf) const override {
|
2015-06-29 06:16:41 +08:00
|
|
|
for (Export &E : Config->Exports) {
|
2016-01-09 09:22:00 +08:00
|
|
|
uint8_t *P = Buf + OutputSectionOff + E.Ordinal * 4;
|
|
|
|
if (E.ForwardChunk) {
|
|
|
|
write32le(P, E.ForwardChunk->getRVA());
|
|
|
|
} else {
|
2016-12-10 05:55:24 +08:00
|
|
|
write32le(P, cast<Defined>(E.Sym)->getRVA());
|
2016-01-09 09:22:00 +08:00
|
|
|
}
|
2015-06-29 06:16:41 +08:00
|
|
|
}
|
2015-06-17 08:16:33 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
size_t Size;
|
|
|
|
};
|
|
|
|
|
|
|
|
class NamePointersChunk : public Chunk {
|
|
|
|
public:
|
|
|
|
explicit NamePointersChunk(std::vector<Chunk *> &V) : Chunks(V) {}
|
|
|
|
size_t getSize() const override { return Chunks.size() * 4; }
|
|
|
|
|
2015-09-20 07:28:57 +08:00
|
|
|
void writeTo(uint8_t *Buf) const override {
|
2015-08-14 11:30:59 +08:00
|
|
|
uint8_t *P = Buf + OutputSectionOff;
|
2015-06-17 08:16:33 +08:00
|
|
|
for (Chunk *C : Chunks) {
|
|
|
|
write32le(P, C->getRVA());
|
|
|
|
P += 4;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
std::vector<Chunk *> Chunks;
|
|
|
|
};
|
|
|
|
|
|
|
|
class ExportOrdinalChunk : public Chunk {
|
|
|
|
public:
|
|
|
|
explicit ExportOrdinalChunk(size_t I) : Size(I) {}
|
|
|
|
size_t getSize() const override { return Size * 2; }
|
|
|
|
|
2015-09-20 07:28:57 +08:00
|
|
|
void writeTo(uint8_t *Buf) const override {
|
2015-08-14 11:30:59 +08:00
|
|
|
uint8_t *P = Buf + OutputSectionOff;
|
2015-06-17 08:16:33 +08:00
|
|
|
for (Export &E : Config->Exports) {
|
|
|
|
if (E.Noname)
|
|
|
|
continue;
|
|
|
|
write16le(P, E.Ordinal);
|
|
|
|
P += 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
size_t Size;
|
|
|
|
};
|
|
|
|
|
2015-08-11 07:02:57 +08:00
|
|
|
} // anonymous namespace
|
|
|
|
|
|
|
|
uint64_t IdataContents::getDirSize() {
|
|
|
|
return Dirs.size() * sizeof(ImportDirectoryTableEntry);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint64_t IdataContents::getIATSize() {
|
|
|
|
return Addresses.size() * ptrSize();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns a list of .idata contents.
|
|
|
|
// See Microsoft PE/COFF spec 5.4 for details.
|
|
|
|
std::vector<Chunk *> IdataContents::getChunks() {
|
|
|
|
create();
|
|
|
|
std::vector<Chunk *> V;
|
|
|
|
// The loader assumes a specific order of data.
|
|
|
|
// Add each type in the correct order.
|
|
|
|
for (std::unique_ptr<Chunk> &C : Dirs)
|
|
|
|
V.push_back(C.get());
|
|
|
|
for (std::unique_ptr<Chunk> &C : Lookups)
|
|
|
|
V.push_back(C.get());
|
|
|
|
for (std::unique_ptr<Chunk> &C : Addresses)
|
|
|
|
V.push_back(C.get());
|
|
|
|
for (std::unique_ptr<Chunk> &C : Hints)
|
|
|
|
V.push_back(C.get());
|
|
|
|
for (auto &P : DLLNames) {
|
|
|
|
std::unique_ptr<Chunk> &C = P.second;
|
|
|
|
V.push_back(C.get());
|
|
|
|
}
|
|
|
|
return V;
|
|
|
|
}
|
|
|
|
|
|
|
|
void IdataContents::create() {
|
2015-08-17 16:30:31 +08:00
|
|
|
std::vector<std::vector<DefinedImportData *>> V = binImports(Imports);
|
2015-08-11 07:02:57 +08:00
|
|
|
|
|
|
|
// Create .idata contents for each DLL.
|
2015-08-17 16:30:31 +08:00
|
|
|
for (std::vector<DefinedImportData *> &Syms : V) {
|
|
|
|
StringRef Name = Syms[0]->getDLLName();
|
2015-08-11 07:02:57 +08:00
|
|
|
|
|
|
|
// Create lookup and address tables. If they have external names,
|
|
|
|
// we need to create HintName chunks to store the names.
|
|
|
|
// If they don't (if they are import-by-ordinals), we store only
|
|
|
|
// ordinal values to the table.
|
|
|
|
size_t Base = Lookups.size();
|
|
|
|
for (DefinedImportData *S : Syms) {
|
|
|
|
uint16_t Ord = S->getOrdinal();
|
|
|
|
if (S->getExternalName().empty()) {
|
|
|
|
Lookups.push_back(make_unique<OrdinalOnlyChunk>(Ord));
|
|
|
|
Addresses.push_back(make_unique<OrdinalOnlyChunk>(Ord));
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
auto C = make_unique<HintNameChunk>(S->getExternalName(), Ord);
|
|
|
|
Lookups.push_back(make_unique<LookupChunk>(C.get()));
|
|
|
|
Addresses.push_back(make_unique<LookupChunk>(C.get()));
|
|
|
|
Hints.push_back(std::move(C));
|
|
|
|
}
|
|
|
|
// Terminate with null values.
|
|
|
|
Lookups.push_back(make_unique<NullChunk>(ptrSize()));
|
|
|
|
Addresses.push_back(make_unique<NullChunk>(ptrSize()));
|
|
|
|
|
|
|
|
for (int I = 0, E = Syms.size(); I < E; ++I)
|
|
|
|
Syms[I]->setLocation(Addresses[Base + I].get());
|
|
|
|
|
|
|
|
// Create the import table header.
|
|
|
|
if (!DLLNames.count(Name))
|
|
|
|
DLLNames[Name] = make_unique<StringChunk>(Name);
|
|
|
|
auto Dir = make_unique<ImportDirectoryChunk>(DLLNames[Name].get());
|
|
|
|
Dir->LookupTab = Lookups[Base].get();
|
|
|
|
Dir->AddressTab = Addresses[Base].get();
|
|
|
|
Dirs.push_back(std::move(Dir));
|
|
|
|
}
|
|
|
|
// Add null terminator.
|
|
|
|
Dirs.push_back(make_unique<NullChunk>(sizeof(ImportDirectoryTableEntry)));
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<Chunk *> DelayLoadContents::getChunks() {
|
|
|
|
std::vector<Chunk *> V;
|
|
|
|
for (std::unique_ptr<Chunk> &C : Dirs)
|
|
|
|
V.push_back(C.get());
|
|
|
|
for (std::unique_ptr<Chunk> &C : Names)
|
|
|
|
V.push_back(C.get());
|
|
|
|
for (std::unique_ptr<Chunk> &C : HintNames)
|
|
|
|
V.push_back(C.get());
|
|
|
|
for (auto &P : DLLNames) {
|
|
|
|
std::unique_ptr<Chunk> &C = P.second;
|
|
|
|
V.push_back(C.get());
|
|
|
|
}
|
|
|
|
return V;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<Chunk *> DelayLoadContents::getDataChunks() {
|
|
|
|
std::vector<Chunk *> V;
|
|
|
|
for (std::unique_ptr<Chunk> &C : ModuleHandles)
|
|
|
|
V.push_back(C.get());
|
|
|
|
for (std::unique_ptr<Chunk> &C : Addresses)
|
|
|
|
V.push_back(C.get());
|
|
|
|
return V;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint64_t DelayLoadContents::getDirSize() {
|
|
|
|
return Dirs.size() * sizeof(delay_import_directory_table_entry);
|
|
|
|
}
|
|
|
|
|
|
|
|
void DelayLoadContents::create(Defined *H) {
|
|
|
|
Helper = H;
|
2015-08-17 16:30:31 +08:00
|
|
|
std::vector<std::vector<DefinedImportData *>> V = binImports(Imports);
|
2015-08-11 07:02:57 +08:00
|
|
|
|
|
|
|
// Create .didat contents for each DLL.
|
2015-08-17 16:30:31 +08:00
|
|
|
for (std::vector<DefinedImportData *> &Syms : V) {
|
|
|
|
StringRef Name = Syms[0]->getDLLName();
|
2015-08-11 07:02:57 +08:00
|
|
|
|
|
|
|
// Create the delay import table header.
|
|
|
|
if (!DLLNames.count(Name))
|
|
|
|
DLLNames[Name] = make_unique<StringChunk>(Name);
|
|
|
|
auto Dir = make_unique<DelayDirectoryChunk>(DLLNames[Name].get());
|
|
|
|
|
|
|
|
size_t Base = Addresses.size();
|
|
|
|
for (DefinedImportData *S : Syms) {
|
|
|
|
Chunk *T = newThunkChunk(S, Dir.get());
|
|
|
|
auto A = make_unique<DelayAddressChunk>(T);
|
|
|
|
Addresses.push_back(std::move(A));
|
|
|
|
Thunks.push_back(std::unique_ptr<Chunk>(T));
|
|
|
|
StringRef ExtName = S->getExternalName();
|
|
|
|
if (ExtName.empty()) {
|
|
|
|
Names.push_back(make_unique<OrdinalOnlyChunk>(S->getOrdinal()));
|
|
|
|
} else {
|
|
|
|
auto C = make_unique<HintNameChunk>(ExtName, 0);
|
|
|
|
Names.push_back(make_unique<LookupChunk>(C.get()));
|
|
|
|
HintNames.push_back(std::move(C));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Terminate with null values.
|
|
|
|
Addresses.push_back(make_unique<NullChunk>(8));
|
|
|
|
Names.push_back(make_unique<NullChunk>(8));
|
|
|
|
|
|
|
|
for (int I = 0, E = Syms.size(); I < E; ++I)
|
|
|
|
Syms[I]->setLocation(Addresses[Base + I].get());
|
|
|
|
auto *MH = new NullChunk(8);
|
|
|
|
MH->setAlign(8);
|
|
|
|
ModuleHandles.push_back(std::unique_ptr<Chunk>(MH));
|
|
|
|
|
|
|
|
// Fill the delay import table header fields.
|
|
|
|
Dir->ModuleHandle = MH;
|
|
|
|
Dir->AddressTab = Addresses[Base].get();
|
|
|
|
Dir->NameTab = Names[Base].get();
|
|
|
|
Dirs.push_back(std::move(Dir));
|
|
|
|
}
|
|
|
|
// Add null terminator.
|
|
|
|
Dirs.push_back(
|
|
|
|
make_unique<NullChunk>(sizeof(delay_import_directory_table_entry)));
|
|
|
|
}
|
|
|
|
|
|
|
|
Chunk *DelayLoadContents::newThunkChunk(DefinedImportData *S, Chunk *Dir) {
|
|
|
|
switch (Config->Machine) {
|
|
|
|
case AMD64:
|
|
|
|
return new ThunkChunkX64(S, Dir, Helper);
|
|
|
|
case I386:
|
|
|
|
return new ThunkChunkX86(S, Dir, Helper);
|
|
|
|
default:
|
|
|
|
llvm_unreachable("unsupported machine type");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-17 08:16:33 +08:00
|
|
|
EdataContents::EdataContents() {
|
|
|
|
uint16_t MaxOrdinal = 0;
|
|
|
|
for (Export &E : Config->Exports)
|
|
|
|
MaxOrdinal = std::max(MaxOrdinal, E.Ordinal);
|
|
|
|
|
|
|
|
auto *DLLName = new StringChunk(sys::path::filename(Config->OutputFile));
|
|
|
|
auto *AddressTab = new AddressTableChunk(MaxOrdinal);
|
|
|
|
std::vector<Chunk *> Names;
|
|
|
|
for (Export &E : Config->Exports)
|
|
|
|
if (!E.Noname)
|
COFF: Improve dllexported name mangling compatibility.
The rules for dllexported symbols are overly complicated due to
x86 name decoration, fuzzy symbol resolution, and the fact that
one symbol can be resolved by so many different names. The rules
are probably intended to be "intuitive", so that users don't have
to understand the name mangling schemes, but it seems that it can
lead to unintended symbol exports.
To make it clear what I'm trying to do with this patch, let me
write how the export rules are subtle and complicated.
- x86 name decoration: If machine type is i386 and export name
is given by a command line option, like /export:foo, the
real symbol name the linker has to search for is _foo because
all symbols are decorated with "_" prefixes. This doesn't happen
on non-x86 machines. This automatic name decoration happens only
when the name is not C++ mangled.
However, the symbol name exported from DLLs are ones without "_"
on all platforms.
Moreover, if the option is given via .drectve section, no
symbol decoration is done (the reason being that the .drectve
section is created by a compiler and the compiler should always
know the exact name of the symbol, I guess).
- Fuzzy symbol resolution: In addition to x86 name decoration,
the linker has to look for cdecl or C++ mangled symbols
for a given /export. For example, it searches for not only
_foo but also _foo@<number> or ??foo@... for /export:foo.
Previous implementation didn't get it right. I'm trying to make
it as compatible with MSVC linker as possible with this patch
however the rules are. The new code looks a bit messy to me, but
I don't think it can be simpler due to the ad-hoc-ness of the rules.
llvm-svn: 246424
2015-08-31 16:43:21 +08:00
|
|
|
Names.push_back(new StringChunk(E.ExportName));
|
2016-01-09 09:22:00 +08:00
|
|
|
|
|
|
|
std::vector<Chunk *> Forwards;
|
|
|
|
for (Export &E : Config->Exports) {
|
|
|
|
if (E.ForwardTo.empty())
|
|
|
|
continue;
|
|
|
|
E.ForwardChunk = new StringChunk(E.ForwardTo);
|
|
|
|
Forwards.push_back(E.ForwardChunk);
|
|
|
|
}
|
|
|
|
|
2015-06-17 08:16:33 +08:00
|
|
|
auto *NameTab = new NamePointersChunk(Names);
|
|
|
|
auto *OrdinalTab = new ExportOrdinalChunk(Names.size());
|
|
|
|
auto *Dir = new ExportDirectoryChunk(MaxOrdinal, Names.size(), DLLName,
|
|
|
|
AddressTab, NameTab, OrdinalTab);
|
|
|
|
Chunks.push_back(std::unique_ptr<Chunk>(Dir));
|
|
|
|
Chunks.push_back(std::unique_ptr<Chunk>(DLLName));
|
|
|
|
Chunks.push_back(std::unique_ptr<Chunk>(AddressTab));
|
|
|
|
Chunks.push_back(std::unique_ptr<Chunk>(NameTab));
|
|
|
|
Chunks.push_back(std::unique_ptr<Chunk>(OrdinalTab));
|
|
|
|
for (Chunk *C : Names)
|
|
|
|
Chunks.push_back(std::unique_ptr<Chunk>(C));
|
2016-01-09 09:22:00 +08:00
|
|
|
for (Chunk *C : Forwards)
|
|
|
|
Chunks.push_back(std::unique_ptr<Chunk>(C));
|
2015-06-07 09:15:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace coff
|
|
|
|
} // namespace lld
|