diff options
-rw-r--r-- | lld/lib/Driver/WinLinkDriver.cpp | 2 | ||||
-rw-r--r-- | lld/lib/ReaderWriter/PECOFF/IdataPass.cpp | 56 | ||||
-rw-r--r-- | lld/lib/ReaderWriter/PECOFF/IdataPass.h | 35 | ||||
-rw-r--r-- | lld/lib/ReaderWriter/PECOFF/WriterPECOFF.cpp | 1 | ||||
-rw-r--r-- | lld/test/pecoff/Inputs/vars64.lib | bin | 0 -> 2016 bytes | |||
-rw-r--r-- | lld/test/pecoff/delayimport.test | 39 |
6 files changed, 120 insertions, 13 deletions
diff --git a/lld/lib/Driver/WinLinkDriver.cpp b/lld/lib/Driver/WinLinkDriver.cpp index cbba4e43c6e..eb4c83ccc2d 100644 --- a/lld/lib/Driver/WinLinkDriver.cpp +++ b/lld/lib/Driver/WinLinkDriver.cpp @@ -1227,8 +1227,6 @@ bool WinLinkDriver::parse(int argc, const char *argv[], case OPT_delayload: ctx.addDelayLoadDLL(inputArg->getValue()); - ctx.addInitialUndefinedSymbol( - ctx.is64Bit() ? "__delayLoadHelper2" : "___delayLoadHelper2@8"); break; case OPT_stub: { diff --git a/lld/lib/ReaderWriter/PECOFF/IdataPass.cpp b/lld/lib/ReaderWriter/PECOFF/IdataPass.cpp index cab507d1352..f0e30b40364 100644 --- a/lld/lib/ReaderWriter/PECOFF/IdataPass.cpp +++ b/lld/lib/ReaderWriter/PECOFF/IdataPass.cpp @@ -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<MutableFile> &file) { 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); } diff --git a/lld/lib/ReaderWriter/PECOFF/IdataPass.h b/lld/lib/ReaderWriter/PECOFF/IdataPass.h index 0adf2dd881e..efba5835e1d 100644 --- a/lld/lib/ReaderWriter/PECOFF/IdataPass.h +++ b/lld/lib/ReaderWriter/PECOFF/IdataPass.h @@ -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 { diff --git a/lld/lib/ReaderWriter/PECOFF/WriterPECOFF.cpp b/lld/lib/ReaderWriter/PECOFF/WriterPECOFF.cpp index 313bcd5a737..6c241974741 100644 --- a/lld/lib/ReaderWriter/PECOFF/WriterPECOFF.cpp +++ b/lld/lib/ReaderWriter/PECOFF/WriterPECOFF.cpp @@ -1043,6 +1043,7 @@ void PECOFFWriter::build(const File &linkedFile) { .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; diff --git a/lld/test/pecoff/Inputs/vars64.lib b/lld/test/pecoff/Inputs/vars64.lib Binary files differnew file mode 100644 index 00000000000..fb48c9ab141 --- /dev/null +++ b/lld/test/pecoff/Inputs/vars64.lib diff --git a/lld/test/pecoff/delayimport.test b/lld/test/pecoff/delayimport.test index 1d8b5c3c218..d122178b914 100644 --- a/lld/test/pecoff/delayimport.test +++ b/lld/test/pecoff/delayimport.test @@ -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@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: } |