forked from OSchip/llvm-project
[PECOFF] Support delay-load import table for x86
This patch creates the import address table and sets its address to the delay-load import table. This also creates wrapper functions for __delayLoadHelper2. x86 only for now. llvm-svn: 219948
This commit is contained in:
parent
ec81c0b40d
commit
b38b96ab4c
|
@ -262,6 +262,10 @@ public:
|
|||
std::vector<ExportDesc> &getDllExports() { return _dllExports; }
|
||||
const std::vector<ExportDesc> &getDllExports() const { return _dllExports; }
|
||||
|
||||
StringRef getDelayLoadHelperName() const {
|
||||
return is64Bit() ? "__delayLoadHelper2" : "___delayLoadHelper2@8";
|
||||
}
|
||||
|
||||
StringRef allocate(StringRef ref) const {
|
||||
_allocMutex.lock();
|
||||
char *x = _allocator.Allocate<char>(ref.size() + 1);
|
||||
|
|
|
@ -1226,6 +1226,7 @@ bool WinLinkDriver::parse(int argc, const char *argv[],
|
|||
break;
|
||||
|
||||
case OPT_delayload:
|
||||
ctx.addInitialUndefinedSymbol(ctx.getDelayLoadHelperName());
|
||||
ctx.addDelayLoadDLL(inputArg->getValue());
|
||||
break;
|
||||
|
||||
|
|
|
@ -131,30 +131,101 @@ std::vector<uint8_t> DelayImportDirectoryAtom::createContent() {
|
|||
return r;
|
||||
}
|
||||
|
||||
// Find "___delayLoadHelper2@8" (or "__delayLoadHelper2" on x64).
|
||||
// This is not efficient but should be OK for now.
|
||||
static const Atom *
|
||||
findDelayLoadHelper(MutableFile &file, const PECOFFLinkingContext &ctx) {
|
||||
StringRef sym = ctx.getDelayLoadHelperName();
|
||||
for (const DefinedAtom *atom : file.defined())
|
||||
if (atom->name() == sym)
|
||||
return atom;
|
||||
std::string msg = (sym + " was not found").str();
|
||||
llvm_unreachable(msg.c_str());
|
||||
}
|
||||
|
||||
// Create the data referred by the delay-import table.
|
||||
void DelayImportDirectoryAtom::addRelocations(
|
||||
IdataContext &context, StringRef loadName,
|
||||
const std::vector<COFFSharedLibraryAtom *> &sharedAtoms) {
|
||||
// "ModuleHandle" field
|
||||
auto *hmodule = new (_alloc) DelayImportHModuleAtom(context);
|
||||
// "ModuleHandle" field. This points to an array of pointer-size data
|
||||
// in ".data" section. Initially the array is initialized with zero.
|
||||
// The delay-load import helper will set DLL base address at runtime.
|
||||
auto *hmodule = new (_alloc) DelayImportAddressAtom(context);
|
||||
addDir32NBReloc(this, hmodule, context.ctx.getMachineType(),
|
||||
offsetof(delay_import_directory_table_entry, ModuleHandle));
|
||||
|
||||
// "NameTable" field
|
||||
// "NameTable" field. The data structure of this field is the same
|
||||
// as (non-delay) import table's Import Lookup Table. Contains
|
||||
// imported function names. This is a parallel array of AddressTable
|
||||
// field.
|
||||
std::vector<ImportTableEntryAtom *> nameTable =
|
||||
createImportTableAtoms(context, sharedAtoms, true, ".didat", _alloc);
|
||||
createImportTableAtoms(context, sharedAtoms, false, ".didat", _alloc);
|
||||
addDir32NBReloc(
|
||||
this, nameTable[0], context.ctx.getMachineType(),
|
||||
offsetof(delay_import_directory_table_entry, DelayImportNameTable));
|
||||
|
||||
// "Name" field
|
||||
// "Name" field. This points to the NUL-terminated DLL name string.
|
||||
auto *name = new (_alloc)
|
||||
COFFStringAtom(context.dummyFile, context.dummyFile.getNextOrdinal(),
|
||||
".didat", loadName);
|
||||
context.file.addAtom(*name);
|
||||
addDir32NBReloc(this, name, context.ctx.getMachineType(),
|
||||
offsetof(delay_import_directory_table_entry, Name));
|
||||
// TODO: emit other fields
|
||||
|
||||
// "AddressTable" field. This points to an array of pointers, which
|
||||
// in turn pointing to delay-load functions.
|
||||
std::vector<DelayImportAddressAtom *> addrTable;
|
||||
for (int i = 0, e = sharedAtoms.size() + 1; i < e; ++i)
|
||||
addrTable.push_back(new (_alloc) DelayImportAddressAtom(context));
|
||||
for (int i = 0, e = sharedAtoms.size(); i < e; ++i)
|
||||
sharedAtoms[i]->setImportTableEntry(addrTable[i]);
|
||||
addDir32NBReloc(
|
||||
this, addrTable[0], context.ctx.getMachineType(),
|
||||
offsetof(delay_import_directory_table_entry, DelayImportAddressTable));
|
||||
|
||||
const Atom *delayLoadHelper = findDelayLoadHelper(context.file, context.ctx);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
DelayLoaderAtom::DelayLoaderAtom(IdataContext &context, const Atom *impAtom,
|
||||
const Atom *descAtom, const Atom *delayLoadHelperAtom)
|
||||
: IdataAtom(context, createContent()) {
|
||||
MachineTypes machine = context.ctx.getMachineType();
|
||||
addDir32Reloc(this, impAtom, machine, 3);
|
||||
addDir32Reloc(this, descAtom, machine, 8);
|
||||
addRel32Reloc(this, delayLoadHelperAtom, machine, 13);
|
||||
}
|
||||
|
||||
// DelayLoaderAtom contains a wrapper function for __delayLoadHelper2.
|
||||
//
|
||||
// __delayLoadHelper2 takes two pointers: a pointer to the delay-load
|
||||
// table descripter and a pointer to _imp_ symbol for the function
|
||||
// to be resolved.
|
||||
//
|
||||
// __delayLoadHelper2 looks at the table descriptor to know the DLL
|
||||
// name, calls dlopen()-like function to load it, resolves all
|
||||
// imported symbols, and then writes the resolved addresses to the
|
||||
// import address table. It returns a pointer to the resolved
|
||||
// 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[] = {
|
||||
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
|
||||
};
|
||||
return std::vector<uint8_t>(array, array + sizeof(array));
|
||||
}
|
||||
|
||||
} // namespace idata
|
||||
|
|
|
@ -161,9 +161,9 @@ private:
|
|||
}
|
||||
};
|
||||
|
||||
class DelayImportHModuleAtom : public IdataAtom {
|
||||
class DelayImportAddressAtom : public IdataAtom {
|
||||
public:
|
||||
explicit DelayImportHModuleAtom(IdataContext &context)
|
||||
explicit DelayImportAddressAtom(IdataContext &context)
|
||||
: IdataAtom(context, createContent(context.ctx)) {}
|
||||
StringRef customSectionName() const override { return ".data"; }
|
||||
ContentPermissions permissions() const override { return permRW_; }
|
||||
|
@ -175,6 +175,19 @@ private:
|
|||
}
|
||||
};
|
||||
|
||||
// DelayLoaderAtom contains a wrapper function for __delayLoadHelper2.
|
||||
class DelayLoaderAtom : public IdataAtom {
|
||||
public:
|
||||
DelayLoaderAtom(IdataContext &context, const Atom *impAtom,
|
||||
const Atom *descAtom, const Atom *delayLoadHelperAtom);
|
||||
StringRef customSectionName() const override { return ".text"; }
|
||||
ContentPermissions permissions() const override { return permR_X; }
|
||||
Alignment alignment() const override { return Alignment(0); }
|
||||
|
||||
private:
|
||||
std::vector<uint8_t> createContent() const;
|
||||
};
|
||||
|
||||
} // namespace idata
|
||||
|
||||
class IdataPass : public lld::Pass {
|
||||
|
|
|
@ -55,5 +55,21 @@ void addDir32NBReloc(COFFBaseDefinedAtom *atom, const Atom *target,
|
|||
}
|
||||
}
|
||||
|
||||
void addRel32Reloc(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_REL32);
|
||||
return;
|
||||
case llvm::COFF::IMAGE_FILE_MACHINE_AMD64:
|
||||
addReloc(atom, target, offsetInAtom, Reference::KindArch::x86_64,
|
||||
llvm::COFF::IMAGE_REL_AMD64_REL32);
|
||||
return;
|
||||
default:
|
||||
llvm_unreachable("unsupported machine type");
|
||||
}
|
||||
}
|
||||
|
||||
} // end namespace pecoff
|
||||
} // end namespace lld
|
||||
|
|
|
@ -22,6 +22,9 @@ void addDir32Reloc(COFFBaseDefinedAtom *atom, const Atom *target,
|
|||
void addDir32NBReloc(COFFBaseDefinedAtom *atom, const Atom *target,
|
||||
llvm::COFF::MachineTypes machine, size_t offsetInAtom);
|
||||
|
||||
void addRel32Reloc(COFFBaseDefinedAtom *atom, const Atom *target,
|
||||
llvm::COFF::MachineTypes machine, size_t offsetInAtom);
|
||||
|
||||
} // namespace pecoff
|
||||
} // namespace lld
|
||||
|
||||
|
|
|
@ -48,6 +48,12 @@ symbols:
|
|||
SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
ComplexType: IMAGE_SYM_DTYPE_FUNCTION
|
||||
StorageClass: IMAGE_SYM_CLASS_EXTERNAL
|
||||
- Name: "__delayLoadHelper2"
|
||||
Value: 0
|
||||
SectionNumber: 1
|
||||
SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
ComplexType: IMAGE_SYM_DTYPE_NULL
|
||||
StorageClass: IMAGE_SYM_CLASS_EXTERNAL
|
||||
- Name: __imp_var
|
||||
Value: 0
|
||||
SectionNumber: 0
|
||||
|
|
|
@ -48,6 +48,12 @@ symbols:
|
|||
SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
ComplexType: IMAGE_SYM_DTYPE_FUNCTION
|
||||
StorageClass: IMAGE_SYM_CLASS_EXTERNAL
|
||||
- Name: "___delayLoadHelper2@8"
|
||||
Value: 0
|
||||
SectionNumber: 1
|
||||
SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
ComplexType: IMAGE_SYM_DTYPE_NULL
|
||||
StorageClass: IMAGE_SYM_CLASS_EXTERNAL
|
||||
- Name: __imp__var
|
||||
Value: 0
|
||||
SectionNumber: 0
|
||||
|
|
|
@ -13,7 +13,7 @@ X86: DelayImport {
|
|||
X86-NEXT: Name: vars.dll
|
||||
X86-NEXT: Attributes: 0x1
|
||||
X86-NEXT: ModuleHandle: 0x1000
|
||||
X86-NEXT: ImportAddressTable: 0x0
|
||||
X86-NEXT: ImportAddressTable: 0x1008
|
||||
X86-NEXT: ImportNameTable: 0x2000
|
||||
X86-NEXT: BoundDelayImportTable: 0x0
|
||||
X86-NEXT: UnloadDelayImportTable: 0x0
|
||||
|
@ -26,7 +26,7 @@ X64: DelayImport {
|
|||
X64-NEXT: Name: vars64.dll
|
||||
X64-NEXT: Attributes: 0x1
|
||||
X64-NEXT: ModuleHandle: 0x1000
|
||||
X64-NEXT: ImportAddressTable: 0x0
|
||||
X64-NEXT: ImportAddressTable: 0x1008
|
||||
X64-NEXT: ImportNameTable: 0x2000
|
||||
X64-NEXT: BoundDelayImportTable: 0x0
|
||||
X64-NEXT: UnloadDelayImportTable: 0x0
|
||||
|
|
Loading…
Reference in New Issue