From 2845fb29d8ec227b2dedf83fa606eceaea443ccf Mon Sep 17 00:00:00 2001 From: Rui Ueyama Date: Fri, 17 Oct 2014 22:03:54 +0000 Subject: [PATCH] [PECOFF] Emit x64 delay-import wrapper function Previously we supported x86 only. This patch is to support x64. The array of pointers to delay-loaded functions points the DLL delay loading function at start-up. When a function is called for the first time, the delay loading function gets called and then rewrite the function pointer array. llvm-svn: 220096 --- lld/lib/ReaderWriter/PECOFF/IdataPass.cpp | 60 +++++++++++++++++++---- lld/lib/ReaderWriter/PECOFF/IdataPass.h | 2 +- lld/lib/ReaderWriter/PECOFF/Pass.cpp | 16 ++++++ lld/lib/ReaderWriter/PECOFF/Pass.h | 3 ++ 4 files changed, 71 insertions(+), 10 deletions(-) diff --git a/lld/lib/ReaderWriter/PECOFF/IdataPass.cpp b/lld/lib/ReaderWriter/PECOFF/IdataPass.cpp index 5db2372291cb..538387a5fb72 100644 --- a/lld/lib/ReaderWriter/PECOFF/IdataPass.cpp +++ b/lld/lib/ReaderWriter/PECOFF/IdataPass.cpp @@ -187,17 +187,28 @@ void DelayImportDirectoryAtom::addRelocations( for (int i = 0, e = sharedAtoms.size(); i < e; ++i) { const DefinedAtom *loader = new (_alloc) DelayLoaderAtom( context, addrTable[i], this, delayLoadHelper); - addDir32Reloc(addrTable[i], loader, context.ctx.getMachineType(), 0); + addDir64Reloc(addrTable[i], loader, context.ctx.getMachineType(), 0); } } DelayLoaderAtom::DelayLoaderAtom(IdataContext &context, const Atom *impAtom, const Atom *descAtom, const Atom *delayLoadHelperAtom) - : IdataAtom(context, createContent()) { + : IdataAtom(context, createContent(context.ctx.getMachineType())) { MachineTypes machine = context.ctx.getMachineType(); - addDir32Reloc(this, impAtom, machine, 3); - addDir32Reloc(this, descAtom, machine, 8); - addRel32Reloc(this, delayLoadHelperAtom, machine, 13); + switch (machine) { + case llvm::COFF::IMAGE_FILE_MACHINE_I386: + addDir32Reloc(this, impAtom, machine, 3); + addDir32Reloc(this, descAtom, machine, 8); + addRel32Reloc(this, delayLoadHelperAtom, machine, 13); + break; + case llvm::COFF::IMAGE_FILE_MACHINE_AMD64: + addRel32Reloc(this, impAtom, machine, 36); + addRel32Reloc(this, descAtom, machine, 43); + addRel32Reloc(this, delayLoadHelperAtom, machine, 48); + break; + default: + llvm::report_fatal_error("unsupported machine type"); + } } // DelayLoaderAtom contains a wrapper function for __delayLoadHelper2. @@ -213,9 +224,9 @@ DelayLoaderAtom::DelayLoaderAtom(IdataContext &context, const Atom *impAtom, // function. // // __delayLoadHelper2 is defined in delayimp.lib. -std::vector DelayLoaderAtom::createContent() const { - // NB: x86 only for now. ECX and EDX are caller-save. - static const uint8_t array[] = { +std::vector +DelayLoaderAtom::createContent(MachineTypes machine) const { + static const uint8_t x86[] = { 0x51, // push ecx 0x52, // push edx 0x68, 0, 0, 0, 0, // push offset ___imp__ @@ -225,7 +236,38 @@ std::vector DelayLoaderAtom::createContent() const { 0x59, // pop ecx 0xFF, 0xE0, // jmp eax }; - return std::vector(array, array + sizeof(array)); + static const uint8_t x64[] = { + 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_] + 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 + }; + switch (machine) { + case llvm::COFF::IMAGE_FILE_MACHINE_I386: + return std::vector(x86, x86 + sizeof(x86)); + case llvm::COFF::IMAGE_FILE_MACHINE_AMD64: + return std::vector(x64, x64 + sizeof(x64)); + default: + llvm::report_fatal_error("unsupported machine type"); + } } } // namespace idata diff --git a/lld/lib/ReaderWriter/PECOFF/IdataPass.h b/lld/lib/ReaderWriter/PECOFF/IdataPass.h index 4e01d10371f9..3616df0dd3b8 100644 --- a/lld/lib/ReaderWriter/PECOFF/IdataPass.h +++ b/lld/lib/ReaderWriter/PECOFF/IdataPass.h @@ -185,7 +185,7 @@ public: Alignment alignment() const override { return Alignment(0); } private: - std::vector createContent() const; + std::vector createContent(MachineTypes machine) const; }; } // namespace idata diff --git a/lld/lib/ReaderWriter/PECOFF/Pass.cpp b/lld/lib/ReaderWriter/PECOFF/Pass.cpp index 55c3ef8770ef..255eebd90bf6 100644 --- a/lld/lib/ReaderWriter/PECOFF/Pass.cpp +++ b/lld/lib/ReaderWriter/PECOFF/Pass.cpp @@ -23,6 +23,22 @@ static void addReloc(COFFBaseDefinedAtom *atom, const Atom *target, target, offsetInAtom, relType, arch)); } +void addDir64Reloc(COFFBaseDefinedAtom *atom, const Atom *target, + llvm::COFF::MachineTypes machine, size_t offsetInAtom) { + switch (machine) { + case llvm::COFF::IMAGE_FILE_MACHINE_I386: + addReloc(atom, target, offsetInAtom, Reference::KindArch::x86, + llvm::COFF::IMAGE_REL_I386_DIR32); + return; + case llvm::COFF::IMAGE_FILE_MACHINE_AMD64: + addReloc(atom, target, offsetInAtom, Reference::KindArch::x86_64, + llvm::COFF::IMAGE_REL_AMD64_ADDR64); + return; + default: + llvm_unreachable("unsupported machine type"); + } +} + void addDir32Reloc(COFFBaseDefinedAtom *atom, const Atom *target, llvm::COFF::MachineTypes machine, size_t offsetInAtom) { switch (machine) { diff --git a/lld/lib/ReaderWriter/PECOFF/Pass.h b/lld/lib/ReaderWriter/PECOFF/Pass.h index 290aed4c469e..22466f77859e 100644 --- a/lld/lib/ReaderWriter/PECOFF/Pass.h +++ b/lld/lib/ReaderWriter/PECOFF/Pass.h @@ -16,6 +16,9 @@ namespace lld { namespace pecoff { +void addDir64Reloc(COFFBaseDefinedAtom *atom, const Atom *target, + llvm::COFF::MachineTypes machine, size_t offsetInAtom); + void addDir32Reloc(COFFBaseDefinedAtom *atom, const Atom *target, llvm::COFF::MachineTypes machine, size_t offsetInAtom);