[lld] r219948 - [PECOFF] Support delay-load import table for x86
Rui Ueyama
ruiu at google.com
Thu Oct 16 12:30:45 PDT 2014
Author: ruiu
Date: Thu Oct 16 14:30:44 2014
New Revision: 219948
URL: http://llvm.org/viewvc/llvm-project?rev=219948&view=rev
Log:
[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.
Modified:
lld/trunk/include/lld/ReaderWriter/PECOFFLinkingContext.h
lld/trunk/lib/Driver/WinLinkDriver.cpp
lld/trunk/lib/ReaderWriter/PECOFF/IdataPass.cpp
lld/trunk/lib/ReaderWriter/PECOFF/IdataPass.h
lld/trunk/lib/ReaderWriter/PECOFF/Pass.cpp
lld/trunk/lib/ReaderWriter/PECOFF/Pass.h
lld/trunk/test/pecoff/Inputs/vars-main-x64.obj.yaml
lld/trunk/test/pecoff/Inputs/vars-main-x86.obj.yaml
lld/trunk/test/pecoff/delayimport.test
Modified: lld/trunk/include/lld/ReaderWriter/PECOFFLinkingContext.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/ReaderWriter/PECOFFLinkingContext.h?rev=219948&r1=219947&r2=219948&view=diff
==============================================================================
--- lld/trunk/include/lld/ReaderWriter/PECOFFLinkingContext.h (original)
+++ lld/trunk/include/lld/ReaderWriter/PECOFFLinkingContext.h Thu Oct 16 14:30:44 2014
@@ -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 at 8";
+ }
+
StringRef allocate(StringRef ref) const {
_allocMutex.lock();
char *x = _allocator.Allocate<char>(ref.size() + 1);
Modified: lld/trunk/lib/Driver/WinLinkDriver.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Driver/WinLinkDriver.cpp?rev=219948&r1=219947&r2=219948&view=diff
==============================================================================
--- lld/trunk/lib/Driver/WinLinkDriver.cpp (original)
+++ lld/trunk/lib/Driver/WinLinkDriver.cpp Thu Oct 16 14:30:44 2014
@@ -1226,6 +1226,7 @@ bool WinLinkDriver::parse(int argc, cons
break;
case OPT_delayload:
+ ctx.addInitialUndefinedSymbol(ctx.getDelayLoadHelperName());
ctx.addDelayLoadDLL(inputArg->getValue());
break;
Modified: lld/trunk/lib/ReaderWriter/PECOFF/IdataPass.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/PECOFF/IdataPass.cpp?rev=219948&r1=219947&r2=219948&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/PECOFF/IdataPass.cpp (original)
+++ lld/trunk/lib/ReaderWriter/PECOFF/IdataPass.cpp Thu Oct 16 14:30:44 2014
@@ -131,30 +131,101 @@ std::vector<uint8_t> DelayImportDirector
return r;
}
+// Find "___delayLoadHelper2 at 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 at 8
+ 0x5A, // pop edx
+ 0x59, // pop ecx
+ 0xFF, 0xE0, // jmp eax
+ };
+ return std::vector<uint8_t>(array, array + sizeof(array));
}
} // namespace idata
Modified: lld/trunk/lib/ReaderWriter/PECOFF/IdataPass.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/PECOFF/IdataPass.h?rev=219948&r1=219947&r2=219948&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/PECOFF/IdataPass.h (original)
+++ lld/trunk/lib/ReaderWriter/PECOFF/IdataPass.h Thu Oct 16 14:30:44 2014
@@ -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 {
Modified: lld/trunk/lib/ReaderWriter/PECOFF/Pass.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/PECOFF/Pass.cpp?rev=219948&r1=219947&r2=219948&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/PECOFF/Pass.cpp (original)
+++ lld/trunk/lib/ReaderWriter/PECOFF/Pass.cpp Thu Oct 16 14:30:44 2014
@@ -55,5 +55,21 @@ void addDir32NBReloc(COFFBaseDefinedAtom
}
}
+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
Modified: lld/trunk/lib/ReaderWriter/PECOFF/Pass.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/PECOFF/Pass.h?rev=219948&r1=219947&r2=219948&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/PECOFF/Pass.h (original)
+++ lld/trunk/lib/ReaderWriter/PECOFF/Pass.h Thu Oct 16 14:30:44 2014
@@ -22,6 +22,9 @@ void addDir32Reloc(COFFBaseDefinedAtom *
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
Modified: lld/trunk/test/pecoff/Inputs/vars-main-x64.obj.yaml
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/pecoff/Inputs/vars-main-x64.obj.yaml?rev=219948&r1=219947&r2=219948&view=diff
==============================================================================
--- lld/trunk/test/pecoff/Inputs/vars-main-x64.obj.yaml (original)
+++ lld/trunk/test/pecoff/Inputs/vars-main-x64.obj.yaml Thu Oct 16 14:30:44 2014
@@ -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
Modified: lld/trunk/test/pecoff/Inputs/vars-main-x86.obj.yaml
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/pecoff/Inputs/vars-main-x86.obj.yaml?rev=219948&r1=219947&r2=219948&view=diff
==============================================================================
--- lld/trunk/test/pecoff/Inputs/vars-main-x86.obj.yaml (original)
+++ lld/trunk/test/pecoff/Inputs/vars-main-x86.obj.yaml Thu Oct 16 14:30:44 2014
@@ -48,6 +48,12 @@ symbols:
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_FUNCTION
StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: "___delayLoadHelper2 at 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
Modified: lld/trunk/test/pecoff/delayimport.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/pecoff/delayimport.test?rev=219948&r1=219947&r2=219948&view=diff
==============================================================================
--- lld/trunk/test/pecoff/delayimport.test (original)
+++ lld/trunk/test/pecoff/delayimport.test Thu Oct 16 14:30:44 2014
@@ -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
More information about the llvm-commits
mailing list