//===- 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 "lld/Core/Simple.h" #include "lld/ReaderWriter/PECOFFLinkingContext.h" #include "llvm/Support/COFF.h" #include #include using llvm::COFF::ImportDirectoryTableEntry; namespace lld { namespace pecoff { namespace idata { class DLLNameAtom; class HintNameAtom; class ImportTableEntryAtom; // A state object of this pass. struct IdataContext { IdataContext(MutableFile &f, VirtualFile &g, const PECOFFLinkingContext &c) : file(f), dummyFile(g), ctx(c) {} MutableFile &file; VirtualFile &dummyFile; const PECOFFLinkingContext &ctx; }; /// The root class of all idata atoms. class IdataAtom : public COFFLinkerInternalAtom { public: SectionChoice sectionChoice() const override { return sectionCustomRequired; } StringRef customSectionName() const override { return ".idata"; } ContentType contentType() const override { return typeData; } ContentPermissions permissions() const override { return permR__; } protected: IdataAtom(IdataContext &context, std::vector data); }; /// 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(IdataContext &context, uint16_t hint, StringRef importName); StringRef getContentString() { return _importName; } private: std::vector assembleRawContent(uint16_t hint, StringRef importName); StringRef _importName; }; class ImportTableEntryAtom : public IdataAtom { public: ImportTableEntryAtom(IdataContext &ctx, uint64_t contents, StringRef sectionName) : IdataAtom(ctx, assembleRawContent(contents, ctx.ctx.is64Bit())), _sectionName(sectionName) {} StringRef customSectionName() const override { return _sectionName; }; private: std::vector assembleRawContent(uint64_t contents, bool is64); StringRef _sectionName; }; /// 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(IdataContext &context, StringRef loadName, const std::vector &sharedAtoms) : IdataAtom(context, std::vector(20, 0)) { addRelocations(context, loadName, sharedAtoms); } StringRef customSectionName() const override { return ".idata.d"; } private: void addRelocations(IdataContext &context, StringRef loadName, const std::vector &sharedAtoms); mutable llvm::BumpPtrAllocator _alloc; }; /// The last NULL entry in the import directory. class NullImportDirectoryAtom : public IdataAtom { public: explicit NullImportDirectoryAtom(IdataContext &context) : IdataAtom(context, std::vector(20, 0)) {} 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 &sharedAtoms) : IdataAtom(context, createContent()) { addRelocations(context, loadName, sharedAtoms); } StringRef customSectionName() const override { return ".didat.d"; } private: std::vector createContent(); void addRelocations(IdataContext &context, StringRef loadName, const std::vector &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 createContent() const { return std::vector( sizeof(llvm::object::delay_import_directory_table_entry), 0); } }; class DelayImportAddressAtom : public IdataAtom { public: explicit DelayImportAddressAtom(IdataContext &context) : IdataAtom(context, createContent(context.ctx)), _align(Alignment(context.ctx.is64Bit() ? 3 : 2)) {} StringRef customSectionName() const override { return ".data"; } ContentPermissions permissions() const override { return permRW_; } Alignment alignment() const override { return _align; } private: std::vector createContent(const PECOFFLinkingContext &ctx) const { return std::vector(ctx.is64Bit() ? 8 : 4, 0); } Alignment _align; }; // 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 createContent(MachineTypes machine) const; }; } // namespace idata class IdataPass : public lld::Pass { public: IdataPass(const PECOFFLinkingContext &ctx) : _dummyFile(ctx), _ctx(ctx) {} void perform(std::unique_ptr &file) override; private: std::map> groupByLoadName(MutableFile &file); void replaceSharedLibraryAtoms(MutableFile &file); // 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. VirtualFile _dummyFile; const PECOFFLinkingContext &_ctx; llvm::BumpPtrAllocator _alloc; }; } // namespace pecoff } // namespace lld #endif