[lld] r219384 - [PECOFF] Emit the delay-import table
Rui Ueyama
ruiu at google.com
Wed Oct 8 19:48:15 PDT 2014
Author: ruiu
Date: Wed Oct 8 21:48:14 2014
New Revision: 219384
URL: http://llvm.org/viewvc/llvm-project?rev=219384&view=rev
Log:
[PECOFF] Emit the delay-import table
This is a partial patch to emit the delay-import table. With this,
LLD is now able to emit the table that llvm-readobj can read and
dump.
The table lacks a few fields, such as the address of HMODULE, the
import address table, etc. They'll be added in subsequent patches.
Added:
lld/trunk/test/pecoff/Inputs/vars64.lib
Modified:
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/WriterPECOFF.cpp
lld/trunk/test/pecoff/delayimport.test
Modified: lld/trunk/lib/Driver/WinLinkDriver.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Driver/WinLinkDriver.cpp?rev=219384&r1=219383&r2=219384&view=diff
==============================================================================
--- lld/trunk/lib/Driver/WinLinkDriver.cpp (original)
+++ lld/trunk/lib/Driver/WinLinkDriver.cpp Wed Oct 8 21:48:14 2014
@@ -1227,8 +1227,6 @@ bool WinLinkDriver::parse(int argc, cons
case OPT_delayload:
ctx.addDelayLoadDLL(inputArg->getValue());
- ctx.addInitialUndefinedSymbol(
- ctx.is64Bit() ? "__delayLoadHelper2" : "___delayLoadHelper2 at 8");
break;
case OPT_stub: {
Modified: lld/trunk/lib/ReaderWriter/PECOFF/IdataPass.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/PECOFF/IdataPass.cpp?rev=219384&r1=219383&r2=219384&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/PECOFF/IdataPass.cpp (original)
+++ lld/trunk/lib/ReaderWriter/PECOFF/IdataPass.cpp Wed Oct 8 21:48:14 2014
@@ -21,6 +21,9 @@
#include <cstddef>
#include <cstring>
#include <map>
+#include <vector>
+
+using llvm::object::delay_import_directory_table_entry;
namespace lld {
namespace pecoff {
@@ -119,6 +122,36 @@ void ImportDirectoryAtom::addRelocations
offsetof(ImportDirectoryTableEntry, NameRVA));
}
+// Create the contents for the delay-import table.
+std::vector<uint8_t> DelayImportDirectoryAtom::createContent() {
+ std::vector<uint8_t> r(sizeof(delay_import_directory_table_entry), 0);
+ auto entry = reinterpret_cast<delay_import_directory_table_entry *>(&r[0]);
+ // link.exe seems to set 1 to Attributes field, so do we.
+ entry->Attributes = 1;
+ return r;
+}
+
+// Create the data referred by the delay-import table.
+void DelayImportDirectoryAtom::addRelocations(
+ IdataContext &context, StringRef loadName,
+ const std::vector<COFFSharedLibraryAtom *> &sharedAtoms) {
+ // "NameTable" field
+ std::vector<ImportTableEntryAtom *> nameTable =
+ createImportTableAtoms(context, sharedAtoms, true, ".didat", _alloc);
+ addDir32NBReloc(
+ this, nameTable[0], context.ctx.getMachineType(),
+ offsetof(delay_import_directory_table_entry, DelayImportNameTable));
+
+ // "Name" field
+ auto *atom = new (_alloc)
+ COFFStringAtom(context.dummyFile, context.dummyFile.getNextOrdinal(),
+ ".didat", loadName);
+ context.file.addAtom(*atom);
+ addDir32NBReloc(this, atom, context.ctx.getMachineType(),
+ offsetof(delay_import_directory_table_entry, Name));
+ // TODO: emit other fields
+}
+
} // namespace idata
void IdataPass::perform(std::unique_ptr<MutableFile> &file) {
@@ -128,15 +161,32 @@ void IdataPass::perform(std::unique_ptr<
idata::IdataContext context(*file, _dummyFile, _ctx);
std::map<StringRef, std::vector<COFFSharedLibraryAtom *>> sharedAtoms =
groupByLoadName(*file);
+ bool hasImports = false;
+ bool hasDelayImports = false;
+
+ // Create the import table and terminate it with the null entry.
for (auto i : sharedAtoms) {
StringRef loadName = i.first;
+ if (_ctx.isDelayLoadDLL(loadName))
+ continue;
+ hasImports = true;
std::vector<COFFSharedLibraryAtom *> &atoms = i.second;
new (_alloc) idata::ImportDirectoryAtom(context, loadName, atoms);
}
+ if (hasImports)
+ new (_alloc) idata::NullImportDirectoryAtom(context);
- // All atoms, including those of tyep NullImportDirectoryAtom, are added to
- // context.file in the IdataAtom's constructor.
- new (_alloc) idata::NullImportDirectoryAtom(context);
+ // Create the delay import table and terminate it with the null entry.
+ for (auto i : sharedAtoms) {
+ StringRef loadName = i.first;
+ if (!_ctx.isDelayLoadDLL(loadName))
+ continue;
+ hasDelayImports = true;
+ std::vector<COFFSharedLibraryAtom *> &atoms = i.second;
+ new (_alloc) idata::DelayImportDirectoryAtom(context, loadName, atoms);
+ }
+ if (hasDelayImports)
+ new (_alloc) idata::DelayNullImportDirectoryAtom(context);
replaceSharedLibraryAtoms(*file);
}
Modified: lld/trunk/lib/ReaderWriter/PECOFF/IdataPass.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/PECOFF/IdataPass.h?rev=219384&r1=219383&r2=219384&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/PECOFF/IdataPass.h (original)
+++ lld/trunk/lib/ReaderWriter/PECOFF/IdataPass.h Wed Oct 8 21:48:14 2014
@@ -126,6 +126,41 @@ public:
StringRef customSectionName() const override { return ".idata.d"; }
};
+/// The class for the the delay-load import table.
+class DelayImportDirectoryAtom : public IdataAtom {
+public:
+ DelayImportDirectoryAtom(
+ IdataContext &context, StringRef loadName,
+ const std::vector<COFFSharedLibraryAtom *> &sharedAtoms)
+ : IdataAtom(context, createContent()) {
+ addRelocations(context, loadName, sharedAtoms);
+ }
+
+ StringRef customSectionName() const override { return ".didat.d"; }
+
+private:
+ std::vector<uint8_t> createContent();
+ void addRelocations(IdataContext &context, StringRef loadName,
+ const std::vector<COFFSharedLibraryAtom *> &sharedAtoms);
+
+ mutable llvm::BumpPtrAllocator _alloc;
+};
+
+/// Terminator of the delay-load import table. The content of this atom is all
+/// zero.
+class DelayNullImportDirectoryAtom : public IdataAtom {
+public:
+ explicit DelayNullImportDirectoryAtom(IdataContext &context)
+ : IdataAtom(context, createContent()) {}
+ StringRef customSectionName() const override { return ".didat.d"; }
+
+private:
+ std::vector<uint8_t> createContent() const {
+ return std::vector<uint8_t>(
+ sizeof(llvm::object::delay_import_directory_table_entry), 0);
+ }
+};
+
} // namespace idata
class IdataPass : public lld::Pass {
Modified: lld/trunk/lib/ReaderWriter/PECOFF/WriterPECOFF.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/PECOFF/WriterPECOFF.cpp?rev=219384&r1=219383&r2=219384&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/PECOFF/WriterPECOFF.cpp (original)
+++ lld/trunk/lib/ReaderWriter/PECOFF/WriterPECOFF.cpp Wed Oct 8 21:48:14 2014
@@ -1043,6 +1043,7 @@ void PECOFFWriter::build(const File &lin
.Case(".idata.d", DataDirectoryIndex::IMPORT_TABLE)
.Case(".edata", DataDirectoryIndex::EXPORT_TABLE)
.Case(".loadcfg", DataDirectoryIndex::LOAD_CONFIG_TABLE)
+ .Case(".didat.d", DataDirectoryIndex::DELAY_IMPORT_DESCRIPTOR)
.Default(ignore);
if (idx == ignore)
continue;
Added: lld/trunk/test/pecoff/Inputs/vars64.lib
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/pecoff/Inputs/vars64.lib?rev=219384&view=auto
==============================================================================
Binary files lld/trunk/test/pecoff/Inputs/vars64.lib (added) and lld/trunk/test/pecoff/Inputs/vars64.lib Wed Oct 8 21:48:14 2014 differ
Modified: lld/trunk/test/pecoff/delayimport.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/pecoff/delayimport.test?rev=219384&r1=219383&r2=219384&view=diff
==============================================================================
--- lld/trunk/test/pecoff/delayimport.test (original)
+++ lld/trunk/test/pecoff/delayimport.test Wed Oct 8 21:48:14 2014
@@ -1,13 +1,36 @@
# RUN: yaml2obj %p/Inputs/vars-main-x86.obj.yaml > %t-x86.obj
# RUN: yaml2obj %p/Inputs/vars-main-x64.obj.yaml > %t-x64.obj
#
-# RUN: not lld -flavor link /out:%t.exe /subsystem:console /entry:main \
-# RUN: /delayload:vars.dll -- %t-x86.obj %p/Inputs/vars.lib 2>&1 \
-# RUN: | FileCheck -check-prefix=X86 %s
+# RUN: lld -flavor link /out:%t1.exe /subsystem:console /entry:main \
+# RUN: /delayload:vars.dll -- %t-x86.obj %p/Inputs/vars.lib
+# RUN: llvm-readobj -coff-imports %t1.exe | FileCheck -check-prefix=X86 %s
#
-# RUN: not lld -flavor link /out:%t.exe /subsystem:console /entry:main \
-# RUN: /machine:x64 /delayload:vars.dll -- %t-x64.obj %p/Inputs/vars.lib 2>&1 \
-# RUN: | FileCheck -check-prefix=X64 %s
+# RUN: lld -flavor link /out:%t2.exe /subsystem:console /entry:main \
+# RUN: /machine:x64 /delayload:vars64.dll -- %t-x64.obj %p/Inputs/vars64.lib
+# RUN: llvm-readobj -coff-imports %t2.exe | FileCheck -check-prefix=X64 %s
-X86: Undefined symbol: {{.*}} ___delayLoadHelper2 at 8
-X64: Undefined symbol: {{.*}} __delayLoadHelper2
+X86: DelayImport {
+X86-NEXT: Name: vars.dll
+X86-NEXT: Attributes: 0x1
+X86-NEXT: ModuleHandle: 0x0
+X86-NEXT: ImportAddressTable: 0x0
+X86-NEXT: ImportNameTable: 0x1000
+X86-NEXT: BoundDelayImportTable: 0x0
+X86-NEXT: UnloadDelayImportTable: 0x0
+X86-NEXT: Symbol: _name_with_underscore (0)
+X86-NEXT: Symbol: fn (1)
+X86-NEXT: Symbol: (1)
+X86-NEXT: }
+
+X64: DelayImport {
+X64-NEXT: Name: vars64.dll
+X64-NEXT: Attributes: 0x1
+X64-NEXT: ModuleHandle: 0x0
+X64-NEXT: ImportAddressTable: 0x0
+X64-NEXT: ImportNameTable: 0x1000
+X64-NEXT: BoundDelayImportTable: 0x0
+X64-NEXT: UnloadDelayImportTable: 0x0
+X64-NEXT: Symbol: _name_with_underscore (0)
+X64-NEXT: Symbol: fn (1)
+X64-NEXT: Symbol: (1)
+X64-NEXT: }
More information about the llvm-commits
mailing list