diff options
author | Rui Ueyama <ruiu@google.com> | 2013-07-11 08:46:21 +0000 |
---|---|---|
committer | Rui Ueyama <ruiu@google.com> | 2013-07-11 08:46:21 +0000 |
commit | c8a53795ab3463d29950f25f6b91860ef43c502b (patch) | |
tree | 38e1817a8c699092f4d348792ccc0b249525bcec | |
parent | 67ddcd6dd08f31c74b4c6662aeb9574651d0c7c7 (diff) | |
download | bcm5719-llvm-c8a53795ab3463d29950f25f6b91860ef43c502b.tar.gz bcm5719-llvm-c8a53795ab3463d29950f25f6b91860ef43c502b.zip |
[PECOFF] Support linking against DLL.
This patch adds a new pass, IdataPass, to transform shared atom references
to real references and to construct the .idata section data. With this patch
lld can produce a working Hello World program by linking it against
kernel32.dll and user32.dll.
Reviewers: Bigcheese
CC: llvm-commits
Differential Revision: http://llvm-reviews.chandlerc.com/D1096
llvm-svn: 186071
-rw-r--r-- | lld/include/lld/Core/DefinedAtom.h | 1 | ||||
-rw-r--r-- | lld/lib/Core/DefinedAtom.cpp | 1 | ||||
-rw-r--r-- | lld/lib/ReaderWriter/PECOFF/Atoms.h | 41 | ||||
-rw-r--r-- | lld/lib/ReaderWriter/PECOFF/IdataPass.h | 313 | ||||
-rw-r--r-- | lld/lib/ReaderWriter/PECOFF/PECOFFTargetInfo.cpp | 2 | ||||
-rw-r--r-- | lld/lib/ReaderWriter/PECOFF/ReaderImportHeader.cpp | 3 | ||||
-rw-r--r-- | lld/lib/ReaderWriter/PECOFF/WriterPECOFF.cpp | 90 | ||||
-rw-r--r-- | lld/test/pecoff/Inputs/dynamic.dll | bin | 32256 -> 0 bytes | |||
-rw-r--r-- | lld/test/pecoff/Inputs/dynamic.lib | bin | 1792 -> 0 bytes | |||
-rw-r--r-- | lld/test/pecoff/Inputs/grouped-sections.asm | 1 | ||||
-rw-r--r-- | lld/test/pecoff/Inputs/grouped-sections.obj.yaml | 10 | ||||
-rw-r--r-- | lld/test/pecoff/Inputs/vars-main.c | 6 | ||||
-rw-r--r-- | lld/test/pecoff/Inputs/vars-main.obj.yaml | 80 | ||||
-rw-r--r-- | lld/test/pecoff/Inputs/vars.c | 11 | ||||
-rw-r--r-- | lld/test/pecoff/Inputs/vars.dll.yaml | 19 | ||||
-rw-r--r-- | lld/test/pecoff/Inputs/vars.lib | bin | 0 -> 1762 bytes | |||
-rw-r--r-- | lld/test/pecoff/importlib.test | 22 |
17 files changed, 532 insertions, 68 deletions
diff --git a/lld/include/lld/Core/DefinedAtom.h b/lld/include/lld/Core/DefinedAtom.h index 9ba2428a9a6..b4b2f87641a 100644 --- a/lld/include/lld/Core/DefinedAtom.h +++ b/lld/include/lld/Core/DefinedAtom.h @@ -144,6 +144,7 @@ public: typeTLVInitialData, // initial data for a TLV [Darwin] typeTLVInitialZeroFill, // TLV initial zero fill data [Darwin] typeTLVInitializerPtr, // pointer to thread local initializer [Darwin] + typeDataDirectoryEntry, // linker created for data directory header [PECOFF] }; // Permission bits for atoms and segments. The order of these values are diff --git a/lld/lib/Core/DefinedAtom.cpp b/lld/lib/Core/DefinedAtom.cpp index 0aa2aa84e92..9e00567afc7 100644 --- a/lld/lib/Core/DefinedAtom.cpp +++ b/lld/lib/Core/DefinedAtom.cpp @@ -51,6 +51,7 @@ DefinedAtom::ContentPermissions DefinedAtom::permissions(ContentType type) { case typeLazyPointer: case typeLazyDylibPointer: case typeThunkTLV: + case typeDataDirectoryEntry: return permRW_; case typeGOT: diff --git a/lld/lib/ReaderWriter/PECOFF/Atoms.h b/lld/lib/ReaderWriter/PECOFF/Atoms.h index f7a99be57cd..7ef7995c43d 100644 --- a/lld/lib/ReaderWriter/PECOFF/Atoms.h +++ b/lld/lib/ReaderWriter/PECOFF/Atoms.h @@ -223,27 +223,45 @@ public: virtual uint64_t ordinal() const { return 0; } virtual Scope scope() const { return scopeGlobal; } virtual Alignment alignment() const { return Alignment(1); } - virtual uint64_t size() const { return _data->size(); } - virtual ArrayRef<uint8_t> rawContent() const { return *_data; } + virtual uint64_t size() const { return _data.size(); } + virtual ArrayRef<uint8_t> rawContent() const { return _data; } protected: - COFFLinkerInternalAtom(const File &file, std::vector<uint8_t> *data, + COFFLinkerInternalAtom(const File &file, std::vector<uint8_t> data, StringRef symbolName = "") - : COFFBaseDefinedAtom(file, symbolName, Kind::Internal), _data(data) {} + : COFFBaseDefinedAtom(file, symbolName, Kind::Internal), + _data(std::move(data)) {} private: - std::vector<uint8_t> *_data; + std::vector<uint8_t> _data; +}; + +// A COFFDataDirectoryAtom represents an entry of Optional Data Directory in the +// COFF header. +class COFFDataDirectoryAtom : public COFFLinkerInternalAtom { +public: + COFFDataDirectoryAtom(const File &file, uint64_t ordinal) + : COFFLinkerInternalAtom(file, std::vector<uint8_t>(8)), + _ordinal(ordinal) {} + + virtual uint64_t ordinal() const { return _ordinal; } + virtual ContentType contentType() const { return typeDataDirectoryEntry; } + virtual ContentPermissions permissions() const { return permR__; } + +private: + uint64_t _ordinal; }; // A COFFSharedLibraryAtom represents a symbol for data in an import library. A // reference to a COFFSharedLibraryAtom will be transformed to a real reference -// to an import address table entry in a pass. +// to an import address table entry in Idata pass. class COFFSharedLibraryAtom : public SharedLibraryAtom { public: COFFSharedLibraryAtom(const File &file, uint16_t hint, StringRef symbolName, StringRef loadName) : _file(file), _hint(hint), _unmangledName(symbolName), - _loadName(loadName), _mangledName(addImpPrefix(symbolName)) {} + _loadName(loadName), _mangledName(addImpPrefix(symbolName)), + _importTableEntry(nullptr) {} virtual const File &file() const { return _file; } uint16_t hint() const { return _hint; } @@ -252,6 +270,14 @@ public: virtual StringRef loadName() const { return _loadName; } virtual bool canBeNullAtRuntime() const { return false; } + void setImportTableEntry(const DefinedAtom *atom) { + _importTableEntry = atom; + } + + const DefinedAtom *getImportTableEntry() const { + return _importTableEntry; + } + private: /// Mangle the symbol name by adding "__imp_" prefix. See the file comment of /// ReaderImportHeader.cpp for details about the prefix. @@ -266,6 +292,7 @@ private: StringRef _unmangledName; StringRef _loadName; std::string _mangledName; + const DefinedAtom *_importTableEntry; }; //===----------------------------------------------------------------------===// diff --git a/lld/lib/ReaderWriter/PECOFF/IdataPass.h b/lld/lib/ReaderWriter/PECOFF/IdataPass.h new file mode 100644 index 00000000000..fd41552af19 --- /dev/null +++ b/lld/lib/ReaderWriter/PECOFF/IdataPass.h @@ -0,0 +1,313 @@ +//===- lib/ReaderWriter/PECOFF/IdataPass.h---------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file \brief This linker pass creates atoms for the DLL import +/// information. The defined atoms constructed in this pass will go into .idata +/// section, unless .idata section is merged with other section such as .data. +/// +/// For the details of the .idata section format, see Microsoft PE/COFF +/// Specification section 5.4, The .idata Section. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLD_READER_WRITER_PE_COFF_IDATA_PASS_H_ +#define LLD_READER_WRITER_PE_COFF_IDATA_PASS_H_ + +#include "Atoms.h" + +#include "lld/Core/File.h" +#include "lld/Core/Pass.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/COFF.h" +#include "llvm/Support/Endian.h" + +#include <algorithm> +#include <cstddef> +#include <cstring> +#include <map> + +using lld::coff::COFFBaseDefinedAtom; +using lld::coff::COFFDefinedAtom; +using lld::coff::COFFLinkerInternalAtom; +using lld::coff::COFFReference; +using lld::coff::COFFSharedLibraryAtom; +using lld::coff::COFFSharedLibraryAtom; +using llvm::COFF::ImportDirectoryTableEntry; +using std::map; +using std::vector; + +namespace lld { +namespace pecoff { + +namespace { +class DLLNameAtom; +class HintNameAtom; +class ImportTableEntryAtom; + +void addDir32NBReloc(COFFBaseDefinedAtom *atom, const Atom *target, + size_t offsetInAtom) { + atom->addReference(std::unique_ptr<COFFReference>(new COFFReference( + target, offsetInAtom, llvm::COFF::IMAGE_REL_I386_DIR32NB))); +} + +// A state object of this pass. +struct Context { + explicit Context(MutableFile &f) : file(f) {} + + MutableFile &file; + + // The object to accumulate idata atoms. Idata atoms need to be grouped by + // type and be continuous in the output file. To force such layout, we + // accumulate all atoms created in the pass in the following vectors, and add + // layout edges when finishing the pass. + vector<COFFBaseDefinedAtom *> importDirectories; + vector<ImportTableEntryAtom *> importLookupTables; + vector<ImportTableEntryAtom *> importAddressTables; + vector<HintNameAtom *> hintNameAtoms; + vector<DLLNameAtom *> dllNameAtoms; + + map<StringRef, COFFBaseDefinedAtom *> sharedToDefinedAtom; +}; + +/// The root class of all idata atoms. +class IdataAtom : public COFFLinkerInternalAtom { +public: + virtual ContentType contentType() const { return typeData; } + virtual ContentPermissions permissions() const { return permR__; } + +protected: + IdataAtom(MutableFile &file, vector<uint8_t> data) + : COFFLinkerInternalAtom(file, data) { + file.addAtom(*this); + } +}; + +/// A DLLNameAtom contains a name of a DLL and is referenced by the Name RVA +/// field in the import directory table entry. +class DLLNameAtom : public IdataAtom { +public: + DLLNameAtom(Context &ctx, StringRef name) + : IdataAtom(ctx.file, stringRefToVector(name)) { + ctx.dllNameAtoms.push_back(this); + } + +private: + vector<uint8_t> stringRefToVector(StringRef name) { + vector<uint8_t> ret(name.size() + 1); + memcpy(&ret[0], name.data(), name.size()); + ret[name.size()] = 0; + return std::move(ret); + } +}; + +/// A HintNameAtom represents a symbol that will be imported from a DLL at +/// runtime. It consists with an optional hint, which is a small integer, and a +/// symbol name. +/// +/// A hint is an index of the export pointer table in a DLL. If the import +/// library and DLL is in sync (i.e., ".lib" and ".dll" is for the same version +/// or the symbol ordinal is maintained by hand with ".exp" file), the PE/COFF +/// loader can find the symbol quickly. +class HintNameAtom : public IdataAtom { +public: + HintNameAtom(Context &ctx, uint16_t hint, StringRef name) + : IdataAtom(ctx.file, assembleRawContent(hint, name)), _name(name) { + ctx.hintNameAtoms.push_back(this); + } + + StringRef getContentString() { return _name; } + +private: + // The first two bytes of the content is a hint, followed by a null-terminated + // symbol name. The total size needs to be multiple of 2. + vector<uint8_t> assembleRawContent(uint16_t hint, StringRef name) { + name = unmangle(name); + size_t size = llvm::RoundUpToAlignment(sizeof(hint) + name.size() + 1, 2); + vector<uint8_t> ret(size); + ret[name.size()] = 0; + ret[name.size() - 1] = 0; + *reinterpret_cast<llvm::support::ulittle16_t *>(&ret[0]) = hint; + std::memcpy(&ret[2], name.data(), name.size()); + return ret; + } + + /// Undo name mangling. In Windows, the symbol name for function is encoded + /// as "_name@X", where X is the number of bytes of the arguments. + StringRef unmangle(StringRef mangledName) { + assert(mangledName.startswith("_")); + return mangledName.substr(1).split('@').first; + } + + StringRef _name; +}; + +class ImportTableEntryAtom : public IdataAtom { +public: + explicit ImportTableEntryAtom(Context &ctx) + : IdataAtom(ctx.file, vector<uint8_t>(4, 0)) {} +}; + +/// An ImportDirectoryAtom includes information to load a DLL, including a DLL +/// name, symbols that will be resolved from the DLL, and the import address +/// table that are overwritten by the loader with the pointers to the referenced +/// items. The executable has one ImportDirectoryAtom per one imported DLL. +class ImportDirectoryAtom : public IdataAtom { +public: + ImportDirectoryAtom(Context &ctx, StringRef loadName, + const vector<COFFSharedLibraryAtom *> &sharedAtoms) + : IdataAtom(ctx.file, vector<uint8_t>(20, 0)) { + addRelocations(ctx, loadName, sharedAtoms); + ctx.importDirectories.push_back(this); + } + +private: + void addRelocations(Context &ctx, StringRef loadName, + const vector<COFFSharedLibraryAtom *> &sharedAtoms) { + size_t lookupEnd = ctx.importLookupTables.size(); + size_t addressEnd = ctx.importAddressTables.size(); + + // Create parallel arrays. The contents of the two are initially the + // same. The PE/COFF loader overwrites the import address tables with the + // pointers to the referenced items after loading the executable into + // memory. + addImportTableAtoms(ctx, sharedAtoms, false, ctx.importLookupTables); + addImportTableAtoms(ctx, sharedAtoms, true, ctx.importAddressTables); + + addDir32NBReloc(this, ctx.importLookupTables[lookupEnd], + offsetof(ImportDirectoryTableEntry, ImportLookupTableRVA)); + addDir32NBReloc(this, ctx.importAddressTables[addressEnd], + offsetof(ImportDirectoryTableEntry, ImportAddressTableRVA)); + addDir32NBReloc(this, new (_alloc) DLLNameAtom(ctx, loadName), + offsetof(ImportDirectoryTableEntry, NameRVA)); + } + + // Creates atoms for an import lookup table. The import lookup table is an + // array of pointers to hint/name atoms. The array needs to be terminated with + // the NULL entry. + void addImportTableAtoms(Context &ctx, + const vector<COFFSharedLibraryAtom *> &sharedAtoms, + bool shouldAddReference, + vector<ImportTableEntryAtom *> &ret) const { + for (COFFSharedLibraryAtom *shared : sharedAtoms) { + HintNameAtom *hintName = createHintNameAtom(ctx, shared); + ImportTableEntryAtom *entry = new (_alloc) ImportTableEntryAtom(ctx); + addDir32NBReloc(entry, hintName, 0); + ret.push_back(entry); + if (shouldAddReference) + shared->setImportTableEntry(entry); + } + // Add the NULL entry. + ret.push_back(new (_alloc) ImportTableEntryAtom(ctx)); + } + + HintNameAtom *createHintNameAtom( + Context &ctx, const COFFSharedLibraryAtom *atom) const { + return new (_alloc) HintNameAtom(ctx, atom->hint(), atom->unmangledName()); + } + + mutable llvm::BumpPtrAllocator _alloc; +}; + +/// The last NULL entry in the import directory. +class NullImportDirectoryAtom : public IdataAtom { +public: + explicit NullImportDirectoryAtom(Context &ctx) + : IdataAtom(ctx.file, vector<uint8_t>(20, 0)) { + ctx.importDirectories.push_back(this); + } +}; + +} // anonymous namespace + +class IdataPass : public lld::Pass { +public: + virtual void perform(MutableFile &file) { + if (file.sharedLibrary().size() == 0) + return; + + Context ctx(file); + map<StringRef, vector<COFFSharedLibraryAtom *>> sharedAtoms = + groupByLoadName(file); + for (auto i : sharedAtoms) { + StringRef loadName = i.first; + vector<COFFSharedLibraryAtom *> &atoms = i.second; + createImportDirectory(ctx, loadName, atoms); + } + new (_alloc) NullImportDirectoryAtom(ctx); + connectAtoms(ctx); + createDataDirectoryAtoms(ctx); + replaceSharedLibraryAtoms(ctx); + } + +private: + map<StringRef, vector<COFFSharedLibraryAtom *>> + groupByLoadName(MutableFile &file) { + map<StringRef, COFFSharedLibraryAtom *> uniqueAtoms; + for (const SharedLibraryAtom *atom : file.sharedLibrary()) + uniqueAtoms[atom->name()] = (COFFSharedLibraryAtom *)atom; + + map<StringRef, vector<COFFSharedLibraryAtom *>> ret; + for (auto i : uniqueAtoms) { + COFFSharedLibraryAtom *atom = i.second; + ret[atom->loadName()].push_back(atom); + } + return std::move(ret); + } + + void + createImportDirectory(Context &ctx, StringRef loadName, + vector<COFFSharedLibraryAtom *> &dllAtoms) { + new (_alloc) ImportDirectoryAtom(ctx, loadName, dllAtoms); + } + + void connectAtoms(Context &ctx) { + coff::connectAtomsWithLayoutEdge(ctx.importDirectories); + coff::connectAtomsWithLayoutEdge(ctx.importLookupTables); + coff::connectAtomsWithLayoutEdge(ctx.importAddressTables); + coff::connectAtomsWithLayoutEdge(ctx.hintNameAtoms); + coff::connectAtomsWithLayoutEdge(ctx.dllNameAtoms); + } + + /// The addresses of the import dirctory and the import address table needs to + /// be set to the COFF Optional Data Directory header. A COFFDataDirectoryAtom + /// represents an entry in the data directory header. We create atoms of class + /// COFFDataDirectoryAtom and set relocations to them, so that the address + /// will be set by the writer. + void createDataDirectoryAtoms(Context &ctx) { + auto *dir = new (_alloc) coff::COFFDataDirectoryAtom(ctx.file, 1); + addDir32NBReloc(dir, ctx.importDirectories[0], 0); + ctx.file.addAtom(*dir); + + auto *iat = new (_alloc) coff::COFFDataDirectoryAtom(ctx.file, 12); + addDir32NBReloc(iat, ctx.importAddressTables[0], 0); + ctx.file.addAtom(*iat); + } + + /// Transforms a reference to a COFFSharedLibraryAtom to a real reference. + void replaceSharedLibraryAtoms(Context &ctx) { + for (const DefinedAtom *atom : ctx.file.defined()) { + for (const Reference *ref : *atom) { + const Atom *target = ref->target(); + auto *sharedAtom = dyn_cast<SharedLibraryAtom>(target); + if (!sharedAtom) + continue; + auto *coffSharedAtom = (COFFSharedLibraryAtom *)sharedAtom; + const DefinedAtom *entry = coffSharedAtom->getImportTableEntry(); + const_cast<Reference *>(ref)->setTarget(entry); + } + } + } + + llvm::BumpPtrAllocator _alloc; +}; + +} // namespace pecoff +} // namespace lld + +#endif diff --git a/lld/lib/ReaderWriter/PECOFF/PECOFFTargetInfo.cpp b/lld/lib/ReaderWriter/PECOFF/PECOFFTargetInfo.cpp index 94bf1103256..4b182346d8a 100644 --- a/lld/lib/ReaderWriter/PECOFF/PECOFFTargetInfo.cpp +++ b/lld/lib/ReaderWriter/PECOFF/PECOFFTargetInfo.cpp @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include "GroupedSectionsPass.h" +#include "IdataPass.h" #include "lld/Core/PassManager.h" #include "lld/Passes/LayoutPass.h" @@ -59,6 +60,7 @@ PECOFFTargetInfo::stringFromRelocKind(Reference::Kind kind) const { void PECOFFTargetInfo::addPasses(PassManager &pm) const { pm.add(std::unique_ptr<Pass>(new pecoff::GroupedSectionsPass())); + pm.add(std::unique_ptr<Pass>(new pecoff::IdataPass())); pm.add(std::unique_ptr<Pass>(new LayoutPass())); } diff --git a/lld/lib/ReaderWriter/PECOFF/ReaderImportHeader.cpp b/lld/lib/ReaderWriter/PECOFF/ReaderImportHeader.cpp index 173f72b5693..134abfac42a 100644 --- a/lld/lib/ReaderWriter/PECOFF/ReaderImportHeader.cpp +++ b/lld/lib/ReaderWriter/PECOFF/ReaderImportHeader.cpp @@ -135,7 +135,8 @@ namespace { class FuncAtom : public COFFLinkerInternalAtom { public: FuncAtom(const File &file, StringRef symbolName) - : COFFLinkerInternalAtom(file, &rawContent, symbolName) {} + : COFFLinkerInternalAtom(file, std::vector<uint8_t>(rawContent), + symbolName) {} virtual uint64_t ordinal() const { return 0; } virtual Scope scope() const { return scopeGlobal; } diff --git a/lld/lib/ReaderWriter/PECOFF/WriterPECOFF.cpp b/lld/lib/ReaderWriter/PECOFF/WriterPECOFF.cpp index 0c6ddc9c645..8be345294b2 100644 --- a/lld/lib/ReaderWriter/PECOFF/WriterPECOFF.cpp +++ b/lld/lib/ReaderWriter/PECOFF/WriterPECOFF.cpp @@ -64,7 +64,8 @@ class Chunk { public: enum Kind { kindHeader, - kindSection + kindSection, + kindDataDirectory }; explicit Chunk(Kind kind) : _kind(kind), _size(0), _align(1) {} @@ -243,43 +244,6 @@ private: llvm::object::pe32_header _peHeader; }; -/// A DataDirectoryChunk represents data directory entries that follows the PE -/// header in the output file. An entry consists of an 8 byte field that -/// indicates a relative virtual address (the starting address of the entry data -/// in memory) and 8 byte entry data size. -class DataDirectoryChunk : public HeaderChunk { -public: - DataDirectoryChunk() : HeaderChunk() { - _size = sizeof(_dirs); - std::memset(_dirs, 0, sizeof(_dirs)); - } - - // Set the import table address and size. The import table is usually in - // .idata section, but because .idata section can be merged with other section - // such as .rdata, the given address can be in any section. - void setImportTableDirectoryRva(uint32_t rva, uint32_t size) { - _dirs[1].RelativeVirtualAddress = rva; - _dirs[1].Size = size; - } - - // Set the address and size of the import address table (IAT). This is - // redundant information because the import table contains the file offset of - // the IAT. Although it's redundant, it needs to be set properly, otherwise - // the loader refuses the executable. - void setImportAddressTableRva(uint32_t rva, uint32_t size) { - _dirs[12].RelativeVirtualAddress = rva; - _dirs[12].Size = size; - } - - virtual void write(uint8_t *fileBuffer) { - fileBuffer += fileOffset(); - std::memcpy(fileBuffer, &_dirs, sizeof(_dirs)); - } - -private: - llvm::object::data_directory _dirs[16]; -}; - /// A SectionHeaderTableChunk represents Section Table Header of PE/COFF /// format, which is a list of section headers. class SectionHeaderTableChunk : public HeaderChunk { @@ -363,11 +327,51 @@ public: layout->_virtualAddr += rva; } + static bool classof(const Chunk *c) { + Kind kind = c->getKind(); + return kind == kindSection || kind == kindDataDirectory; + } + protected: AtomChunk(Kind kind) : Chunk(kind) {} std::vector<AtomLayout *> _atomLayouts; }; +/// A DataDirectoryChunk represents data directory entries that follows the PE +/// header in the output file. An entry consists of an 8 byte field that +/// indicates a relative virtual address (the starting address of the entry data +/// in memory) and 8 byte entry data size. +class DataDirectoryChunk : public AtomChunk { +public: + DataDirectoryChunk(const File &linkedFile) + : AtomChunk(kindDataDirectory) { + // Extract atoms from the linked file and append them to this section. + for (const DefinedAtom *atom : linkedFile.defined()) { + if (atom->contentType() == DefinedAtom::typeDataDirectoryEntry) { + uint64_t size = atom->ordinal() * sizeof(llvm::object::data_directory); + _atomLayouts.push_back(new (_alloc) AtomLayout(atom, size, size)); + } + } + } + + virtual uint64_t size() const { + return sizeof(llvm::object::data_directory) * 16; + } + + virtual void write(uint8_t *fileBuffer) { + fileBuffer += fileOffset(); + for (const AtomLayout *layout : _atomLayouts) { + if (!layout) + continue; + ArrayRef<uint8_t> content = static_cast<const DefinedAtom *>(layout->_atom)->rawContent(); + std::memcpy(fileBuffer + layout->_fileOffset, content.data(), content.size()); + } + } + +private: + mutable llvm::BumpPtrAllocator _alloc; +}; + /// A SectionChunk represents a section containing atoms. It consists of a /// section header that to be written to PECOFF header and atoms which to be /// written to the raw data section. @@ -453,13 +457,13 @@ private: } void appendAtom(const DefinedAtom *atom) { - auto *layout = new (_storage) AtomLayout(atom, _size, _size); + auto *layout = new (_alloc) AtomLayout(atom, _size, _size); _atomLayouts.push_back(layout); _size += atom->rawContent().size(); } llvm::object::coff_section _sectionHeader; - mutable llvm::BumpPtrAllocator _storage; + mutable llvm::BumpPtrAllocator _alloc; }; void SectionHeaderTableChunk::addSection(SectionChunk *chunk) { @@ -545,10 +549,10 @@ private: void applyRelocations(uint8_t *bufferStart) { std::map<const Atom *, uint64_t> atomToVirtualAddr; for (auto &cp : _chunks) - if (SectionChunk *chunk = dyn_cast<SectionChunk>(&*cp)) + if (AtomChunk *chunk = dyn_cast<AtomChunk>(&*cp)) chunk->buildAtomToVirtualAddr(atomToVirtualAddr); for (auto &cp : _chunks) - if (SectionChunk *chunk = dyn_cast<SectionChunk>(&*cp)) + if (AtomChunk *chunk = dyn_cast<AtomChunk>(&*cp)) chunk->applyRelocations(bufferStart, atomToVirtualAddr); } @@ -586,7 +590,7 @@ public: // Create file chunks and add them to the list. auto *dosStub = new DOSStubChunk(); auto *peHeader = new PEHeaderChunk(_PECOFFTargetInfo); - auto *dataDirectory = new DataDirectoryChunk(); + auto *dataDirectory = new DataDirectoryChunk(linkedFile); auto *sectionTable = new SectionHeaderTableChunk(); auto *text = new TextSectionChunk(linkedFile); auto *rdata = new RDataSectionChunk(linkedFile); diff --git a/lld/test/pecoff/Inputs/dynamic.dll b/lld/test/pecoff/Inputs/dynamic.dll Binary files differdeleted file mode 100644 index c9e76e75691..00000000000 --- a/lld/test/pecoff/Inputs/dynamic.dll +++ /dev/null diff --git a/lld/test/pecoff/Inputs/dynamic.lib b/lld/test/pecoff/Inputs/dynamic.lib Binary files differdeleted file mode 100644 index 52d2a230e78..00000000000 --- a/lld/test/pecoff/Inputs/dynamic.lib +++ /dev/null diff --git a/lld/test/pecoff/Inputs/grouped-sections.asm b/lld/test/pecoff/Inputs/grouped-sections.asm index f17ab1166af..af69363efef 100644 --- a/lld/test/pecoff/Inputs/grouped-sections.asm +++ b/lld/test/pecoff/Inputs/grouped-sections.asm @@ -14,4 +14,5 @@ _data$1 ends .code main: + nop end main diff --git a/lld/test/pecoff/Inputs/grouped-sections.obj.yaml b/lld/test/pecoff/Inputs/grouped-sections.obj.yaml index 8509e85644b..b118490e31b 100644 --- a/lld/test/pecoff/Inputs/grouped-sections.obj.yaml +++ b/lld/test/pecoff/Inputs/grouped-sections.obj.yaml @@ -6,7 +6,7 @@ sections: - Name: .text Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] Alignment: 4 - SectionData: "" + SectionData: 90 - Name: .data Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ] Alignment: 4 @@ -22,7 +22,7 @@ sections: - Name: ".debug$S" Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] Alignment: 1 - SectionData: 04000000F1000000670000002C000111000000005A3A5C67726F7570656473656374696F6E735C73656374696F6E2D67726F7570732E6F626A0037003C1103020000030000000000000000000A0000001B9D01004D6963726F736F667420285229204D6163726F20417373656D626C6572000000 + SectionData: 04000000F1000000590000001E000111000000005A3A5C67726F757065642D73656374696F6E732E6F626A0037003C1103020000030000000000000000000A0000001B9D01004D6963726F736F667420285229204D6163726F20417373656D626C65720000000000 - Name: .drectve Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ] Alignment: 2147483648 @@ -41,7 +41,7 @@ symbols: ComplexType: IMAGE_SYM_DTYPE_NULL StorageClass: IMAGE_SYM_CLASS_STATIC NumberOfAuxSymbols: 1 - AuxiliaryData: 000000000000000000000000000000000000 + AuxiliaryData: 010000000000000000000000000000000000 - Name: .data Value: 0 SectionNumber: 2 @@ -66,14 +66,14 @@ symbols: StorageClass: IMAGE_SYM_CLASS_STATIC NumberOfAuxSymbols: 1 AuxiliaryData: 040000000000000000000000000000000000 - - Name: ."debug$S" + - Name: ".debug$S" Value: 0 SectionNumber: 5 SimpleType: IMAGE_SYM_TYPE_NULL ComplexType: IMAGE_SYM_DTYPE_NULL StorageClass: IMAGE_SYM_CLASS_STATIC NumberOfAuxSymbols: 1 - AuxiliaryData: 740000000000000000000000000000000000 + AuxiliaryData: 680000000000000000000000000000000000 - Name: _main Value: 0 SectionNumber: 1 diff --git a/lld/test/pecoff/Inputs/vars-main.c b/lld/test/pecoff/Inputs/vars-main.c new file mode 100644 index 00000000000..ac72617ec4a --- /dev/null +++ b/lld/test/pecoff/Inputs/vars-main.c @@ -0,0 +1,6 @@ +__declspec(dllimport) int var; +__declspec(dllimport) int fn(void); + +int main() { + return var + fn(); +} diff --git a/lld/test/pecoff/Inputs/vars-main.obj.yaml b/lld/test/pecoff/Inputs/vars-main.obj.yaml new file mode 100644 index 00000000000..6ca2dd0b6d4 --- /dev/null +++ b/lld/test/pecoff/Inputs/vars-main.obj.yaml @@ -0,0 +1,80 @@ +--- +header: + Machine: IMAGE_FILE_MACHINE_I386 + Characteristics: [ ] +sections: + - Name: .drectve + Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ] + Alignment: 1 + SectionData: 2020202F44454641554C544C49423A224C4942434D5422202F44454641554C544C49423A224F4C444E414D45532220 + - Name: ".debug$S" + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] + Alignment: 1 + SectionData: 04000000F10000005500000017000111000000005A3A5C766172732D6D61696E2E6F626A003A003C11002200000700100000001B9D0100100000001B9D01004D6963726F736F667420285229204F7074696D697A696E6720436F6D70696C657200000000 + - Name: .text + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + Alignment: 16 + SectionData: 558BECFF15000000008B0D0000000003015DC3 + Relocations: + - VirtualAddress: 5 + SymbolName: __imp__fn + Type: IMAGE_REL_I386_DIR32 + - VirtualAddress: 11 + SymbolName: __imp__var + Type: IMAGE_REL_I386_DIR32 +symbols: + - Name: "@comp.id" + Value: 11181339 + SectionNumber: 65535 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + - Name: "@feat.00" + Value: 1 + SectionNumber: 65535 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + - Name: .drectve + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + NumberOfAuxSymbols: 1 + AuxiliaryData: 2F0000000000000000000000000000000000 + - Name: ".debug$S" + Value: 0 + SectionNumber: 2 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + NumberOfAuxSymbols: 1 + AuxiliaryData: 640000000000000000000000000000000000 + - Name: .text + Value: 0 + SectionNumber: 3 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + NumberOfAuxSymbols: 1 + AuxiliaryData: 1300000002000000B8433CE4000000000000 + - Name: _main + Value: 0 + SectionNumber: 3 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: __imp__var + Value: 0 + SectionNumber: 0 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: __imp__fn + Value: 0 + SectionNumber: 0 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_EXTERNAL +... diff --git a/lld/test/pecoff/Inputs/vars.c b/lld/test/pecoff/Inputs/vars.c new file mode 100644 index 00000000000..6532824fa3f --- /dev/null +++ b/lld/test/pecoff/Inputs/vars.c @@ -0,0 +1,11 @@ +// cl.exe /c vars.c +// link.exe /debug /nodefaultlib /entry:dllmain vars.obj +__declspec(dllexport) int var = 3; + +__declspec(dllexport) int fn(void) { + return 4; +} + +int dllmain() { + return 1; +} diff --git a/lld/test/pecoff/Inputs/vars.dll.yaml b/lld/test/pecoff/Inputs/vars.dll.yaml new file mode 100644 index 00000000000..cbeab6e4902 --- /dev/null +++ b/lld/test/pecoff/Inputs/vars.dll.yaml @@ -0,0 +1,19 @@ +--- +header: + Machine: IMAGE_FILE_MACHINE_I386 + Characteristics: [ IMAGE_FILE_EXECUTABLE_IMAGE, IMAGE_FILE_32BIT_MACHINE, IMAGE_FILE_DLL ] +sections: + - Name: .text + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + Alignment: 2147483648 + SectionData: 558BECB8090000005DC3CCCCCCCCCCCC558BECB8010000005DC3000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 + - Name: .rdata + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] + Alignment: 2147483648 + SectionData: 0000000041ADCC51000000003C2000000100000002000000020000002820000030200000382000000010000000300000452000004820000000000100766172732E646C6C00666E007661720000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 + - Name: .data + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ] + Alignment: 2147483648 + SectionData: 0300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +symbols: +... diff --git a/lld/test/pecoff/Inputs/vars.lib b/lld/test/pecoff/Inputs/vars.lib Binary files differnew file mode 100644 index 00000000000..6ed368e1b31 --- /dev/null +++ b/lld/test/pecoff/Inputs/vars.lib diff --git a/lld/test/pecoff/importlib.test b/lld/test/pecoff/importlib.test index b15d8aae3ce..62f5f3693d2 100644 --- a/lld/test/pecoff/importlib.test +++ b/lld/test/pecoff/importlib.test @@ -1,19 +1,17 @@ # Verify that lld can handle .lib files. "main.obj" refers _val1 and -# _val2 that are defined in "dynamic.lib". +# _val2 that are defined in "vars.lib". # -# RUN: yaml2obj %p/Inputs/main.obj.yaml > %t.obj +# RUN: yaml2obj %p/Inputs/vars-main.obj.yaml > %t.obj # # RUN: lld -flavor link -out %t1 -subsystem console -- %t.obj \ -# RUN: %p/Inputs/dynamic.lib && llvm-objdump -d %t1 | FileCheck %s +# RUN: %p/Inputs/vars.lib && llvm-objdump -d %t1 | FileCheck %s CHECK: Disassembly of section .text: CHECK: .text: -CHECK: 1000: a1 0c 10 40 00 movl 4198412, %eax -CHECK: 1005: 03 05 14 10 40 00 addl 4198420, %eax -CHECK: 100b: c3 ret -CHECK: 100c: ff 25 00 00 40 00 jmpl *4194304 -CHECK: 1012: 90 nop -CHECK: 1013: 90 nop -CHECK: 1014: ff 25 00 00 40 00 jmpl *4194304 -CHECK: 101a: 90 nop -CHECK: 101b: 90 nop +CHECK: 1000: 55 pushl %ebp +CHECK: 1001: 8b ec movl %esp, %ebp +CHECK: 1003: ff 15 4c 20 40 00 calll *4202572 +CHECK: 1009: 8b 0d 50 20 40 00 movl 4202576, %ecx +CHECK: 100f: 03 01 addl (%ecx), %eax +CHECK: 1011: 5d popl %ebp +CHECK: 1012: c3 ret |