[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