diff options
Diffstat (limited to 'lld/lib/ReaderWriter/PECOFF/IdataPass.h')
| -rw-r--r-- | lld/lib/ReaderWriter/PECOFF/IdataPass.h | 252 |
1 files changed, 33 insertions, 219 deletions
diff --git a/lld/lib/ReaderWriter/PECOFF/IdataPass.h b/lld/lib/ReaderWriter/PECOFF/IdataPass.h index d85604f1a29..5b784185cb0 100644 --- a/lld/lib/ReaderWriter/PECOFF/IdataPass.h +++ b/lld/lib/ReaderWriter/PECOFF/IdataPass.h @@ -25,12 +25,8 @@ #include "lld/Core/Pass.h" #include "lld/ReaderWriter/Simple.h" #include "llvm/Support/COFF.h" -#include "llvm/Support/Debug.h" -#include "llvm/Support/Endian.h" #include <algorithm> -#include <cstddef> -#include <cstring> #include <map> using lld::coff::COFFBaseDefinedAtom; @@ -40,24 +36,16 @@ 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 { -class IdataPassFile; +namespace idata { -namespace { class DLLNameAtom; class HintNameAtom; +class IdataPassFile; class ImportTableEntryAtom; -void addDir32NBReloc(COFFBaseDefinedAtom *atom, const Atom *target, - size_t offsetInAtom = 0) { - atom->addReference(std::unique_ptr<COFFReference>(new COFFReference( - target, offsetInAtom, llvm::COFF::IMAGE_REL_I386_DIR32NB))); -} - // A state object of this pass. struct Context { Context(MutableFile &f, IdataPassFile &g) : file(f), dummyFile(g) {} @@ -69,13 +57,13 @@ struct Context { // 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; + std::vector<COFFBaseDefinedAtom *> importDirectories; + std::vector<ImportTableEntryAtom *> importLookupTables; + std::vector<ImportTableEntryAtom *> importAddressTables; + std::vector<HintNameAtom *> hintNameAtoms; + std::vector<DLLNameAtom *> dllNameAtoms; - map<StringRef, COFFBaseDefinedAtom *> sharedToDefinedAtom; + std::map<StringRef, COFFBaseDefinedAtom *> sharedToDefinedAtom; }; /// The root class of all idata atoms. @@ -85,25 +73,14 @@ public: virtual ContentPermissions permissions() const { return permR__; } protected: - IdataAtom(Context &context, vector<uint8_t> data); + IdataAtom(Context &context, std::vector<uint8_t> data); }; /// 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 &context, StringRef name) - : IdataAtom(context, stringRefToVector(name)) { - context.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 ret; - } + DLLNameAtom(Context &context, StringRef name); }; /// A HintNameAtom represents a symbol that will be imported from a DLL at @@ -116,28 +93,12 @@ private: /// loader can find the symbol quickly. class HintNameAtom : public IdataAtom { public: - HintNameAtom(Context &context, uint16_t hint, StringRef importName) - : IdataAtom(context, assembleRawContent(hint, importName)), - _importName(importName) { - context.hintNameAtoms.push_back(this); - } + HintNameAtom(Context &context, uint16_t hint, StringRef importName); StringRef getContentString() { return _importName; } 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 importName) { - size_t size = - llvm::RoundUpToAlignment(sizeof(hint) + importName.size() + 1, 2); - vector<uint8_t> ret(size); - ret[importName.size()] = 0; - ret[importName.size() - 1] = 0; - *reinterpret_cast<llvm::support::ulittle16_t *>(&ret[0]) = hint; - std::memcpy(&ret[2], importName.data(), importName.size()); - return ret; - } - + std::vector<uint8_t> assembleRawContent(uint16_t hint, StringRef importName); StringRef _importName; }; @@ -147,11 +108,7 @@ public: : IdataAtom(context, assembleRawContent(contents)) {} private: - vector<uint8_t> assembleRawContent(uint32_t contents) { - vector<uint8_t> ret(4); - *reinterpret_cast<llvm::support::ulittle32_t *>(&ret[0]) = contents; - return ret; - } + std::vector<uint8_t> assembleRawContent(uint32_t contents); }; /// An ImportDirectoryAtom includes information to load a DLL, including a DLL @@ -161,66 +118,20 @@ private: class ImportDirectoryAtom : public IdataAtom { public: ImportDirectoryAtom(Context &context, StringRef loadName, - const vector<COFFSharedLibraryAtom *> &sharedAtoms) - : IdataAtom(context, vector<uint8_t>(20, 0)) { + const std::vector<COFFSharedLibraryAtom *> &sharedAtoms) + : IdataAtom(context, std::vector<uint8_t>(20, 0)) { addRelocations(context, loadName, sharedAtoms); context.importDirectories.push_back(this); } private: void addRelocations(Context &context, StringRef loadName, - const vector<COFFSharedLibraryAtom *> &sharedAtoms) { - size_t lookupEnd = context.importLookupTables.size(); - size_t addressEnd = context.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(context, sharedAtoms, false, - context.importLookupTables); - addImportTableAtoms(context, sharedAtoms, true, - context.importAddressTables); - - addDir32NBReloc(this, context.importLookupTables[lookupEnd], - offsetof(ImportDirectoryTableEntry, ImportLookupTableRVA)); - addDir32NBReloc(this, context.importAddressTables[addressEnd], - offsetof(ImportDirectoryTableEntry, ImportAddressTableRVA)); - addDir32NBReloc(this, new (_alloc) DLLNameAtom(context, 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 &context, - const vector<COFFSharedLibraryAtom *> &sharedAtoms, - bool shouldAddReference, - vector<ImportTableEntryAtom *> &ret) const { - for (COFFSharedLibraryAtom *atom : sharedAtoms) { - ImportTableEntryAtom *entry = nullptr; - if (atom->importName().empty()) { - // Import by ordinal - uint32_t hint = (1U << 31) | atom->hint(); - entry = new (_alloc) ImportTableEntryAtom(context, hint); - } else { - // Import by name - entry = new (_alloc) ImportTableEntryAtom(context, 0); - HintNameAtom *hintName = createHintNameAtom(context, atom); - addDir32NBReloc(entry, hintName); - } - ret.push_back(entry); - if (shouldAddReference) - atom->setImportTableEntry(entry); - } - // Add the NULL entry. - ret.push_back(new (_alloc) ImportTableEntryAtom(context, 0)); - } - + const std::vector<COFFSharedLibraryAtom *> &sharedAtoms); + void addImportTableAtoms( + Context &context, const std::vector<COFFSharedLibraryAtom *> &sharedAtoms, + bool shouldAddReference, std::vector<ImportTableEntryAtom *> &ret) const; HintNameAtom *createHintNameAtom(Context &context, - const COFFSharedLibraryAtom *atom) const { - return new (_alloc) HintNameAtom(context, atom->hint(), atom->importName()); - } + const COFFSharedLibraryAtom *atom) const; mutable llvm::BumpPtrAllocator _alloc; }; @@ -229,13 +140,11 @@ private: class NullImportDirectoryAtom : public IdataAtom { public: explicit NullImportDirectoryAtom(Context &context) - : IdataAtom(context, vector<uint8_t>(20, 0)) { + : IdataAtom(context, std::vector<uint8_t>(20, 0)) { context.importDirectories.push_back(this); } }; -} // anonymous namespace - // An instance of this class represents "input file" for atoms created in this // pass. Only one instance of this class is created as a field of IdataPass. class IdataPassFile : public SimpleFile { @@ -251,131 +160,36 @@ private: uint64_t _nextOrdinal; }; +} // namespace idata + class IdataPass : public lld::Pass { public: IdataPass(const LinkingContext &ctx) : _dummyFile(ctx) {} - virtual void perform(std::unique_ptr<MutableFile> &file) { - if (file->sharedLibrary().size() == 0) - return; - - Context context(*file, _dummyFile); - map<StringRef, vector<COFFSharedLibraryAtom *> > sharedAtoms = - groupByLoadName(*file); - for (auto i : sharedAtoms) { - StringRef loadName = i.first; - vector<COFFSharedLibraryAtom *> &atoms = i.second; - createImportDirectory(context, loadName, atoms); - } - - // All atoms, including those of tyep NullImportDirectoryAtom, are added to - // context.file in the IdataAtom's constructor. - new (_alloc) NullImportDirectoryAtom(context); - - connectAtoms(context); - createDataDirectoryAtoms(context); - replaceSharedLibraryAtoms(context); - } + virtual void perform(std::unique_ptr<MutableFile> &file); 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 ret; - } + std::map<StringRef, std::vector<COFFSharedLibraryAtom *> > + groupByLoadName(MutableFile &file); - void createImportDirectory(Context &context, StringRef loadName, - vector<COFFSharedLibraryAtom *> &dllAtoms) { - new (_alloc) ImportDirectoryAtom(context, loadName, dllAtoms); - } + void createImportDirectory(idata::Context &context, StringRef loadName, + std::vector<COFFSharedLibraryAtom *> &dllAtoms); - // Append vec2's elements at the end of vec1. template <typename T, typename U> - void appendAtoms(vector<T *> &vec1, const vector<U *> &vec2) { - vec1.insert(vec1.end(), vec2.begin(), vec2.end()); - } - - void connectAtoms(Context &context) { - vector<COFFBaseDefinedAtom *> atoms; - appendAtoms(atoms, context.importDirectories); - appendAtoms(atoms, context.importLookupTables); - appendAtoms(atoms, context.importAddressTables); - appendAtoms(atoms, context.dllNameAtoms); - appendAtoms(atoms, context.hintNameAtoms); - coff::connectAtomsWithLayoutEdge(atoms); - } + void appendAtoms(std::vector<T *> &vec1, const std::vector<U *> &vec2); - /// 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 the data directory header. We create a COFFDataDirectoryAtom - /// and set relocations to them, so that the address will be set by the - /// writer. - void createDataDirectoryAtoms(Context &context) { - // CLR_RUNTIME_HEADER is the last index of the data directory. - int nentries = llvm::COFF::CLR_RUNTIME_HEADER + 1; - int entSize = sizeof(llvm::object::data_directory); - std::vector<uint8_t> contents(nentries * entSize, 0); - - auto importTableOffset = llvm::COFF::DataDirectoryIndex::IMPORT_TABLE - * entSize; - auto iatOffset = llvm::COFF::DataDirectoryIndex::IAT * entSize; - - auto *importTableEntry = reinterpret_cast<llvm::object::data_directory *>( - &contents[0] + importTableOffset); - auto *iatEntry = reinterpret_cast<llvm::object::data_directory *>( - &contents[0] + iatOffset); - - importTableEntry->Size = context.importDirectories.size() - * context.importDirectories[0]->size(); - iatEntry->Size = context.importAddressTables.size() - * context.importAddressTables[0]->size(); - - auto *dir = new (_alloc) coff::COFFDataDirectoryAtom( - context.dummyFile, context.dummyFile.getNextOrdinal(), - std::move(contents)); - addDir32NBReloc(dir, context.importDirectories[0], importTableOffset); - addDir32NBReloc(dir, context.importAddressTables[0], iatOffset); - - context.file.addAtom(*dir); - } - - /// Transforms a reference to a COFFSharedLibraryAtom to a real reference. - void replaceSharedLibraryAtoms(Context &context) { - for (const DefinedAtom *atom : context.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); - } - } - } + void connectAtoms(idata::Context &context); + void createDataDirectoryAtoms(idata::Context &context); + void replaceSharedLibraryAtoms(idata::Context &context); // A dummy file with which all the atoms created in the pass will be // associated. Atoms need to be associated to an input file even if it's not // read from a file, so we use this object. - IdataPassFile _dummyFile; + idata::IdataPassFile _dummyFile; llvm::BumpPtrAllocator _alloc; }; -IdataAtom::IdataAtom(Context &context, vector<uint8_t> data) - : COFFLinkerInternalAtom(context.dummyFile, - context.dummyFile.getNextOrdinal(), data) { - context.file.addAtom(*this); -} - } // namespace pecoff } // namespace lld |

