[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
This commit is contained in:
Rui Ueyama 2014-10-17 22:03:54 +00:00
parent 39e4bb3bc5
commit 2845fb29d8
4 changed files with 71 additions and 10 deletions

View File

@ -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<uint8_t> DelayLoaderAtom::createContent() const {
// NB: x86 only for now. ECX and EDX are caller-save.
static const uint8_t array[] = {
std::vector<uint8_t>
DelayLoaderAtom::createContent(MachineTypes machine) const {
static const uint8_t x86[] = {
0x51, // push ecx
0x52, // push edx
0x68, 0, 0, 0, 0, // push offset ___imp__<FUNCNAME>
@ -225,7 +236,38 @@ std::vector<uint8_t> DelayLoaderAtom::createContent() const {
0x59, // pop ecx
0xFF, 0xE0, // jmp eax
};
return std::vector<uint8_t>(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_<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
};
switch (machine) {
case llvm::COFF::IMAGE_FILE_MACHINE_I386:
return std::vector<uint8_t>(x86, x86 + sizeof(x86));
case llvm::COFF::IMAGE_FILE_MACHINE_AMD64:
return std::vector<uint8_t>(x64, x64 + sizeof(x64));
default:
llvm::report_fatal_error("unsupported machine type");
}
}
} // namespace idata

View File

@ -185,7 +185,7 @@ public:
Alignment alignment() const override { return Alignment(0); }
private:
std::vector<uint8_t> createContent() const;
std::vector<uint8_t> createContent(MachineTypes machine) const;
};
} // namespace idata

View File

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

View File

@ -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);