summaryrefslogtreecommitdiffstats
path: root/lld/COFF/DLL.cpp
diff options
context:
space:
mode:
authorRui Ueyama <ruiu@google.com>2015-06-21 22:31:52 +0000
committerRui Ueyama <ruiu@google.com>2015-06-21 22:31:52 +0000
commita77336bd5dc4eb2f3cf300a88c918aa2f7d4c108 (patch)
treec2bd1a08b5c6ecf0b3b5641cdcc6f19fc5bb7e7c /lld/COFF/DLL.cpp
parent5055f6dfe0df092ae81a838223f2216353c16064 (diff)
downloadbcm5719-llvm-a77336bd5dc4eb2f3cf300a88c918aa2f7d4c108.tar.gz
bcm5719-llvm-a77336bd5dc4eb2f3cf300a88c918aa2f7d4c108.zip
COFF: Support delay-load import tables.
DLLs are usually resolved at process startup, but you can delay-load them by passing /delayload option to the linker. If a /delayload is specified, the linker has to create data which is similar to regular import table. One notable difference is that the pointers in a delay-load import table are originally pointing to thunks that resolves themselves. Each thunk loads a DLL, resolve its name, and then overwrites the pointer with the result so that subsequent function calls directly call a desired function. The linker has to emit thunks. llvm-svn: 240250
Diffstat (limited to 'lld/COFF/DLL.cpp')
-rw-r--r--lld/COFF/DLL.cpp173
1 files changed, 163 insertions, 10 deletions
diff --git a/lld/COFF/DLL.cpp b/lld/COFF/DLL.cpp
index 288558b7580..c8a2c7202b2 100644
--- a/lld/COFF/DLL.cpp
+++ b/lld/COFF/DLL.cpp
@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
//
-// This file defines various types of chunks for the DLL import
-// descriptor table. They are inherently Windows-specific.
+// This file defines various types of chunks for the DLL import or export
+// descriptor tables. They are inherently Windows-specific.
// You need to read Microsoft PE/COFF spec to understand details
// about the data structures.
//
@@ -114,6 +114,7 @@ public:
explicit NullChunk(size_t N) : Size(N) {}
bool hasData() const override { return false; }
size_t getSize() const override { return Size; }
+ void setAlign(size_t N) { Align = N; }
private:
size_t Size;
@@ -149,23 +150,33 @@ std::vector<Chunk *> IdataContents::getChunks() {
return V;
}
-void IdataContents::create() {
+static std::map<StringRef, 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 *>> Map;
+ std::map<StringRef, std::vector<DefinedImportData *>> M;
for (DefinedImportData *Sym : Imports)
- Map[Sym->getDLLName()].push_back(Sym);
-
- // Create .idata contents for each DLL.
- for (auto &P : Map) {
- StringRef Name = P.first;
- std::vector<DefinedImportData *> &Syms = P.second;
+ M[Sym->getDLLName()].push_back(Sym);
+ for (auto &P : M) {
// Sort symbols by name for each group.
+ std::vector<DefinedImportData *> &Syms = P.second;
std::sort(Syms.begin(), Syms.end(),
[](DefinedImportData *A, DefinedImportData *B) {
return A->getName() < B->getName();
});
+ }
+ return M;
+}
+
+void IdataContents::create() {
+ std::map<StringRef, std::vector<DefinedImportData *>> Map =
+ binImports(Imports);
+
+ // Create .idata contents for each DLL.
+ for (auto &P : Map) {
+ StringRef Name = P.first;
+ std::vector<DefinedImportData *> &Syms = P.second;
// Create lookup and address tables. If they have external names,
// we need to create HintName chunks to store the names.
@@ -204,6 +215,148 @@ void IdataContents::create() {
}
// 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);
+ }
+
+ void writeTo(uint8_t *Buf) override {
+ auto *E = (delay_import_directory_table_entry *)(Buf + FileOff);
+ 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.
+// This code calls __delayLoadHerper2 function to resolve a symbol
+// and then overwrites its jump table slot with the result
+// for subsequent function calls.
+static const uint8_t Thunk[] = {
+ 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
+};
+
+// A chunk for the delay import thunk.
+class ThunkChunk : public Chunk {
+public:
+ ThunkChunk(Defined *I, Defined *H) : Imp(I), Helper(H) {}
+
+ size_t getSize() const override { return sizeof(Thunk); }
+
+ void writeTo(uint8_t *Buf) override {
+ memcpy(Buf + FileOff, Thunk, sizeof(Thunk));
+ write32le(Buf + FileOff + 36, Imp->getRVA());
+ write32le(Buf + FileOff + 43, Desc->getRVA());
+ write32le(Buf + FileOff + 48, Helper->getRVA());
+ }
+
+ Defined *Imp = nullptr;
+ Chunk *Desc = nullptr;
+ Defined *Helper = nullptr;
+};
+
+std::vector<Chunk *> DelayLoadContents::getChunks(Defined *H) {
+ Helper = H;
+ create();
+ std::vector<Chunk *> V;
+ for (std::unique_ptr<Chunk> &C : Dirs)
+ V.push_back(C.get());
+ for (std::unique_ptr<Chunk> &C : Addresses)
+ 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;
+}
+
+uint64_t DelayLoadContents::getDirSize() {
+ return Dirs.size() * sizeof(delay_import_directory_table_entry);
+}
+
+void DelayLoadContents::create() {
+ std::map<StringRef, std::vector<DefinedImportData *>> Map =
+ binImports(Imports);
+
+ // Create .didat contents for each DLL.
+ for (auto &P : Map) {
+ StringRef Name = P.first;
+ std::vector<DefinedImportData *> &Syms = P.second;
+
+ size_t Base = Addresses.size();
+ for (DefinedImportData *S : Syms) {
+ auto T = make_unique<ThunkChunk>(S, Helper);
+ auto A = make_unique<LookupChunk>(T.get());
+ T->Desc = A.get();
+ Addresses.push_back(std::move(A));
+ Thunks.push_back(std::move(T));
+ auto C =
+ make_unique<HintNameChunk>(S->getExternalName(), S->getOrdinal());
+ Names.push_back(make_unique<LookupChunk>(C.get()));
+ HintNames.push_back(std::move(C));
+ }
+ // Terminate with null values.
+ Addresses.push_back(make_unique<NullChunk>(LookupChunkSize));
+ Names.push_back(make_unique<NullChunk>(LookupChunkSize));
+
+ 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));
+
+ // Create the delay import table header.
+ if (!DLLNames.count(Name))
+ DLLNames[Name] = make_unique<StringChunk>(Name);
+ auto Dir = make_unique<DelayDirectoryChunk>(DLLNames[Name].get());
+ 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)));
+}
+
+// Export table
// Read Microsoft PE/COFF spec 5.3 for details.
// A chunk for the export descriptor table.
OpenPOWER on IntegriCloud