Index: include/lld/Core/ArchiveLibraryFile.h =================================================================== --- include/lld/Core/ArchiveLibraryFile.h +++ include/lld/Core/ArchiveLibraryFile.h @@ -33,14 +33,14 @@ /// specified name and return the File object for that member, or nullptr. virtual const File *find(StringRef name, bool dataSymbolOnly) const = 0; - virtual const LinkingContext &getLinkingContext() const { return _context; } + virtual error_code parseAllMembers( + std::vector> &result) const = 0; protected: /// only subclasses of ArchiveLibraryFile can be instantiated - ArchiveLibraryFile(const LinkingContext &context, StringRef path) - : File(path, kindArchiveLibrary), _context(context) {} + ArchiveLibraryFile(StringRef path) + : File(path, kindArchiveLibrary) {} - const LinkingContext &_context; }; } // namespace lld Index: include/lld/Core/File.h =================================================================== --- include/lld/Core/File.h +++ include/lld/Core/File.h @@ -156,8 +156,6 @@ /// all AbsoluteAtoms in this File. virtual const atom_collection &absolute() const = 0; - virtual const LinkingContext &getLinkingContext() const = 0; - protected: /// \brief only subclasses of File can be instantiated File(StringRef p, Kind kind) : _path(p), _kind(kind), _ordinal(UINT64_MAX) {} @@ -235,15 +233,10 @@ typedef range::iterator> DefinedAtomRange; virtual DefinedAtomRange definedAtoms() = 0; - virtual const LinkingContext &getLinkingContext() const { return _context; } - protected: /// \brief only subclasses of MutableFile can be instantiated - MutableFile(const LinkingContext &ctx, StringRef p) - : File(p, kindObject), _context(ctx) {} - -private: - const LinkingContext &_context; + MutableFile(StringRef p) + : File(p, kindObject){} }; } // end namespace lld Index: include/lld/Core/LinkingContext.h =================================================================== --- include/lld/Core/LinkingContext.h +++ include/lld/Core/LinkingContext.h @@ -24,10 +24,6 @@ #include #include -namespace llvm { -class Triple; -} - namespace lld { class PassManager; class File; @@ -40,10 +36,8 @@ /// /// The base class LinkingContext contains the options needed by core linking. /// Subclasses of LinkingContext have additional options needed by specific -/// Readers -/// and Writers. For example, ELFLinkingContext has methods that supplies -/// options -/// to the ELF Reader and Writer. +/// Writers. For example, ELFLinkingContext has methods that supplies +/// options to the ELF Writer and ELF Passes. class LinkingContext { public: /// \brief The types of output file that the linker @@ -283,14 +277,9 @@ /// Returns the output file that that the linker needs to create OutputFileType outputFileType() const { return _outputFileType; } - /// Returns the YAML reader. - virtual Reader &getYAMLReader() const { return *_yamlReader; } - - /// Returns the LLD Native file format reader. - virtual Reader &getNativeReader() const { return *_nativeReader; } - - /// Return the default reader for the target - virtual Reader &getDefaultReader() const = 0; + /// + const Registry ®istry() const { return _registry; } + Registry ®istry() { return _registry; } /// This method is called by core linking to give the Writer a chance /// to add file format specific "files" to set of files to be linked. This is @@ -323,23 +312,9 @@ /// Return the next ordinal and Increment it. virtual uint64_t getNextOrdinalAndIncrement() const { return _nextOrdinal++; } - + /// @} - - /// \name Methods needed by YAML I/O and error messages to convert Kind values - /// to and from strings. - /// @{ - - /// Abstract method to parse a kind name string into an integral - /// Reference::Kind - virtual ErrorOr relocKindFromString(StringRef str) const = 0; - - /// Abstract method to return the name for a given integral - /// Reference::Kind. - virtual ErrorOr stringFromRelocKind(Reference::Kind k) const = 0; - - /// @} - + protected: LinkingContext(); // Must be subclassed @@ -367,18 +342,18 @@ OutputFileType _outputFileType; std::vector _deadStripRoots; std::vector _llvmOptions; - std::unique_ptr _yamlReader; - std::unique_ptr _nativeReader; StringRefVector _initialUndefinedSymbols; std::unique_ptr _inputGraph; mutable llvm::BumpPtrAllocator _allocator; InputElement *_currentInputElement; mutable uint64_t _nextOrdinal; + Registry _registry; private: /// Validate the subclass bits. Only called by validate. virtual bool validateImpl(raw_ostream &diagnostics) = 0; }; + } // end namespace lld #endif Index: include/lld/Core/Pass.h =================================================================== --- include/lld/Core/Pass.h +++ include/lld/Core/Pass.h @@ -63,7 +63,7 @@ /// Returns whether the Reference kind is for a call site. The pass /// uses this to find calls that need to be indirected through a stub. - virtual bool isCallSite(int32_t) = 0; + virtual bool isCallSite(const Reference &) = 0; /// Returns a file format specific atom for a stub/PLT entry which contains /// instructions which jump to the specified atom. May be called multiple @@ -101,7 +101,7 @@ /// Returns whether the Reference kind is a pre-instantiated GOT access. /// The default implementation of perform() uses this to figure out /// what GOT entries to instantiate. - virtual bool isGOTAccess(int32_t, bool &canBypassGOT) = 0; + virtual bool isGOTAccess(const Reference &, bool &canBypassGOT) = 0; /// The file format Writer needs to alter the reference kind from a /// pre-instantiated GOT access to an actual access. If targetIsNowGOT is Index: include/lld/Core/Reference.h =================================================================== --- include/lld/Core/Reference.h +++ include/lld/Core/Reference.h @@ -29,53 +29,56 @@ /// grouping atoms (group comdat), forcing layout (one atom must follow /// another), marking data-in-code (jump tables or ARM constants), etc. /// +/// The "kind" of a reference is a tuple of . This +/// enable us to re-use existing relocation types definded for various +/// file formats and architectures. For instance, in ELF the relocation type 10 +/// means R_X86_64_32 for x86_64, and R_386_GOTPC for i386. For PE/COFF +/// relocation 10 means IMAGE_REL_AMD64_SECTION. +/// class Reference { public: - /// The meaning of positive kind values is architecture specific. - /// Negative kind values are architecture independent. - typedef int32_t Kind; + /// Which universe defines the kindValue(). + enum class KindNamespace { + all = 0, + testing = 1, + ELF = 2, + COFF = 3, + mach_o = 4, + }; + KindNamespace kindNamespace() const { return (KindNamespace)_kindNamespace; } + void setKindNamespace(KindNamespace ns) { _kindNamespace = (uint8_t)ns; } + + // Which architecture the kind value is for. + enum class KindArch { + all = 0, + x86_64 = 1, + x86 = 2, + ARM = 3, + PowerPC = 4, + Hexagon = 5, + Mips = 6 + }; + + KindArch kindArch() const { return (KindArch)_kindArch; } + void setKindArch(KindArch a) { _kindArch = (uint8_t)a; } + + uint16_t kindValue() const { return _kindValue; } + + /// setKindValue() is needed because during linking, some optimizations may + /// change the codegen and hence the reference kind. + void setKindValue(uint16_t value) { _kindValue = value; }; + + /// KindValues used with KindNamespace::all and KindArch::all. enum { - kindInGroup = -3, - kindLayoutAfter = -2, - kindLayoutBefore = -1, - kindTargetLow = 0 + kindInGroup = 1, + kindLayoutAfter = 2, + kindLayoutBefore = 3 }; // A value to be added to the value of a target typedef int64_t Addend; - /// What sort of reference this is. - Kind kind() const { return _kind; } - - /// During linking, some optimizations may change the code gen and - /// hence the reference kind. - void setKind(Kind kind) { _kind = kind; }; - - virtual StringRef kindToString() const { - switch (kind()) { - case kindLayoutBefore: - return "layout-before"; - case kindLayoutAfter: - return "layout-after"; - case kindInGroup: - return "in-group"; - default: - return "unknown"; - } - } - - virtual int32_t stringToKind(StringRef kindString) const { - if (kindString == "in-group") - return kindInGroup; - else if (kindString == "layout-before") - return kindLayoutBefore; - else if (kindString == "layout-after") - return kindLayoutAfter; - assert(0 && "unknown relocation kind"); - return -1; - } - /// If the reference is a fixup in the Atom, then this returns the /// byte offset into the Atom's content to do the fix up. virtual uint64_t offsetInAtom() const = 0; @@ -95,8 +98,9 @@ virtual void setAddend(Addend) = 0; protected: - /// Atom is an abstract base class. Only subclasses can access constructor. - Reference() {} + /// Reference is an abstract base class. Only subclasses can use constructor. + Reference(KindNamespace ns, KindArch a, uint16_t value) + : _kindValue(value), _kindNamespace((uint8_t)ns), _kindArch((uint8_t)a) {} /// The memory for Reference objects is always managed by the owning File /// object. Therefore, no one but the owning File object should call @@ -104,7 +108,9 @@ /// an array of References, so they cannot be individually deleted by anyone. virtual ~Reference() {} - Kind _kind; + uint16_t _kindValue; + uint8_t _kindNamespace; + uint8_t _kindArch; }; } // namespace lld Index: include/lld/Core/Resolver.h =================================================================== --- include/lld/Core/Resolver.h +++ include/lld/Core/Resolver.h @@ -38,7 +38,7 @@ Resolver(LinkingContext &context) : _context(context), _symbolTable(context), - _result(new MergedFile(context)), _haveLLVMObjs(false), + _result(new MergedFile()), _haveLLVMObjs(false), _addToFinalSection(false) {} virtual ~Resolver() {} @@ -84,9 +84,9 @@ class MergedFile : public MutableFile { public: - MergedFile(const LinkingContext &context) - : MutableFile(context, "") {} - + MergedFile() + : MutableFile("") {} + virtual const atom_collection &defined() const { return _definedAtoms; } Index: include/lld/Driver/CoreInputGraph.h =================================================================== --- include/lld/Driver/CoreInputGraph.h +++ include/lld/Driver/CoreInputGraph.h @@ -18,6 +18,7 @@ #define LLD_DRIVER_CORE_INPUT_GRAPH_H #include "lld/Core/InputGraph.h" +#include "lld/ReaderWriter/Reader.h" #include "lld/ReaderWriter/CoreLinkingContext.h" #include @@ -54,7 +55,7 @@ std::unique_ptr mb(opmb.take()); _buffer = std::move(mb); - return _ctx.getDefaultReader().parseFile(_buffer, _files); + return ctx.registry().parseFile(_buffer, _files); } /// \brief Return the file that has to be processed by the resolver Index: include/lld/Driver/DarwinInputGraph.h =================================================================== --- include/lld/Driver/DarwinInputGraph.h +++ include/lld/Driver/DarwinInputGraph.h @@ -18,6 +18,7 @@ #define LLD_DRIVER_DARWIN_INPUT_GRAPH_H #include "lld/Core/InputGraph.h" +#include "lld/Core/ArchiveLibraryFile.h" #include "lld/ReaderWriter/MachOLinkingContext.h" #include @@ -52,11 +53,24 @@ if (ctx.logInputFiles()) diagnostics << *filePath << "\n"; - if (filePath->endswith(".objtxt")) - return ctx.getYAMLReader().parseFile(_buffer, _files); - - (void) (_isWholeArchive); - return error_code::success(); + if (_isWholeArchive) { + std::vector> parsedFiles; + error_code ec = ctx.registry().parseFile(_buffer, parsedFiles); + if (ec) + return ec; + assert(parsedFiles.size() == 1); + std::unique_ptr f(parsedFiles[0].release()); + if (auto archive = reinterpret_cast(f.get())) { + // FIXME: something needs to own archive File + //_files.push_back(std::move(archive)); + return archive->parseAllMembers(_files); + } else { + // if --whole-archive is around non-archive, just use it as normal. + _files.push_back(std::move(f)); + return error_code::success(); + } + } + return ctx.registry().parseFile(_buffer, _files); } /// \brief Return the file that has to be processed by the resolver Index: include/lld/Driver/GnuLdInputGraph.h =================================================================== --- include/lld/Driver/GnuLdInputGraph.h +++ include/lld/Driver/GnuLdInputGraph.h @@ -17,10 +17,10 @@ #ifndef LLD_DRIVER_GNU_LD_INPUT_GRAPH_H #define LLD_DRIVER_GNU_LD_INPUT_GRAPH_H +#include "lld/Core/ArchiveLibraryFile.h" #include "lld/Core/InputGraph.h" #include "lld/Core/Resolver.h" #include "lld/ReaderWriter/ELFLinkingContext.h" -#include "lld/ReaderWriter/FileArchive.h" #include "lld/ReaderWriter/LinkerScript.h" namespace lld { @@ -95,7 +95,7 @@ bool _isWholeArchive; bool _asNeeded; bool _isDashlPrefix; - std::unique_ptr _archiveFile; + std::unique_ptr _archiveFile; }; /// \brief Represents a ELF control node Index: include/lld/Driver/WinLinkInputGraph.h =================================================================== --- include/lld/Driver/WinLinkInputGraph.h +++ include/lld/Driver/WinLinkInputGraph.h @@ -19,7 +19,6 @@ #include "lld/Core/InputGraph.h" #include "lld/ReaderWriter/PECOFFLinkingContext.h" -#include "lld/ReaderWriter/FileArchive.h" #include Index: include/lld/ReaderWriter/CoreLinkingContext.h =================================================================== --- include/lld/ReaderWriter/CoreLinkingContext.h +++ include/lld/ReaderWriter/CoreLinkingContext.h @@ -18,24 +18,28 @@ namespace lld { + class CoreLinkingContext : public LinkingContext { public: CoreLinkingContext(); + enum { + TEST_RELOC_CALL32 = 1, + TEST_RELOC_PCREL32 = 2, + TEST_RELOC_GOT_LOAD32 = 3, + TEST_RELOC_GOT_USE32 = 4, + TEST_RELOC_LEA32_WAS_GOT = 5, + }; + virtual bool validateImpl(raw_ostream &diagnostics); virtual void addPasses(PassManager &pm); - virtual ErrorOr relocKindFromString(StringRef str) const; - virtual ErrorOr stringFromRelocKind(Reference::Kind kind) const; void addPassNamed(StringRef name) { _passNames.push_back(name); } - virtual Reader &getDefaultReader() const { return *_reader; } - protected: virtual Writer &writer() const; private: - std::unique_ptr _reader; std::unique_ptr _writer; std::vector _passNames; }; Index: include/lld/ReaderWriter/ELFLinkingContext.h =================================================================== --- include/lld/ReaderWriter/ELFLinkingContext.h +++ include/lld/ReaderWriter/ELFLinkingContext.h @@ -36,8 +36,11 @@ class TargetHandlerBase { public: virtual ~TargetHandlerBase() {} + virtual void registerRelocationNames(Registry &) = 0; }; + + class ELFLinkingContext : public LinkingContext { public: @@ -115,8 +118,6 @@ return getDefaultInterpreter(); } - virtual Reader &getDefaultReader() const { return *_elfReader; } - /// \brief Does the output have dynamic sections. virtual bool isDynamic() const; @@ -129,6 +130,9 @@ return static_cast &>(*_targetHandler.get()); } + TargetHandlerBase *targetHandler() const { + return _targetHandler.get(); + } virtual void addPasses(PassManager &pm); void setTriple(llvm::Triple trip) { _triple = trip; } @@ -228,7 +232,7 @@ ELFLinkingContext() LLVM_DELETED_FUNCTION; protected: - ELFLinkingContext(llvm::Triple, std::unique_ptr); + ELFLinkingContext( llvm::Triple, std::unique_ptr); virtual Writer &writer() const; @@ -248,7 +252,6 @@ bool _noAllowDynamicLibraries; OutputMagic _outputMagic; StringRefVector _inputSearchPaths; - std::unique_ptr _elfReader; std::unique_ptr _writer; StringRef _dynamicLinkerPath; StringRefVector _initFunctions; Index: include/lld/ReaderWriter/FileArchive.h =================================================================== --- include/lld/ReaderWriter/FileArchive.h +++ include/lld/ReaderWriter/FileArchive.h @@ -19,40 +19,6 @@ namespace lld { -/// \brief The FileArchive class represents an Archive Library file -class FileArchive : public ArchiveLibraryFile { -public: - FileArchive(const LinkingContext &context, std::unique_ptr mb, - error_code &ec, bool isWholeArchive); - virtual ~FileArchive() {} - - virtual const File *find(StringRef name, bool dataSymbolOnly) const; - - /// \brief Load all members of the archive? - virtual bool isWholeArchive() const { return _isWholeArchive; } - - /// \brief parse each member - virtual error_code - parseAllMembers(std::vector > &result) const; - - virtual const atom_collection &defined() const; - virtual const atom_collection &undefined() const; - virtual const atom_collection &sharedLibrary() const; - virtual const atom_collection &absolute() const; - -protected: - error_code isDataSymbol(MemoryBuffer *mb, StringRef symbol) const; - -private: - std::unique_ptr _archive; - atom_collection_vector _definedAtoms; - atom_collection_vector _undefinedAtoms; - atom_collection_vector _sharedLibraryAtoms; - atom_collection_vector _absoluteAtoms; - bool _isWholeArchive; - std::unordered_map - _symbolMemberMap; -}; } // end namespace lld Index: include/lld/ReaderWriter/MachOLinkingContext.h =================================================================== --- include/lld/ReaderWriter/MachOLinkingContext.h +++ include/lld/ReaderWriter/MachOLinkingContext.h @@ -31,8 +31,6 @@ ~MachOLinkingContext(); virtual void addPasses(PassManager &pm); - virtual ErrorOr relocKindFromString(StringRef str) const; - virtual ErrorOr stringFromRelocKind(Reference::Kind kind) const; virtual bool validateImpl(raw_ostream &diagnostics); uint32_t getCPUType() const; @@ -65,6 +63,7 @@ }; Arch arch() const { return _arch; } + StringRef archName() const { return nameFromArch(_arch); } OS os() const { return _os; } void setOutputFileType(HeaderFileType type) { _outputFileType = type; } @@ -74,8 +73,6 @@ void setDoNothing(bool value) { _doNothing = value; } bool doNothing() const { return _doNothing; } - virtual Reader &getDefaultReader() const { return *_machoReader; } - /// \brief The dylib's binary compatibility version, in the raw uint32 format. /// /// When building a dynamic library, this is the compatibility version that @@ -125,6 +122,7 @@ static Arch archFromCpuType(uint32_t cputype, uint32_t cpusubtype); static Arch archFromName(StringRef archName); + static StringRef nameFromArch(Arch arch); static uint32_t cpuTypeFromArch(Arch arch); static uint32_t cpuSubtypeFromArch(Arch arch); static bool is64Bit(Arch arch); @@ -163,7 +161,6 @@ bool _deadStrippableDylib; StringRef _bundleLoader; mutable std::unique_ptr _kindHandler; - mutable std::unique_ptr _machoReader; mutable std::unique_ptr _writer; Index: include/lld/ReaderWriter/PECOFFLinkingContext.h =================================================================== --- include/lld/ReaderWriter/PECOFFLinkingContext.h +++ include/lld/ReaderWriter/PECOFFLinkingContext.h @@ -73,8 +73,6 @@ IMAGE_DLL }; - virtual Reader &getDefaultReader() const { return *_reader; } - virtual Writer &writer() const; virtual bool validateImpl(raw_ostream &diagnostics); @@ -199,6 +197,9 @@ StringRef from, StringRef to); StringRef getAlternateName(StringRef def) const; + const std::map &alternateNames() { + return _alternateNames; + } void setAlternateName(StringRef def, StringRef weak); void addNoDefaultLib(StringRef path) { _noDefaultLibs.insert(path); } @@ -209,9 +210,6 @@ void setNoDefaultLibAll(bool val) { _noDefaultLibAll = val; } bool getNoDefaultLibAll() const { return _noDefaultLibAll; } - virtual ErrorOr relocKindFromString(StringRef str) const; - virtual ErrorOr stringFromRelocKind(Reference::Kind kind) const; - void setSectionSetMask(StringRef sectionName, uint32_t flags); void setSectionClearMask(StringRef sectionName, uint32_t flags); uint32_t getSectionAttributes(StringRef sectionName, uint32_t flags) const; @@ -285,7 +283,6 @@ std::set _noDefaultLibs; std::vector _inputSearchPaths; - std::unique_ptr _reader; std::unique_ptr _writer; // A map for weak aliases. Index: include/lld/ReaderWriter/Reader.h =================================================================== --- include/lld/ReaderWriter/Reader.h +++ include/lld/ReaderWriter/Reader.h @@ -11,16 +11,23 @@ #define LLD_READER_WRITER_READER_H #include "lld/Core/LLVM.h" +#include "lld/Core/Reference.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/YAMLTraits.h" #include #include #include +using llvm::sys::fs::file_magic; + namespace lld { class ELFLinkingContext; class File; class LinkingContext; class PECOFFLinkingContext; +class TargetHandlerBase; + /// \brief An abstract class for reading object files, library files, and /// executable files. @@ -31,26 +38,97 @@ public: virtual ~Reader(); + /// Sniffs the file to determine if this Reader can parse it. + /// The method is called with: + /// 1) the file_magic enumeration returned by identify_magic() + /// 2) the file extenstion (e.g. ".obj") + /// 3) the whole file content buffer if the above is not enough. + virtual bool canParse(file_magic magic, StringRef fileExtention, + const MemoryBuffer &mb) const = 0; + /// \brief Parse a supplied buffer (already filled with the contents of a /// file) and create a File object. /// - /// On success, the resulting File object takes ownership of the MemoryBuffer. + /// The resulting File object may take ownership of the MemoryBuffer. virtual error_code - parseFile(std::unique_ptr &mb, + parseFile(std::unique_ptr &mb, const class Registry &, std::vector > &result) const = 0; +}; -protected: - // only concrete subclasses can be instantiated - Reader(const LinkingContext &context) : _context(context) {} - const LinkingContext &_context; +/// A registry to hold the list of currently registered Readers and +/// tables which map Reference kind values to strings. +/// The linker does not directly invoke Readers. Instead, it registers +/// Readers based on it configuration and command line options, then calls +/// the Registry object to parse files. +class Registry { +public: + Registry(); + + /// Walk the list of registered Readers and find one that can parse the + /// supplied file and parse it. + error_code parseFile(std::unique_ptr &mb, + std::vector> &result) const; + + /// Walk the list of registered kind tables to convert a Reference Kind + /// name to a value. + bool referenceKindFromString(StringRef inputStr, Reference::KindNamespace &ns, + Reference::KindArch &a, uint16_t &value) const; + + /// Walk the list of registered kind tables to convert a Reference Kind + /// value to a string. + bool referenceKindToString(Reference::KindNamespace ns, Reference::KindArch a, + uint16_t value, StringRef &) const; + + // These methods are called to dynamically add support for various file + // formats. The methods are also implemented in the appropriate lib*.a + // library, so that the code for handling a format is only linked in, if this + // method is used. Any options that a Reader might need must be passed + // as parameters to the adSupport*() method. + void addSupportArchives(bool logLoading); + void addSupportYamlFiles(); + void addSupportNativeObjects(); + void addSupportCOFFObjects(PECOFFLinkingContext &); + void addSupportCOFFImportLibraries(); + void addSupportWindowsResourceFiles(); + void addSupportMachOObjects(StringRef archName); + void addSupportELFObjects(bool atomizeStrings, TargetHandlerBase *handler); + void addSupportELFDynamicSharedObjects(bool useShlibUndefines); + + /// To convert between kind values and names, the registry walks the list + /// of registered kind tables. Each table is a zero terminated array of + /// KindStrings elements. + struct KindStrings { uint16_t value; StringRef name; }; + + /// A Reference Kind value is a tuple of . All + /// entries in a conversion table have the same . The + /// array then contains the value/name pairs. + void addKindTable(Reference::KindNamespace ns, Reference::KindArch arch, + const KindStrings array[]); + +private: + struct KindEntry { + Reference::KindNamespace ns; + Reference::KindArch arch; + const KindStrings *array; + }; + + void add(std::unique_ptr); + + std::vector> _readers; + std::vector _kindEntries; }; -std::unique_ptr createReaderELF(const ELFLinkingContext &); -std::unique_ptr createReaderMachO(const LinkingContext &); -std::unique_ptr createReaderNative(const LinkingContext &); -std::unique_ptr createReaderPECOFF(PECOFFLinkingContext &); -std::unique_ptr createReaderYAML(const LinkingContext &); +// Utilities for building a KindString table. For instance: +// static const Registry::KindStrings table[] = { +// LLD_KIND_STRING_ENTRY(R_VAX_ADDR16), +// LLD_KIND_STRING_ENTRY(R_VAX_DATA16), +// LLD_KIND_STRING_END +// }; +#define LLD_KIND_STRING_ENTRY(name) { name, #name } +#define LLD_KIND_STRING_END {0, ""} + + } // end namespace lld #endif Index: include/lld/ReaderWriter/Simple.h =================================================================== --- include/lld/ReaderWriter/Simple.h +++ include/lld/ReaderWriter/Simple.h @@ -23,8 +23,8 @@ namespace lld { class SimpleFile : public MutableFile { public: - SimpleFile(const LinkingContext &context, StringRef path) - : MutableFile(context, path) {} + SimpleFile(StringRef path) + : MutableFile(path) {} virtual void addAtom(const Atom &atom) { if (const DefinedAtom *defAtom = dyn_cast(&atom)) { @@ -63,16 +63,16 @@ } protected: - atom_collection_vector _definedAtoms; - atom_collection_vector _undefinedAtoms; + atom_collection_vector _definedAtoms; + atom_collection_vector _undefinedAtoms; atom_collection_vector _sharedLibraryAtoms; - atom_collection_vector _absoluteAtoms; + atom_collection_vector _absoluteAtoms; }; class FileToMutable : public SimpleFile { public: - FileToMutable(const LinkingContext &context, File &file) - : SimpleFile(context, file.path()) { + FileToMutable(const LinkingContext &context, const File &file) + : SimpleFile(file.path()) { for (auto definedAtom : file.defined()) _definedAtoms._atoms.push_back(std::move(definedAtom)); for (auto undefAtom : file.undefined()) @@ -86,10 +86,10 @@ class SimpleReference : public Reference { public: - SimpleReference(Reference::Kind k, uint64_t off, const Atom *t, + SimpleReference(Reference::KindNamespace ns, Reference::KindArch arch, + uint16_t value, uint64_t off, const Atom *t, Reference::Addend a) - : _target(t), _offsetInAtom(off), _addend(a) { - _kind = k; + : Reference(ns, arch, value), _target(t), _offsetInAtom(off), _addend(a) { } virtual uint64_t offsetInAtom() const { return _offsetInAtom; } @@ -167,9 +167,10 @@ it = reinterpret_cast(index); } - void addReference(Reference::Kind kind, uint64_t offset, const Atom *target, - Reference::Addend addend) { - _references.push_back(SimpleReference(kind, offset, target, addend)); + void addReference(Reference::KindNamespace ns, Reference::KindArch arch, + uint16_t kindValue, uint64_t off, const Atom *target, + Reference::Addend a) { + _references.push_back(SimpleReference(ns, arch, kindValue, off, target, a)); } void setOrdinal(uint64_t ord) { _ordinal = ord; } Index: include/lld/ReaderWriter/YamlContext.h =================================================================== --- /dev/null +++ include/lld/ReaderWriter/YamlContext.h @@ -0,0 +1,47 @@ +//===- lld/ReaderWriter/YamlContext.h - object used in YAML I/O context ---===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_READER_WRITER_YAML_CONTEXT_H +#define LLD_READER_WRITER_YAML_CONTEXT_H + +#include "lld/Core/LLVM.h" + +#include +#include +#include + +namespace lld { + class File; + class LinkingContext; + namespace mach_o { + namespace normalized { + struct NormalizedFile; + } + } +using lld::mach_o::normalized::NormalizedFile; + +/// When YAML I/O is used in lld, the yaml context always holds a YamlContext +/// object. We need to support hetergenous yaml documents which each require +/// different context info. This struct supports all clients. +struct YamlContext { + YamlContext() + : _linkingContext(nullptr), _registry(nullptr), _file(nullptr), + _normalizeMachOFile(nullptr){} + + const LinkingContext *_linkingContext; + const Registry *_registry; + File *_file; + NormalizedFile *_normalizeMachOFile; +}; + +} // end namespace lld + +#endif // LLD_READER_WRITER_YAML_CONTEXT_H + + Index: lib/Core/LinkingContext.cpp =================================================================== --- lib/Core/LinkingContext.cpp +++ lib/Core/LinkingContext.cpp @@ -30,8 +30,6 @@ LinkingContext::~LinkingContext() {} bool LinkingContext::validate(raw_ostream &diagnostics) { - _yamlReader = createReaderYAML(*this); - _nativeReader = createReaderNative(*this); return validateImpl(diagnostics); } @@ -48,7 +46,7 @@ if (entrySymbolName().empty()) return nullptr; std::unique_ptr entryFile( - new SimpleFile(*this, "command line option -entry")); + new SimpleFile("command line option -entry")); entryFile->addAtom( *(new (_allocator) SimpleUndefinedAtom(*entryFile, entrySymbolName()))); return std::move(entryFile); @@ -58,7 +56,7 @@ if (_initialUndefinedSymbols.empty()) return nullptr; std::unique_ptr undefinedSymFile( - new SimpleFile(*this, "command line option -u")); + new SimpleFile("command line option -u")); for (auto undefSymStr : _initialUndefinedSymbols) undefinedSymFile->addAtom(*(new (_allocator) SimpleUndefinedAtom( *undefinedSymFile, undefSymStr))); Index: lib/Driver/CoreDriver.cpp =================================================================== --- lib/Driver/CoreDriver.cpp +++ lib/Driver/CoreDriver.cpp @@ -66,11 +66,31 @@ namespace lld { +static const Registry::KindStrings coreKindStrings[] = { + { CoreLinkingContext::TEST_RELOC_CALL32, "call32" }, + { CoreLinkingContext::TEST_RELOC_PCREL32, "pcrel32" }, + { CoreLinkingContext::TEST_RELOC_GOT_LOAD32, "gotLoad32" }, + { CoreLinkingContext::TEST_RELOC_GOT_USE32, "gotUse32" }, + { CoreLinkingContext::TEST_RELOC_LEA32_WAS_GOT, "lea32wasGot" }, + LLD_KIND_STRING_END +}; + + bool CoreDriver::link(int argc, const char *argv[], raw_ostream &diagnostics) { - CoreLinkingContext info; - if (!parse(argc, argv, info)) + CoreLinkingContext ctx; + if (!parse(argc, argv, ctx)) return false; - return Driver::link(info); + + // Register possible input file parsers. + ctx.registry().addSupportNativeObjects(); + ctx.registry().addSupportYamlFiles(); + + ctx.registry().addKindTable(Reference::KindNamespace::testing, + Reference::KindArch::all, + coreKindStrings); + + + return Driver::link(ctx); } bool CoreDriver::parse(int argc, const char *argv[], CoreLinkingContext &ctx, Index: lib/Driver/DarwinLdDriver.cpp =================================================================== --- lib/Driver/DarwinLdDriver.cpp +++ lib/Driver/DarwinLdDriver.cpp @@ -77,6 +77,13 @@ return false; if (ctx.doNothing()) return true; + + // Register possible input file parsers. + ctx.registry().addSupportMachOObjects(ctx.archName()); + ctx.registry().addSupportArchives(ctx.logInputFiles()); + ctx.registry().addSupportNativeObjects(); + ctx.registry().addSupportYamlFiles(); + return link(ctx, diagnostics); } Index: lib/Driver/GnuLdDriver.cpp =================================================================== --- lib/Driver/GnuLdDriver.cpp +++ lib/Driver/GnuLdDriver.cpp @@ -110,6 +110,16 @@ if (!options) return true; + // Register possible input file parsers. + options->registry().addSupportELFObjects(options->mergeCommonStrings(), + options->targetHandler()); + options->registry().addSupportArchives(options->logInputFiles()); + options->registry().addSupportYamlFiles(); + options->registry().addSupportNativeObjects(); + if (options->allowLinkWithDynamicLibraries()) + options->registry().addSupportELFDynamicSharedObjects( + options->useShlibUndefines()); + return link(*options, diagnostics); } @@ -326,6 +336,8 @@ } resolvedInputPath = resolvedPath->str(); } + // FIXME: Calling getFileMagic() is is expensive. It would be better to + // wire up the LdScript parser into the registry. llvm::sys::fs::file_magic magic = llvm::sys::fs::file_magic::unknown; error_code ec = getFileMagic(*ctx, resolvedInputPath, magic); if (ec) { @@ -336,7 +348,6 @@ if ((!userPath.endswith(".objtxt")) && (magic == llvm::sys::fs::file_magic::unknown)) isELFFileNode = false; - FileNode *inputNode = nullptr; if (isELFFileNode) inputNode = new ELFFileNode(*ctx, userPath, index++, isWholeArchive, Index: lib/Driver/GnuLdInputGraph.cpp =================================================================== --- lib/Driver/GnuLdInputGraph.cpp +++ lib/Driver/GnuLdInputGraph.cpp @@ -25,38 +25,27 @@ if (ctx.logInputFiles()) diagnostics << *filePath << "\n"; - if (filePath->endswith(".objtxt")) - return ctx.getYAMLReader().parseFile(_buffer, _files); - - // Identify File type - llvm::sys::fs::file_magic FileType = - llvm::sys::fs::identify_magic(_buffer->getBuffer()); - - switch (FileType) { - case llvm::sys::fs::file_magic::elf_relocatable: - case llvm::sys::fs::file_magic::elf_shared_object: - // Call the default reader to read object files and shared objects - return _elfLinkingContext.getDefaultReader().parseFile(_buffer, _files); - - case llvm::sys::fs::file_magic::archive: { - // Process archive files. If Whole Archive option is set, - // parse all members of the archive. - error_code ec; - std::unique_ptr fileArchive( - new FileArchive(ctx, std::move(_buffer), ec, _isWholeArchive)); - if (_isWholeArchive) { - fileArchive->parseAllMembers(_files); - _archiveFile = std::move(fileArchive); - } else { - _files.push_back(std::move(fileArchive)); + if (_isWholeArchive) { + std::vector> parsedFiles; + error_code ec = ctx.registry().parseFile(_buffer, parsedFiles); + if (ec) + return ec; + assert(parsedFiles.size() == 1); + std::unique_ptr f(parsedFiles[0].release()); + if (auto archive = reinterpret_cast(f.get())) { + // Have this node own the FileArchive object. + _archiveFile.reset(archive); + f.release(); + // Add all members to _files vector + return archive->parseAllMembers(_files); + } + else { + // if --whole-archive is around non-archive, just use it as normal. + _files.push_back(std::move(f)); + return error_code::success(); } - return ec; - } - - default: - break; } - return error_code::success(); + return ctx.registry().parseFile(_buffer, _files); } /// \brief Parse the GnuLD Script Index: lib/Driver/WinLinkDriver.cpp =================================================================== --- lib/Driver/WinLinkDriver.cpp +++ lib/Driver/WinLinkDriver.cpp @@ -645,6 +645,14 @@ if (!createManifest(context, diagnostics)) return false; + // Register possible input file parsers. + context.registry().addSupportCOFFObjects(context); + context.registry().addSupportCOFFImportLibraries(); + context.registry().addSupportWindowsResourceFiles(); + context.registry().addSupportArchives(context.logInputFiles()); + context.registry().addSupportNativeObjects(); + context.registry().addSupportYamlFiles(); + return link(context, diagnostics); } Index: lib/Driver/WinLinkInputGraph.cpp =================================================================== --- lib/Driver/WinLinkInputGraph.cpp +++ lib/Driver/WinLinkInputGraph.cpp @@ -9,9 +9,6 @@ #include "lld/Driver/WinLinkInputGraph.h" -using llvm::sys::fs::file_magic; -using llvm::sys::fs::identify_magic; - namespace lld { /// \brief Parse the input file to lld::File. @@ -31,16 +28,7 @@ if (ctx.logInputFiles()) diagnostics << *filePath << "\n"; - if (filePath->endswith(".objtxt")) - return ctx.getYAMLReader().parseFile(_buffer, _files); - if (identify_magic(_buffer->getBuffer()) == file_magic::archive) { - // Archive File - error_code ec; - _files.push_back(std::unique_ptr( - new FileArchive(ctx, std::move(_buffer), ec, false))); - return ec; - } - return _ctx.getDefaultReader().parseFile(_buffer, _files); + return ctx.registry().parseFile(_buffer, _files); } ErrorOr PECOFFFileNode::getNextFile() { Index: lib/Passes/GOTPass.cpp =================================================================== --- lib/Passes/GOTPass.cpp +++ lib/Passes/GOTPass.cpp @@ -75,7 +75,7 @@ for (const Reference *ref : *atom) { // Look at instructions accessing the GOT. bool canBypassGOT; - if (!isGOTAccess(ref->kind(), canBypassGOT)) + if (!isGOTAccess(*ref, canBypassGOT)) continue; const Atom *target = ref->target(); assert(target != nullptr); Index: lib/Passes/LayoutPass.cpp =================================================================== --- lib/Passes/LayoutPass.cpp +++ lib/Passes/LayoutPass.cpp @@ -70,8 +70,7 @@ do { llvm::dbgs() << " " << atomToDebugString(atom) << "\n"; for (const Reference *ref : *atom) { - llvm::dbgs() << " " << ref->kindToString() - << ": " << atomToDebugString(ref->target()) << "\n"; + llvm::dbgs() << ": " << atomToDebugString(ref->target()) << "\n"; } atom = followOnNexts[atom]; } while (atom != start); @@ -324,7 +323,9 @@ _followOnNexts.resize(range.size()); for (const DefinedAtom *ai : range) { for (const Reference *r : *ai) { - if (r->kind() != lld::Reference::kindLayoutAfter) + if (r->kindNamespace() != lld::Reference::KindNamespace::all) + continue; + if (r->kindValue() != lld::Reference::kindLayoutAfter) continue; const DefinedAtom *targetAtom = dyn_cast(r->target()); _followOnNexts[ai] = targetAtom; @@ -385,7 +386,9 @@ // references so that we have only one table for (const DefinedAtom *ai : range) { for (const Reference *r : *ai) { - if (r->kind() == lld::Reference::kindInGroup) { + if (r->kindNamespace() != lld::Reference::KindNamespace::all) + continue; + if (r->kindValue() == lld::Reference::kindInGroup) { const DefinedAtom *rootAtom = dyn_cast(r->target()); // If the root atom is not part of any root // create a new root @@ -455,7 +458,9 @@ // references so that we have only one table for (const DefinedAtom *ai : range) { for (const Reference *r : *ai) { - if (r->kind() == lld::Reference::kindLayoutBefore) { + if (r->kindNamespace() != lld::Reference::KindNamespace::all) + continue; + if (r->kindValue() == lld::Reference::kindLayoutBefore) { const DefinedAtom *targetAtom = dyn_cast(r->target()); // Is the targetAtom not chained if (_followOnRoots.count(targetAtom) == 0) { Index: lib/Passes/RoundTripNativePass.cpp =================================================================== --- lib/Passes/RoundTripNativePass.cpp +++ lib/Passes/RoundTripNativePass.cpp @@ -40,9 +40,12 @@ return; std::unique_ptr mb(buff.take()); - _context.getNativeReader().parseFile(mb, _nativeFile); - - mergedFile.reset(new FileToMutable(_context, *_nativeFile[0].get())); + error_code ec = _context.registry().parseFile(mb, _nativeFile); + assert(!ec && "native reader not registered"); + File *objFile = _nativeFile[0].get(); + const File *obj = dyn_cast(objFile); + assert(obj && "yaml generated file is not an relocatable file"); + mergedFile.reset(new FileToMutable(_context, *obj)); llvm::sys::fs::remove(tmpNativeFile.str()); } Index: lib/Passes/RoundTripYAMLPass.cpp =================================================================== --- lib/Passes/RoundTripYAMLPass.cpp +++ lib/Passes/RoundTripYAMLPass.cpp @@ -45,8 +45,12 @@ if (buff->getBufferSize() < MAX_YAML_FILE_SIZE) { std::unique_ptr mb(buff.take()); - _context.getYAMLReader().parseFile(mb, _yamlFile); - mergedFile.reset(new FileToMutable(_context, *_yamlFile[0].get())); + error_code ec = _context.registry().parseFile(mb, _yamlFile); + assert(!ec && "yaml reader not registered"); + File *objFile = _yamlFile[0].get(); + const File *obj = dyn_cast(objFile); + assert(obj && "yaml generated file is not an relocatable file"); + mergedFile.reset(new FileToMutable(_context, *obj)); } llvm::sys::fs::remove(tmpYAMLFile.str()); Index: lib/Passes/StubsPass.cpp =================================================================== --- lib/Passes/StubsPass.cpp +++ lib/Passes/StubsPass.cpp @@ -32,7 +32,7 @@ for (const DefinedAtom *atom : mergedFile->defined()) { for (const Reference *ref : *atom) { // Look at call-sites. - if (!this->isCallSite(ref->kind())) + if (!this->isCallSite(*ref)) continue; const Atom *target = ref->target(); assert(target != nullptr); Index: lib/ReaderWriter/CMakeLists.txt =================================================================== --- lib/ReaderWriter/CMakeLists.txt +++ lib/ReaderWriter/CMakeLists.txt @@ -11,6 +11,7 @@ LinkerScript.cpp Reader.cpp Writer.cpp + FileArchive.cpp ) target_link_libraries(lldReaderWriter Index: lib/ReaderWriter/CoreLinkingContext.cpp =================================================================== --- lib/ReaderWriter/CoreLinkingContext.cpp +++ lib/ReaderWriter/CoreLinkingContext.cpp @@ -12,7 +12,6 @@ #include "lld/Core/Pass.h" #include "lld/Core/PassManager.h" #include "lld/Passes/LayoutPass.h" -#include "lld/Passes/RoundTripNativePass.h" #include "lld/Passes/RoundTripYAMLPass.h" #include "lld/ReaderWriter/Simple.h" @@ -155,7 +154,7 @@ class TestingPassFile : public SimpleFile { public: TestingPassFile(const LinkingContext &ctx) - : SimpleFile(ctx, "Testing pass") {} + : SimpleFile("Testing pass") {} virtual void addAtom(const Atom &atom) { if (const DefinedAtom *defAtom = dyn_cast(&atom)) @@ -189,25 +188,6 @@ atom_collection_vector _absoluteAtoms; }; -struct TestingKindMapping { - const char *string; - int32_t value; - bool isBranch; - bool isGotLoad; - bool isGotUse; -}; - -// -// Table of fixup kinds in YAML documents used for testing -// -const TestingKindMapping sKinds[] = { - { "in-group", -3, false, false, false }, - { "layout-after", -2, false, false, false }, - { "layout-before", -1, false, false, false }, - { "call32", 2, true, false, false }, { "pcrel32", 3, false, false, false }, - { "gotLoad32", 7, false, true, true }, { "gotUse32", 9, false, false, true }, - { "lea32wasGot", 8, false, false, false }, { nullptr, 0, false, false, false } -}; class TestingStubsPass : public StubsPass { public: @@ -215,12 +195,10 @@ virtual bool noTextRelocs() { return true; } - virtual bool isCallSite(int32_t kind) { - for (const TestingKindMapping *p = sKinds; p->string != nullptr; ++p) { - if (kind == p->value) - return p->isBranch; - } - return false; + virtual bool isCallSite(const Reference &ref) { + if (ref.kindNamespace() != Reference::KindNamespace::testing) + return false; + return (ref.kindValue() == CoreLinkingContext::TEST_RELOC_CALL32); } virtual const DefinedAtom *getStub(const Atom &target) { @@ -245,22 +223,25 @@ virtual bool noTextRelocs() { return true; } - virtual bool isGOTAccess(int32_t kind, bool &canBypassGOT) { - for (const TestingKindMapping *p = sKinds; p->string != nullptr; ++p) { - if (kind == p->value) { - canBypassGOT = p->isGotLoad; - return p->isGotUse || p->isGotLoad; - } + virtual bool isGOTAccess(const Reference &ref, bool &canBypassGOT) { + if (ref.kindNamespace() != Reference::KindNamespace::testing) + return false; + switch (ref.kindValue()) { + case CoreLinkingContext::TEST_RELOC_GOT_LOAD32: + canBypassGOT = true; + return true; + case CoreLinkingContext::TEST_RELOC_GOT_USE32: + canBypassGOT = false; + return true; } return false; } virtual void updateReferenceToGOT(const Reference *ref, bool targetIsNowGOT) { - if (targetIsNowGOT) - const_cast(ref)->setKind(3); // pcrel32 - else - const_cast(ref)->setKind(8); // lea32wasGot - } + const_cast(ref)->setKindValue(targetIsNowGOT ? + CoreLinkingContext::TEST_RELOC_PCREL32 : + CoreLinkingContext::TEST_RELOC_LEA32_WAS_GOT); + } virtual const DefinedAtom *makeGOTEntry(const Atom &target) { return new TestingGOTAtom(_file, target); @@ -275,7 +256,6 @@ CoreLinkingContext::CoreLinkingContext() {} bool CoreLinkingContext::validateImpl(raw_ostream &) { - _reader = createReaderYAML(*this); _writer = createWriterYAML(*this); return true; } @@ -295,20 +275,3 @@ Writer &CoreLinkingContext::writer() const { return *_writer; } -ErrorOr -CoreLinkingContext::relocKindFromString(StringRef str) const { - for (const TestingKindMapping *p = sKinds; p->string != nullptr; ++p) { - if (str.equals(p->string)) - return p->value; - } - return make_error_code(YamlReaderError::illegal_value); -} - -ErrorOr -CoreLinkingContext::stringFromRelocKind(Reference::Kind kind) const { - for (const TestingKindMapping *p = sKinds; p->string != nullptr; ++p) { - if (kind == p->value) - return std::string(p->string); - } - return make_error_code(YamlReaderError::illegal_value); -} Index: lib/ReaderWriter/ELF/Atoms.h =================================================================== --- lib/ReaderWriter/ELF/Atoms.h +++ lib/ReaderWriter/ELF/Atoms.h @@ -41,21 +41,25 @@ typedef llvm::object::Elf_Rel_Impl Elf_Rela; public: - ELFReference(const Elf_Rela *rela, uint64_t off, Kind kind, uint32_t idx) - : _target(nullptr), _targetSymbolIndex(idx), + ELFReference(const Elf_Rela *rela, uint64_t off, Reference::KindArch arch, + uint16_t relocType, uint32_t idx) + : Reference(Reference::KindNamespace::ELF, arch, relocType), + _target(nullptr), _targetSymbolIndex(idx), _offsetInAtom(off), _addend(rela->r_addend) { - _kind = kind; } - ELFReference(const Elf_Rel *rel, uint64_t off, Kind kind, uint32_t idx) - : _target(nullptr), _targetSymbolIndex(idx), + ELFReference(const Elf_Rel *rel, uint64_t off, Reference::KindArch arch, + uint16_t relocType, uint32_t idx) + : Reference(Reference::KindNamespace::ELF, arch, relocType), + _target(nullptr), _targetSymbolIndex(idx), _offsetInAtom(off), _addend(0) { - _kind = kind; } - ELFReference(Kind kind) - : _target(nullptr), _targetSymbolIndex(0), _offsetInAtom(0), _addend(0) { - _kind = kind; + ELFReference(uint32_t edgeKind) + : Reference(Reference::KindNamespace::all, + Reference::KindArch::all, edgeKind), + _target(nullptr), _targetSymbolIndex(0), + _offsetInAtom(0), _addend(0) { } virtual uint64_t offsetInAtom() const { return _offsetInAtom; } @@ -186,8 +190,12 @@ , _referenceList(referenceList) , _targetAtomHandler(nullptr) , _contentType(typeUnknown) - , _permissions(permUnknown) {} + , _permissions(permUnknown) { + } + ~ELFDefinedAtom() { + } + virtual const ELFFile &file() const { return _owningFile; } @@ -211,11 +219,8 @@ // Treat target defined common symbols if ((_symbol->st_shndx > llvm::ELF::SHN_LOPROC && _symbol->st_shndx < llvm::ELF::SHN_HIPROC)) { - if (!_targetAtomHandler) { - const ELFLinkingContext &eti = (_owningFile.getLinkingContext()); - TargetHandler &TargetHandler = eti.getTargetHandler(); - _targetAtomHandler = &TargetHandler.targetAtomHandler(); - } + if (!_targetAtomHandler) + _targetAtomHandler = &_owningFile.targetHandler()->targetAtomHandler(); if (_targetAtomHandler->getType(_symbol) == llvm::ELF::STT_COMMON) return (uint64_t) _symbol->st_size; } @@ -250,11 +255,8 @@ // mergeTentative if ((_symbol->st_shndx > llvm::ELF::SHN_LOPROC && _symbol->st_shndx < llvm::ELF::SHN_HIPROC)) { - if (!_targetAtomHandler) { - const ELFLinkingContext &eti = (_owningFile.getLinkingContext()); - TargetHandler &TargetHandler = eti.getTargetHandler(); - _targetAtomHandler = &TargetHandler.targetAtomHandler(); - } + if (!_targetAtomHandler) + _targetAtomHandler = &_owningFile.targetHandler()->targetAtomHandler(); if (_targetAtomHandler->getType(_symbol) == llvm::ELF::STT_COMMON) return mergeAsTentative; } @@ -277,11 +279,8 @@ if ((_section->sh_flags & llvm::ELF::SHF_MASKPROC) || ((_symbol->st_shndx > llvm::ELF::SHN_LOPROC && _symbol->st_shndx < llvm::ELF::SHN_HIPROC))) { - if (!_targetAtomHandler) { - const ELFLinkingContext &eti = (_owningFile.getLinkingContext()); - TargetHandler &TargetHandler = eti.getTargetHandler(); - _targetAtomHandler = &TargetHandler.targetAtomHandler(); - } + if (!_targetAtomHandler) + _targetAtomHandler = &_owningFile.targetHandler()->targetAtomHandler(); return _contentType = _targetAtomHandler->contentType(this); } @@ -361,11 +360,8 @@ // Treat target defined common symbols if ((_symbol->st_shndx > llvm::ELF::SHN_LOPROC && _symbol->st_shndx < llvm::ELF::SHN_HIPROC)) { - if (!_targetAtomHandler) { - const ELFLinkingContext &eti = (_owningFile.getLinkingContext()); - TargetHandler &TargetHandler = eti.getTargetHandler(); - _targetAtomHandler = &TargetHandler.targetAtomHandler(); - } + if (!_targetAtomHandler) + _targetAtomHandler = &_owningFile.targetHandler()->targetAtomHandler(); if (_targetAtomHandler->getType(_symbol) == llvm::ELF::STT_COMMON) return Alignment(llvm::Log2_64(_symbol->st_value)); } @@ -422,11 +418,8 @@ // Treat target defined symbols if ((_symbol->st_shndx > llvm::ELF::SHN_LOPROC && _symbol->st_shndx < llvm::ELF::SHN_HIPROC)) { - if (!_targetAtomHandler) { - const ELFLinkingContext &eti = (_owningFile.getLinkingContext()); - TargetHandler &TargetHandler = eti.getTargetHandler(); - _targetAtomHandler = &TargetHandler.targetAtomHandler(); - } + if (!_targetAtomHandler) + _targetAtomHandler = &_owningFile.targetHandler()->targetAtomHandler(); return _permissions = _targetAtomHandler->contentPermissions(this); } @@ -671,8 +664,8 @@ virtual ContentType contentType() const { if (_symbol->st_shndx >= llvm::ELF::SHN_LORESERVE && _symbol->st_shndx <= llvm::ELF::SHN_HIOS) - return _owningFile.getLinkingContext().template getTargetHandler(). - targetAtomHandler().contentType(nullptr, _symbol); + return _owningFile.targetHandler()->targetAtomHandler(). + contentType(nullptr, _symbol); return typeZeroFill; } @@ -795,11 +788,46 @@ const Elf_Sym *_symbol; }; + +class SimpleELFDefinedAtom : public SimpleDefinedAtom { +public: + SimpleELFDefinedAtom(const File &f) : SimpleDefinedAtom(f) { } + + void addReferenceELF(Reference::KindArch arch, + uint16_t kindValue, uint64_t off, const Atom *target, + Reference::Addend addend) { + this->addReference(Reference::KindNamespace::ELF, arch, kindValue, + off, target, addend); + } + + void addReferenceELF_Hexeagon(uint16_t relocType, uint64_t off, const Atom *t, + Reference::Addend a) { + this->addReferenceELF(Reference::KindArch::Hexagon, relocType, off, t, a); + } + + void addReferenceELF_x86_64(uint16_t relocType, uint64_t off, const Atom *t, + Reference::Addend a) { + this->addReferenceELF(Reference::KindArch::x86_64, relocType, off, t, a); + } + + void addReferenceELF_PowerPC(uint16_t relocType, uint64_t off, const Atom *t, + Reference::Addend a) { + this->addReferenceELF(Reference::KindArch::PowerPC, relocType, off, t, a); + } + + void addReferenceELF_Mips(uint16_t relocType, uint64_t off, const Atom *t, + Reference::Addend a) { + this->addReferenceELF(Reference::KindArch::Mips, relocType, off, t, a); + } +}; + + + /// \brief Atom which represents an object for which a COPY relocation will be /// generated. -class ObjectAtom : public SimpleDefinedAtom { +class ObjectAtom : public SimpleELFDefinedAtom { public: - ObjectAtom(const File &f) : SimpleDefinedAtom(f) {} + ObjectAtom(const File &f) : SimpleELFDefinedAtom(f) {} virtual Scope scope() const { return scopeGlobal; } @@ -828,12 +856,12 @@ uint64_t _size; }; -class GOTAtom : public SimpleDefinedAtom { +class GOTAtom : public SimpleELFDefinedAtom { StringRef _section; public: GOTAtom(const File &f, StringRef secName) - : SimpleDefinedAtom(f), _section(secName) { + : SimpleELFDefinedAtom(f), _section(secName) { } virtual Scope scope() const { return scopeTranslationUnit; } @@ -864,12 +892,12 @@ #endif }; -class PLTAtom : public SimpleDefinedAtom { +class PLTAtom : public SimpleELFDefinedAtom { StringRef _section; public: PLTAtom(const File &f, StringRef secName) - : SimpleDefinedAtom(f), _section(secName) { + : SimpleELFDefinedAtom(f), _section(secName) { } virtual Scope scope() const { return scopeTranslationUnit; } @@ -909,9 +937,9 @@ } }; -class GLOBAL_OFFSET_TABLEAtom : public SimpleDefinedAtom { +class GLOBAL_OFFSET_TABLEAtom : public SimpleELFDefinedAtom { public: - GLOBAL_OFFSET_TABLEAtom(const File &f) : SimpleDefinedAtom(f) {} + GLOBAL_OFFSET_TABLEAtom(const File &f) : SimpleELFDefinedAtom(f) {} virtual StringRef name() const { return "_GLOBAL_OFFSET_TABLE_"; } @@ -937,9 +965,9 @@ } }; -class TLSGETADDRAtom : public SimpleDefinedAtom { +class TLSGETADDRAtom : public SimpleELFDefinedAtom { public: - TLSGETADDRAtom(const File &f) : SimpleDefinedAtom(f) {} + TLSGETADDRAtom(const File &f) : SimpleELFDefinedAtom(f) {} virtual StringRef name() const { return "__tls_get_addr"; } @@ -962,9 +990,9 @@ virtual ArrayRef rawContent() const { return ArrayRef(); } }; -class DYNAMICAtom : public SimpleDefinedAtom { +class DYNAMICAtom : public SimpleELFDefinedAtom { public: - DYNAMICAtom(const File &f) : SimpleDefinedAtom(f) {} + DYNAMICAtom(const File &f) : SimpleELFDefinedAtom(f) {} virtual StringRef name() const { return "_DYNAMIC"; } @@ -987,12 +1015,12 @@ virtual ArrayRef rawContent() const { return ArrayRef(); } }; -class InitFiniAtom : public SimpleDefinedAtom { +class InitFiniAtom : public SimpleELFDefinedAtom { StringRef _section; public: InitFiniAtom(const File &f, StringRef secName) - : SimpleDefinedAtom(f), _section(secName) { + : SimpleELFDefinedAtom(f), _section(secName) { } virtual Scope scope() const { return scopeGlobal; } Index: lib/ReaderWriter/ELF/DefaultLayout.h =================================================================== --- lib/ReaderWriter/ELF/DefaultLayout.h +++ lib/ReaderWriter/ELF/DefaultLayout.h @@ -331,7 +331,7 @@ switch (contentType) { case DefinedAtom::typeResolver: case DefinedAtom::typeCode: - return llvm::StringSwitch(name) + return llvm::StringSwitch(name) .StartsWith(".eh_frame_hdr", ORDER_EH_FRAMEHDR) .StartsWith(".eh_frame", ORDER_EH_FRAME) .StartsWith(".init", ORDER_INIT) @@ -344,7 +344,7 @@ case DefinedAtom::typeData: case DefinedAtom::typeDataFast: - return llvm::StringSwitch(name) + return llvm::StringSwitch(name) .StartsWith(".init_array", ORDER_INIT_ARRAY) .StartsWith(".fini_array", ORDER_FINI_ARRAY) .Default(ORDER_DATA); @@ -354,7 +354,7 @@ return ORDER_BSS; case DefinedAtom::typeGOT: - return llvm::StringSwitch(name) + return llvm::StringSwitch(name) .StartsWith(".got.plt", ORDER_GOT_PLT) .Default(ORDER_GOT); Index: lib/ReaderWriter/ELF/DynamicFile.h =================================================================== --- lib/ReaderWriter/ELF/DynamicFile.h +++ lib/ReaderWriter/ELF/DynamicFile.h @@ -25,11 +25,9 @@ template class DynamicFile LLVM_FINAL : public SharedLibraryFile { public: static ErrorOr > - create(const ELFLinkingContext &ctx, std::unique_ptr mb) { + create(std::unique_ptr mb, bool useShlibUndefines) { std::unique_ptr file( - new DynamicFile(ctx, mb->getBufferIdentifier())); - - bool useShlibUndefines = ctx.useShlibUndefines(); + new DynamicFile(mb->getBufferIdentifier())); error_code ec; file->_objFile.reset(new llvm::object::ELFFile(mb.release(), ec)); @@ -105,16 +103,11 @@ *this, name, _soname, sym->second._symbol); } - virtual const ELFLinkingContext &getLinkingContext() const { - return _context; - } - private: - DynamicFile(const ELFLinkingContext &context, StringRef name) - : SharedLibraryFile(name), _context(context) {} + DynamicFile(StringRef name) + : SharedLibraryFile(name) {} mutable llvm::BumpPtrAllocator _alloc; - const ELFLinkingContext &_context; std::unique_ptr> _objFile; atom_collection_vector _definedAtoms; atom_collection_vector _undefinedAtoms; Index: lib/ReaderWriter/ELF/ELFLinkingContext.cpp =================================================================== --- lib/ReaderWriter/ELF/ELFLinkingContext.cpp +++ lib/ReaderWriter/ELF/ELFLinkingContext.cpp @@ -16,7 +16,6 @@ #include "lld/Core/Instrumentation.h" #include "lld/Passes/LayoutPass.h" -#include "lld/Passes/RoundTripNativePass.h" #include "lld/Passes/RoundTripYAMLPass.h" #include "llvm/ADT/Triple.h" @@ -36,8 +35,8 @@ } }; -ELFLinkingContext::ELFLinkingContext( - llvm::Triple triple, std::unique_ptr targetHandler) +ELFLinkingContext::ELFLinkingContext(llvm::Triple triple, + std::unique_ptr targetHandler) : _outputELFType(elf::ET_EXEC), _triple(triple), _targetHandler(std::move(targetHandler)), _baseAddress(0), _isStaticExecutable(false), _noInhibitExec(false), @@ -83,7 +82,6 @@ } bool ELFLinkingContext::validateImpl(raw_ostream &diagnostics) { - _elfReader = createReaderELF(*this); switch (outputFileType()) { case LinkingContext::OutputFileType::YAML: _writer = createWriterYAML(*this); @@ -185,7 +183,7 @@ if (_initialUndefinedSymbols.empty()) return nullptr; std::unique_ptr undefinedSymFile( - new SimpleFile(*this, "command line option -u")); + new SimpleFile("command line option -u")); for (auto undefSymStr : _initialUndefinedSymbols) undefinedSymFile->addAtom(*(new (_allocator) CommandLineUndefinedAtom( *undefinedSymFile, undefSymStr))); Index: lib/ReaderWriter/ELF/File.h =================================================================== --- lib/ReaderWriter/ELF/File.h +++ lib/ReaderWriter/ELF/File.h @@ -14,8 +14,8 @@ #include "lld/Core/File.h" #include "lld/Core/Reference.h" + #include "lld/ReaderWriter/ELFLinkingContext.h" -#include "lld/ReaderWriter/FileArchive.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SmallString.h" @@ -118,48 +118,67 @@ typedef typename MergedSectionMapT::iterator MergedSectionMapIterT; public: - ELFFile(const ELFLinkingContext &context, StringRef name) - : File(name, kindObject), _elfLinkingContext(context) {} - - ELFFile(const ELFLinkingContext &context, - std::unique_ptr MB, error_code &EC) - : File(MB->getBufferIdentifier(), kindObject), - _elfLinkingContext(context), _ordinal(0), _doStringsMerge(false) { - _objFile.reset(new llvm::object::ELFFile(MB.release(), EC)); + ELFFile(StringRef name) + : File(name, kindObject), _ordinal(0), + _doStringsMerge(false), _targetHandler(nullptr) {} + + ELFFile(std::unique_ptr mb, bool atomizeStrings, + TargetHandlerBase *handler, error_code &ec) + : File(mb->getBufferIdentifier(), kindObject), + _ordinal(0), _doStringsMerge(atomizeStrings), + _targetHandler(reinterpret_cast*>(handler)) { + _objFile.reset(new llvm::object::ELFFile(mb.release(), ec)); - if (EC) + if (ec) return; - _doStringsMerge = _elfLinkingContext.mergeCommonStrings(); - // Read input sections from the input file that need to be converted to // atoms if (auto err = createAtomizableSections()) { - EC = err; + ec = err; return; } // For mergeable strings, we would need to split the section into various // atoms if (auto err = createMergeableAtoms()) { - EC = err; + ec = err; return; } // Create the necessary symbols that are part of the section that we // created in createAtomizableSections function if (auto err = createSymbolsFromAtomizableSections()) { - EC = err; + ec = err; return; } // Create the appropriate atoms from the file if (auto err = createAtoms()) { - EC = err; + ec = err; return; } } + Reference::KindArch kindArch() { + switch (_objFile->getHeader()->e_machine) { + case llvm::ELF::EM_X86_64: + return Reference::KindArch::x86_64; + case llvm::ELF::EM_386: + return Reference::KindArch::x86; + case llvm::ELF::EM_ARM: + return Reference::KindArch::ARM; + case llvm::ELF::EM_PPC: + return Reference::KindArch::PowerPC; + case llvm::ELF::EM_HEXAGON: + return Reference::KindArch::Hexagon; + case llvm::ELF::EM_MIPS: + return Reference::KindArch::Mips; + } + llvm_unreachable("unsupported e_machine value"); + } + + /// \brief Read input sections and populate necessary data structures /// to read them later and create atoms error_code createAtomizableSections() { @@ -446,7 +465,7 @@ // If the atom was a weak symbol, let's create a followon reference to // the anonymous atom that we created. if (anonAtom) - createEdge(newAtom, anonAtom, lld::Reference::kindLayoutAfter); + createEdge(newAtom, anonAtom, Reference::kindLayoutAfter); if (previousAtom) { // Set the followon atom to the weak atom that we have created, so @@ -491,8 +510,8 @@ return _absoluteAtoms; } - virtual const ELFLinkingContext &getLinkingContext() const { - return _elfLinkingContext; + TargetHandler *targetHandler() const { + return _targetHandler; } Atom *findAtom(const Elf_Sym *symbol) { @@ -516,11 +535,10 @@ symbol->st_value + content.size() <= rai.r_offset) continue; bool isMips64EL = _objFile->isMips64EL(); - Reference::Kind kind = (Reference::Kind) rai.getType(isMips64EL); uint32_t symbolIndex = rai.getSymbol(isMips64EL); auto *ERef = new (_readerStorage) ELFReference(&rai, rai.r_offset - symbol->st_value, - kind, symbolIndex); + kindArch(), rai.getType(isMips64EL), symbolIndex); _references.push_back(ERef); } } @@ -533,11 +551,10 @@ symbol->st_value + content.size() <= ri.r_offset) continue; bool isMips64EL = _objFile->isMips64EL(); - Reference::Kind kind = (Reference::Kind) ri.getType(isMips64EL); uint32_t symbolIndex = ri.getSymbol(isMips64EL); auto *ERef = new (_readerStorage) ELFReference(&ri, ri.r_offset - symbol->st_value, - kind, symbolIndex); + kindArch(), ri.getType(isMips64EL), symbolIndex); // Read the addend from the section contents // TODO : We should move the way lld reads relocations totally from // ELFFile @@ -557,12 +574,12 @@ /// Reference's target with the Atom pointer it refers to. void updateReferences() { /// cached value of target relocation handler - const TargetRelocationHandler &_targetRelocationHandler = - _elfLinkingContext.template getTargetHandler() - .getRelocationHandler(); + assert(_targetHandler); + const TargetRelocationHandler &targetRelocationHandler = + _targetHandler->getRelocationHandler(); for (auto &ri : _references) { - if (ri->kind() >= lld::Reference::kindTargetLow) { + if (ri->kindNamespace() == lld::Reference::KindNamespace::ELF) { const Elf_Sym *symbol = _objFile->getSymbol(ri->targetSymbolIndex()); const Elf_Shdr *shdr = _objFile->getSection(symbol); @@ -576,7 +593,7 @@ // If the target atom is mergeable string atom, the atom might have been // merged with other atom having the same contents. Try to find the // merged one if that's the case. - int64_t relocAddend = _targetRelocationHandler.relocAddend(*ri); + int64_t relocAddend = targetRelocationHandler.relocAddend(*ri); uint64_t addend = ri->addend() + relocAddend; const MergeSectionKey ms(shdr, addend); auto msec = _mergedSectionMap.find(ms); @@ -671,11 +688,9 @@ // whether an architecture dependent section is for common symbols or // not. Let the TargetHandler to make a decision if that's the case. if (isTargetSpecificAtom(nullptr, symbol)) { - TargetHandler &targetHandler = - _elfLinkingContext.template getTargetHandler(); - TargetAtomHandler &targetAtomHandler = - targetHandler.targetAtomHandler(); - return targetAtomHandler.getType(symbol) == llvm::ELF::STT_COMMON; + assert(_targetHandler); + TargetAtomHandler &atomHandler = _targetHandler->targetAtomHandler(); + return atomHandler.getType(symbol) == llvm::ELF::STT_COMMON; } return symbol->getType() == llvm::ELF::STT_COMMON || symbol->st_shndx == llvm::ELF::SHN_COMMON; @@ -692,8 +707,8 @@ } void createEdge(ELFDefinedAtom *from, ELFDefinedAtom *to, - lld::Reference::Kind kind) { - auto reference = new (_readerStorage) ELFReference(kind); + uint32_t edgeKind) { + auto reference = new (_readerStorage) ELFReference(edgeKind); reference->setTarget(to); from->addReference(reference); } @@ -721,7 +736,6 @@ _relocationReferences; std::vector *> _references; llvm::DenseMap _symbolToAtomMapping; - const ELFLinkingContext &_elfLinkingContext; /// \brief Atoms that are created for a section that has the merge property /// set @@ -738,6 +752,7 @@ /// \brief the cached options relevant while reading the ELF File bool _doStringsMerge; + TargetHandler *_targetHandler; }; /// \brief All atoms are owned by a File. To add linker specific atoms @@ -749,7 +764,7 @@ public: typedef llvm::object::Elf_Sym_Impl Elf_Sym; CRuntimeFile(const ELFLinkingContext &context, StringRef name = "C runtime") - : ELFFile(context, name) {} + : ELFFile(name) {} /// \brief add a global absolute atom virtual Atom *addAbsoluteAtom(StringRef symbolName) { Index: lib/ReaderWriter/ELF/Hexagon/HexagonLinkingContext.h =================================================================== --- lib/ReaderWriter/ELF/Hexagon/HexagonLinkingContext.h +++ lib/ReaderWriter/ELF/Hexagon/HexagonLinkingContext.h @@ -26,14 +26,13 @@ : ELFLinkingContext(triple, std::unique_ptr( new HexagonTargetHandler(*this))) {} - virtual ErrorOr relocKindFromString(StringRef str) const; - virtual ErrorOr stringFromRelocKind(Reference::Kind kind) const; - virtual void addPasses(PassManager &); virtual bool isDynamicRelocation(const DefinedAtom &, const Reference &r) const { - switch (r.kind()) { + if (r.kindNamespace() != Reference::KindNamespace::ELF) + return false; + switch (r.kindValue()) { case llvm::ELF::R_HEX_RELATIVE: case llvm::ELF::R_HEX_GLOB_DAT: return true; @@ -43,7 +42,9 @@ } virtual bool isPLTRelocation(const DefinedAtom &, const Reference &r) const { - switch (r.kind()) { + if (r.kindNamespace() != Reference::KindNamespace::ELF) + return false; + switch (r.kindValue()) { case llvm::ELF::R_HEX_JMP_SLOT: return true; default: @@ -54,7 +55,9 @@ /// \brief Hexagon has only one relative relocation /// a) for supporting relative relocs - R_HEX_RELATIVE virtual bool isRelativeReloc(const Reference &r) const { - switch (r.kind()) { + if (r.kindNamespace() != Reference::KindNamespace::ELF) + return false; + switch (r.kindValue()) { case llvm::ELF::R_HEX_RELATIVE: return true; default: Index: lib/ReaderWriter/ELF/Hexagon/HexagonLinkingContext.cpp =================================================================== --- lib/ReaderWriter/ELF/Hexagon/HexagonLinkingContext.cpp +++ lib/ReaderWriter/ELF/Hexagon/HexagonLinkingContext.cpp @@ -22,8 +22,6 @@ using namespace lld; using namespace lld::elf; -#define LLD_CASE(name) .Case(#name, llvm::ELF::name) - namespace { const uint8_t hexagonInitFiniAtomContent[4] = { 0 }; @@ -63,15 +61,15 @@ class HexagonInitFiniFile : public SimpleFile { public: HexagonInitFiniFile(const ELFLinkingContext &context) - : SimpleFile(context, "command line option -init/-fini"), _ordinal(0) {} + : SimpleFile("command line option -init/-fini"), _ordinal(0) {} void addInitFunction(StringRef name) { - Atom *initFunctionAtom = new (_allocator) SimpleUndefinedAtom(*this, name); + Atom *initFuncAtom = new (_allocator) SimpleUndefinedAtom(*this, name); HexagonInitAtom *initAtom = (new (_allocator) HexagonInitAtom(*this, name)); - initAtom->addReference(llvm::ELF::R_HEX_32, 0, initFunctionAtom, 0); + initAtom->addReferenceELF_Hexeagon(llvm::ELF::R_HEX_32, 0, initFuncAtom, 0); initAtom->setOrdinal(_ordinal++); - addAtom(*initFunctionAtom); + addAtom(*initFuncAtom); addAtom(*initAtom); } @@ -79,7 +77,7 @@ Atom *finiFunctionAtom = new (_allocator) SimpleUndefinedAtom(*this, name); HexagonFiniAtom *finiAtom = (new (_allocator) HexagonFiniAtom(*this, name)); - finiAtom->addReference(llvm::ELF::R_HEX_32, 0, finiFunctionAtom, 0); + finiAtom->addReferenceELF_Hexeagon(llvm::ELF::R_HEX_32, 0, finiFunctionAtom, 0); finiAtom->setOrdinal(_ordinal++); addAtom(*finiFunctionAtom); addAtom(*finiAtom); @@ -103,150 +101,3 @@ result.push_back(std::move(initFiniFile)); return true; } - -ErrorOr -elf::HexagonLinkingContext::relocKindFromString(StringRef str) const { - int32_t ret = llvm::StringSwitch(str) LLD_CASE(R_HEX_NONE) - LLD_CASE(R_HEX_B22_PCREL) LLD_CASE(R_HEX_B15_PCREL) - LLD_CASE(R_HEX_B7_PCREL) LLD_CASE(R_HEX_LO16) LLD_CASE(R_HEX_HI16) - LLD_CASE(R_HEX_32) LLD_CASE(R_HEX_16) LLD_CASE(R_HEX_8) - LLD_CASE(R_HEX_GPREL16_0) LLD_CASE(R_HEX_GPREL16_1) - LLD_CASE(R_HEX_GPREL16_2) LLD_CASE(R_HEX_GPREL16_3) LLD_CASE(R_HEX_HL16) - LLD_CASE(R_HEX_B13_PCREL) LLD_CASE(R_HEX_B9_PCREL) - LLD_CASE(R_HEX_B32_PCREL_X) LLD_CASE(R_HEX_32_6_X) - LLD_CASE(R_HEX_B22_PCREL_X) LLD_CASE(R_HEX_B15_PCREL_X) - LLD_CASE(R_HEX_B13_PCREL_X) LLD_CASE(R_HEX_B9_PCREL_X) - LLD_CASE(R_HEX_B7_PCREL_X) LLD_CASE(R_HEX_16_X) LLD_CASE(R_HEX_12_X) - LLD_CASE(R_HEX_11_X) LLD_CASE(R_HEX_10_X) LLD_CASE(R_HEX_9_X) - LLD_CASE(R_HEX_8_X) LLD_CASE(R_HEX_7_X) LLD_CASE(R_HEX_6_X) - LLD_CASE(R_HEX_32_PCREL) LLD_CASE(R_HEX_COPY) LLD_CASE(R_HEX_GLOB_DAT) - LLD_CASE(R_HEX_JMP_SLOT) LLD_CASE(R_HEX_RELATIVE) - LLD_CASE(R_HEX_PLT_B22_PCREL) LLD_CASE(R_HEX_GOTREL_LO16) - LLD_CASE(R_HEX_GOTREL_HI16) LLD_CASE(R_HEX_GOTREL_32) - LLD_CASE(R_HEX_GOT_LO16) LLD_CASE(R_HEX_GOT_HI16) LLD_CASE(R_HEX_GOT_32) - LLD_CASE(R_HEX_GOT_16) LLD_CASE(R_HEX_DTPMOD_32) - LLD_CASE(R_HEX_DTPREL_LO16) LLD_CASE(R_HEX_DTPREL_HI16) - LLD_CASE(R_HEX_DTPREL_32) LLD_CASE(R_HEX_DTPREL_16) - LLD_CASE(R_HEX_GD_PLT_B22_PCREL) LLD_CASE(R_HEX_GD_GOT_LO16) - LLD_CASE(R_HEX_GD_GOT_HI16) LLD_CASE(R_HEX_GD_GOT_32) - LLD_CASE(R_HEX_GD_GOT_16) LLD_CASE(R_HEX_IE_LO16) LLD_CASE(R_HEX_IE_HI16) - LLD_CASE(R_HEX_IE_32) LLD_CASE(R_HEX_IE_GOT_LO16) - LLD_CASE(R_HEX_IE_GOT_HI16) LLD_CASE(R_HEX_IE_GOT_32) - LLD_CASE(R_HEX_IE_GOT_16) LLD_CASE(R_HEX_TPREL_LO16) - LLD_CASE(R_HEX_TPREL_HI16) LLD_CASE(R_HEX_TPREL_32) - LLD_CASE(R_HEX_TPREL_16) LLD_CASE(R_HEX_6_PCREL_X) - LLD_CASE(R_HEX_GOTREL_32_6_X) LLD_CASE(R_HEX_GOTREL_16_X) - LLD_CASE(R_HEX_GOTREL_11_X) LLD_CASE(R_HEX_GOT_32_6_X) - LLD_CASE(R_HEX_GOT_16_X) LLD_CASE(R_HEX_GOT_11_X) - LLD_CASE(R_HEX_DTPREL_32_6_X) LLD_CASE(R_HEX_DTPREL_16_X) - LLD_CASE(R_HEX_DTPREL_11_X) LLD_CASE(R_HEX_GD_GOT_32_6_X) - LLD_CASE(R_HEX_GD_GOT_16_X) LLD_CASE(R_HEX_GD_GOT_11_X) - LLD_CASE(R_HEX_IE_32_6_X) LLD_CASE(R_HEX_IE_16_X) - LLD_CASE(R_HEX_IE_GOT_32_6_X) LLD_CASE(R_HEX_IE_GOT_16_X) - LLD_CASE(R_HEX_IE_GOT_11_X) LLD_CASE(R_HEX_TPREL_32_6_X) - LLD_CASE(R_HEX_TPREL_16_X) LLD_CASE(R_HEX_TPREL_11_X).Default(-1); - - if (ret == -1) - return make_error_code(YamlReaderError::illegal_value); - return ret; -} - -#undef LLD_CASE - -#define LLD_CASE(name) \ - case llvm::ELF::name: \ - return std::string(#name); - -ErrorOr -elf::HexagonLinkingContext::stringFromRelocKind(int32_t kind) const { - switch (kind) { - LLD_CASE(R_HEX_NONE) - LLD_CASE(R_HEX_B22_PCREL) - LLD_CASE(R_HEX_B15_PCREL) - LLD_CASE(R_HEX_B7_PCREL) - LLD_CASE(R_HEX_LO16) - LLD_CASE(R_HEX_HI16) - LLD_CASE(R_HEX_32) - LLD_CASE(R_HEX_16) - LLD_CASE(R_HEX_8) - LLD_CASE(R_HEX_GPREL16_0) - LLD_CASE(R_HEX_GPREL16_1) - LLD_CASE(R_HEX_GPREL16_2) - LLD_CASE(R_HEX_GPREL16_3) - LLD_CASE(R_HEX_HL16) - LLD_CASE(R_HEX_B13_PCREL) - LLD_CASE(R_HEX_B9_PCREL) - LLD_CASE(R_HEX_B32_PCREL_X) - LLD_CASE(R_HEX_32_6_X) - LLD_CASE(R_HEX_B22_PCREL_X) - LLD_CASE(R_HEX_B15_PCREL_X) - LLD_CASE(R_HEX_B13_PCREL_X) - LLD_CASE(R_HEX_B9_PCREL_X) - LLD_CASE(R_HEX_B7_PCREL_X) - LLD_CASE(R_HEX_16_X) - LLD_CASE(R_HEX_12_X) - LLD_CASE(R_HEX_11_X) - LLD_CASE(R_HEX_10_X) - LLD_CASE(R_HEX_9_X) - LLD_CASE(R_HEX_8_X) - LLD_CASE(R_HEX_7_X) - LLD_CASE(R_HEX_6_X) - LLD_CASE(R_HEX_32_PCREL) - LLD_CASE(R_HEX_COPY) - LLD_CASE(R_HEX_GLOB_DAT) - LLD_CASE(R_HEX_JMP_SLOT) - LLD_CASE(R_HEX_RELATIVE) - LLD_CASE(R_HEX_PLT_B22_PCREL) - LLD_CASE(R_HEX_GOTREL_LO16) - LLD_CASE(R_HEX_GOTREL_HI16) - LLD_CASE(R_HEX_GOTREL_32) - LLD_CASE(R_HEX_GOT_LO16) - LLD_CASE(R_HEX_GOT_HI16) - LLD_CASE(R_HEX_GOT_32) - LLD_CASE(R_HEX_GOT_16) - LLD_CASE(R_HEX_DTPMOD_32) - LLD_CASE(R_HEX_DTPREL_LO16) - LLD_CASE(R_HEX_DTPREL_HI16) - LLD_CASE(R_HEX_DTPREL_32) - LLD_CASE(R_HEX_DTPREL_16) - LLD_CASE(R_HEX_GD_PLT_B22_PCREL) - LLD_CASE(R_HEX_GD_GOT_LO16) - LLD_CASE(R_HEX_GD_GOT_HI16) - LLD_CASE(R_HEX_GD_GOT_32) - LLD_CASE(R_HEX_GD_GOT_16) - LLD_CASE(R_HEX_IE_LO16) - LLD_CASE(R_HEX_IE_HI16) - LLD_CASE(R_HEX_IE_32) - LLD_CASE(R_HEX_IE_GOT_LO16) - LLD_CASE(R_HEX_IE_GOT_HI16) - LLD_CASE(R_HEX_IE_GOT_32) - LLD_CASE(R_HEX_IE_GOT_16) - LLD_CASE(R_HEX_TPREL_LO16) - LLD_CASE(R_HEX_TPREL_HI16) - LLD_CASE(R_HEX_TPREL_32) - LLD_CASE(R_HEX_TPREL_16) - LLD_CASE(R_HEX_6_PCREL_X) - LLD_CASE(R_HEX_GOTREL_32_6_X) - LLD_CASE(R_HEX_GOTREL_16_X) - LLD_CASE(R_HEX_GOTREL_11_X) - LLD_CASE(R_HEX_GOT_32_6_X) - LLD_CASE(R_HEX_GOT_16_X) - LLD_CASE(R_HEX_GOT_11_X) - LLD_CASE(R_HEX_DTPREL_32_6_X) - LLD_CASE(R_HEX_DTPREL_16_X) - LLD_CASE(R_HEX_DTPREL_11_X) - LLD_CASE(R_HEX_GD_GOT_32_6_X) - LLD_CASE(R_HEX_GD_GOT_16_X) - LLD_CASE(R_HEX_GD_GOT_11_X) - LLD_CASE(R_HEX_IE_32_6_X) - LLD_CASE(R_HEX_IE_16_X) - LLD_CASE(R_HEX_IE_GOT_32_6_X) - LLD_CASE(R_HEX_IE_GOT_16_X) - LLD_CASE(R_HEX_IE_GOT_11_X) - LLD_CASE(R_HEX_TPREL_32_6_X) - LLD_CASE(R_HEX_TPREL_16_X) - LLD_CASE(R_HEX_TPREL_11_X) - } - - return make_error_code(YamlReaderError::illegal_value); -} Index: lib/ReaderWriter/ELF/Hexagon/HexagonRelocationHandler.h =================================================================== --- lib/ReaderWriter/ELF/Hexagon/HexagonRelocationHandler.h +++ lib/ReaderWriter/ELF/Hexagon/HexagonRelocationHandler.h @@ -31,7 +31,8 @@ virtual error_code applyRelocation(ELFWriter &, llvm::FileOutputBuffer &, const lld::AtomLayout &, const Reference &) const; -private: + + private: const HexagonLinkingContext &_context; const HexagonTargetHandler &_targetHandler; const HexagonTargetLayout &_targetLayout; Index: lib/ReaderWriter/ELF/Hexagon/HexagonRelocationHandler.cpp =================================================================== --- lib/ReaderWriter/ELF/Hexagon/HexagonRelocationHandler.cpp +++ lib/ReaderWriter/ELF/Hexagon/HexagonRelocationHandler.cpp @@ -219,7 +219,10 @@ uint64_t targetVAddress = writer.addressOfAtom(ref.target()); uint64_t relocVAddress = atom._virtualAddr + ref.offsetInAtom(); - switch (ref.kind()) { + if (ref.kindNamespace() != Reference::KindNamespace::ELF) + return error_code::success(); + assert(ref.kindArch() == Reference::KindArch::Hexagon); + switch (ref.kindValue()) { case R_HEX_B22_PCREL: relocBNPCREL(location, relocVAddress, targetVAddress, ref.addend(), 21); break; @@ -334,16 +337,10 @@ _targetHandler.getGOTSymAddr()); break; - case lld::Reference::kindLayoutAfter: - case lld::Reference::kindLayoutBefore: - case lld::Reference::kindInGroup: - break; default : { std::string str; llvm::raw_string_ostream s(str); - auto name = _context.stringFromRelocKind(ref.kind()); - s << "Unhandled relocation: " << (name ? *name : "") << " (" - << ref.kind() << ")"; + s << "Unhandled Hexagon relocation: #" << ref.kindValue(); s.flush(); llvm_unreachable(str.c_str()); } @@ -351,3 +348,5 @@ return error_code::success(); } + + \ No newline at end of file Index: lib/ReaderWriter/ELF/Hexagon/HexagonTargetHandler.h =================================================================== --- lib/ReaderWriter/ELF/Hexagon/HexagonTargetHandler.h +++ lib/ReaderWriter/ELF/Hexagon/HexagonTargetHandler.h @@ -150,6 +150,8 @@ public: HexagonTargetHandler(HexagonLinkingContext &targetInfo); + virtual void registerRelocationNames(Registry ®istry); + bool doesOverrideELFHeader() { return true; } void setELFHeader(ELFHeader *elfHeader) { @@ -215,6 +217,8 @@ } private: + static const Registry::KindStrings kindStrings[]; + HexagonTargetLayout _targetLayout; HexagonTargetRelocationHandler _relocationHandler; HexagonTargetAtomHandler _targetAtomHandler; Index: lib/ReaderWriter/ELF/Hexagon/HexagonTargetHandler.cpp =================================================================== --- lib/ReaderWriter/ELF/Hexagon/HexagonTargetHandler.cpp +++ lib/ReaderWriter/ELF/Hexagon/HexagonTargetHandler.cpp @@ -108,7 +108,8 @@ class ELFPassFile : public SimpleFile { public: - ELFPassFile(const ELFLinkingContext &eti) : SimpleFile(eti, "ELFPassFile") { + ELFPassFile(const ELFLinkingContext &eti) + : SimpleFile("ELFPassFile") { setOrdinal(eti.getNextOrdinalAndIncrement()); } @@ -119,7 +120,10 @@ template class GOTPLTPass : public Pass { /// \brief Handle a specific reference. void handleReference(const DefinedAtom &atom, const Reference &ref) { - switch (ref.kind()) { + if (ref.kindNamespace() != Reference::KindNamespace::ELF) + return; + assert(ref.kindArch() == Reference::KindArch::Hexagon); + switch (ref.kindValue()) { case R_HEX_PLT_B22_PCREL: case R_HEX_B22_PCREL: static_cast(this)->handlePLT32(ref); @@ -226,8 +230,8 @@ if (_PLT0) return _PLT0; _PLT0 = new (_file._alloc) HexagonPLT0Atom(_file); - _PLT0->addReference(R_HEX_B32_PCREL_X, 0, _got0, 0); - _PLT0->addReference(R_HEX_6_PCREL_X, 4, _got0, 4); + _PLT0->addReferenceELF_Hexeagon(R_HEX_B32_PCREL_X, 0, _got0, 0); + _PLT0->addReferenceELF_Hexeagon(R_HEX_6_PCREL_X, 4, _got0, 4); DEBUG_WITH_TYPE("PLT", llvm::dbgs() << "[ PLT0/GOT0 ] " << "Adding plt0/got0 \n"); return _PLT0; @@ -238,13 +242,13 @@ if (plt != _pltMap.end()) return plt->second; auto ga = new (_file._alloc) HexagonGOTPLTAtom(_file); - ga->addReference(R_HEX_JMP_SLOT, 0, a, 0); + ga->addReferenceELF_Hexeagon(R_HEX_JMP_SLOT, 0, a, 0); auto pa = new (_file._alloc) HexagonPLTAtom(_file, ".plt"); - pa->addReference(R_HEX_B32_PCREL_X, 0, ga, 0); - pa->addReference(R_HEX_6_PCREL_X, 4, ga, 4); + pa->addReferenceELF_Hexeagon(R_HEX_B32_PCREL_X, 0, ga, 0); + pa->addReferenceELF_Hexeagon(R_HEX_6_PCREL_X, 4, ga, 4); // Point the got entry to the PLT0 atom initially - ga->addReference(R_HEX_32, 0, getPLT0(), 0); + ga->addReferenceELF_Hexeagon(R_HEX_32, 0, getPLT0(), 0); #ifndef NDEBUG ga->_name = "__got_"; ga->_name += a->name(); @@ -266,7 +270,7 @@ if (got != _gotMap.end()) return got->second; auto ga = new (_file._alloc) HexagonGOTAtom(_file); - ga->addReference(R_HEX_GLOB_DAT, 0, a, 0); + ga->addReferenceELF_Hexeagon(R_HEX_GLOB_DAT, 0, a, 0); #ifndef NDEBUG ga->_name = "__got_"; @@ -287,7 +291,9 @@ error_code handlePLT32(const Reference &ref) { // Turn this into a PC32 to the PLT entry. - const_cast(ref).setKind(R_HEX_B22_PCREL); + assert(ref.kindNamespace() == Reference::KindNamespace::ELF); + assert(ref.kindArch() == Reference::KindArch::Hexagon); + const_cast(ref).setKindValue(R_HEX_B22_PCREL); const_cast(ref).setTarget(getPLTEntry(ref.target())); return error_code::success(); } @@ -299,3 +305,106 @@ pm.add(std::unique_ptr(new DynamicGOTPLTPass(*this))); ELFLinkingContext::addPasses(pm); } + +void HexagonTargetHandler::registerRelocationNames(Registry ®istry) { + registry.addKindTable(Reference::KindNamespace::ELF, + Reference::KindArch::Hexagon, + kindStrings); +} + +const Registry::KindStrings HexagonTargetHandler::kindStrings[] = { + LLD_KIND_STRING_ENTRY(R_HEX_NONE), + LLD_KIND_STRING_ENTRY(R_HEX_B22_PCREL), + LLD_KIND_STRING_ENTRY(R_HEX_B15_PCREL), + LLD_KIND_STRING_ENTRY(R_HEX_B7_PCREL), + LLD_KIND_STRING_ENTRY(R_HEX_LO16), + LLD_KIND_STRING_ENTRY(R_HEX_HI16), + LLD_KIND_STRING_ENTRY(R_HEX_32), + LLD_KIND_STRING_ENTRY(R_HEX_16), + LLD_KIND_STRING_ENTRY(R_HEX_8), + LLD_KIND_STRING_ENTRY(R_HEX_GPREL16_0), + LLD_KIND_STRING_ENTRY(R_HEX_GPREL16_1), + LLD_KIND_STRING_ENTRY(R_HEX_GPREL16_2), + LLD_KIND_STRING_ENTRY(R_HEX_GPREL16_3), + LLD_KIND_STRING_ENTRY(R_HEX_HL16), + LLD_KIND_STRING_ENTRY(R_HEX_B13_PCREL), + LLD_KIND_STRING_ENTRY(R_HEX_B9_PCREL), + LLD_KIND_STRING_ENTRY(R_HEX_B32_PCREL_X), + LLD_KIND_STRING_ENTRY(R_HEX_32_6_X), + LLD_KIND_STRING_ENTRY(R_HEX_B22_PCREL_X), + LLD_KIND_STRING_ENTRY(R_HEX_B15_PCREL_X), + LLD_KIND_STRING_ENTRY(R_HEX_B13_PCREL_X), + LLD_KIND_STRING_ENTRY(R_HEX_B9_PCREL_X), + LLD_KIND_STRING_ENTRY(R_HEX_B7_PCREL_X), + LLD_KIND_STRING_ENTRY(R_HEX_16_X), + LLD_KIND_STRING_ENTRY(R_HEX_12_X), + LLD_KIND_STRING_ENTRY(R_HEX_11_X), + LLD_KIND_STRING_ENTRY(R_HEX_10_X), + LLD_KIND_STRING_ENTRY(R_HEX_9_X), + LLD_KIND_STRING_ENTRY(R_HEX_8_X), + LLD_KIND_STRING_ENTRY(R_HEX_7_X), + LLD_KIND_STRING_ENTRY(R_HEX_6_X), + LLD_KIND_STRING_ENTRY(R_HEX_32_PCREL), + LLD_KIND_STRING_ENTRY(R_HEX_COPY), + LLD_KIND_STRING_ENTRY(R_HEX_GLOB_DAT), + LLD_KIND_STRING_ENTRY(R_HEX_JMP_SLOT), + LLD_KIND_STRING_ENTRY(R_HEX_RELATIVE), + LLD_KIND_STRING_ENTRY(R_HEX_PLT_B22_PCREL), + LLD_KIND_STRING_ENTRY(R_HEX_GOTREL_LO16), + LLD_KIND_STRING_ENTRY(R_HEX_GOTREL_HI16), + LLD_KIND_STRING_ENTRY(R_HEX_GOTREL_32), + LLD_KIND_STRING_ENTRY(R_HEX_GOT_LO16), + LLD_KIND_STRING_ENTRY(R_HEX_GOT_HI16), + LLD_KIND_STRING_ENTRY(R_HEX_GOT_32), + LLD_KIND_STRING_ENTRY(R_HEX_GOT_16), + LLD_KIND_STRING_ENTRY(R_HEX_DTPMOD_32), + LLD_KIND_STRING_ENTRY(R_HEX_DTPREL_LO16), + LLD_KIND_STRING_ENTRY(R_HEX_DTPREL_HI16), + LLD_KIND_STRING_ENTRY(R_HEX_DTPREL_32), + LLD_KIND_STRING_ENTRY(R_HEX_DTPREL_16), + LLD_KIND_STRING_ENTRY(R_HEX_GD_PLT_B22_PCREL), + LLD_KIND_STRING_ENTRY(R_HEX_GD_GOT_LO16), + LLD_KIND_STRING_ENTRY(R_HEX_GD_GOT_HI16), + LLD_KIND_STRING_ENTRY(R_HEX_GD_GOT_32), + LLD_KIND_STRING_ENTRY(R_HEX_GD_GOT_16), + LLD_KIND_STRING_ENTRY(R_HEX_IE_LO16), + LLD_KIND_STRING_ENTRY(R_HEX_IE_HI16), + LLD_KIND_STRING_ENTRY(R_HEX_IE_32), + LLD_KIND_STRING_ENTRY(R_HEX_IE_GOT_LO16), + LLD_KIND_STRING_ENTRY(R_HEX_IE_GOT_HI16), + LLD_KIND_STRING_ENTRY(R_HEX_IE_GOT_32), + LLD_KIND_STRING_ENTRY(R_HEX_IE_GOT_16), + LLD_KIND_STRING_ENTRY(R_HEX_TPREL_LO16), + LLD_KIND_STRING_ENTRY(R_HEX_TPREL_HI16), + LLD_KIND_STRING_ENTRY(R_HEX_TPREL_32), + LLD_KIND_STRING_ENTRY(R_HEX_TPREL_16), + LLD_KIND_STRING_ENTRY(R_HEX_6_PCREL_X), + LLD_KIND_STRING_ENTRY(R_HEX_GOTREL_32_6_X), + LLD_KIND_STRING_ENTRY(R_HEX_GOTREL_16_X), + LLD_KIND_STRING_ENTRY(R_HEX_GOTREL_11_X), + LLD_KIND_STRING_ENTRY(R_HEX_GOT_32_6_X), + LLD_KIND_STRING_ENTRY(R_HEX_GOT_16_X), + LLD_KIND_STRING_ENTRY(R_HEX_GOT_11_X), + LLD_KIND_STRING_ENTRY(R_HEX_DTPREL_32_6_X), + LLD_KIND_STRING_ENTRY(R_HEX_DTPREL_16_X), + LLD_KIND_STRING_ENTRY(R_HEX_DTPREL_11_X), + LLD_KIND_STRING_ENTRY(R_HEX_GD_GOT_32_6_X), + LLD_KIND_STRING_ENTRY(R_HEX_GD_GOT_16_X), + LLD_KIND_STRING_ENTRY(R_HEX_GD_GOT_11_X), + LLD_KIND_STRING_ENTRY(R_HEX_IE_32_6_X), + LLD_KIND_STRING_ENTRY(R_HEX_IE_32_6_X), + LLD_KIND_STRING_ENTRY(R_HEX_IE_16_X), + LLD_KIND_STRING_ENTRY(R_HEX_IE_GOT_32_6_X), + LLD_KIND_STRING_ENTRY(R_HEX_IE_GOT_16_X), + LLD_KIND_STRING_ENTRY(R_HEX_IE_GOT_11_X), + LLD_KIND_STRING_ENTRY(R_HEX_IE_32_6_X), + LLD_KIND_STRING_ENTRY(R_HEX_IE_16_X), + LLD_KIND_STRING_ENTRY(R_HEX_IE_GOT_32_6_X), + LLD_KIND_STRING_ENTRY(R_HEX_IE_GOT_16_X), + LLD_KIND_STRING_ENTRY(R_HEX_IE_GOT_11_X), + LLD_KIND_STRING_ENTRY(R_HEX_TPREL_32_6_X), + LLD_KIND_STRING_ENTRY(R_HEX_TPREL_16_X), + LLD_KIND_STRING_ENTRY(R_HEX_TPREL_11_X), + LLD_KIND_STRING_END +}; + Index: lib/ReaderWriter/ELF/Mips/MipsLinkingContext.h =================================================================== --- lib/ReaderWriter/ELF/Mips/MipsLinkingContext.h +++ lib/ReaderWriter/ELF/Mips/MipsLinkingContext.h @@ -27,8 +27,6 @@ // ELFLinkingContext virtual bool isLittleEndian() const; - virtual ErrorOr relocKindFromString(StringRef str) const; - virtual ErrorOr stringFromRelocKind(Reference::Kind kind) const; virtual void addPasses(PassManager &pm); }; Index: lib/ReaderWriter/ELF/Mips/MipsLinkingContext.cpp =================================================================== --- lib/ReaderWriter/ELF/Mips/MipsLinkingContext.cpp +++ lib/ReaderWriter/ELF/Mips/MipsLinkingContext.cpp @@ -55,7 +55,7 @@ class MipsGOTPassFile : public SimpleFile { public: MipsGOTPassFile(const ELFLinkingContext &ctx) - : SimpleFile(ctx, "MipsGOTPassFile") { + : SimpleFile("MipsGOTPassFile") { setOrdinal(ctx.getNextOrdinalAndIncrement()); } @@ -113,7 +113,10 @@ /// \brief Handle a specific reference. void handleReference(const DefinedAtom &atom, const Reference &ref) { - switch (ref.kind()) { + if (ref.kindNamespace() != lld::Reference::KindNamespace::ELF) + return; + assert(ref.kindArch() == Reference::KindArch::Mips); + switch (ref.kindValue()) { case R_MIPS_GOT16: case R_MIPS_CALL16: handleGOT(ref); @@ -139,9 +142,9 @@ _localGotVector.push_back(ga); else { if (da) - ga->addReference(R_MIPS_32, 0, a, 0); + ga->addReferenceELF_Mips(R_MIPS_32, 0, a, 0); else - ga->addReference(R_MIPS_NONE, 0, a, 0); + ga->addReferenceELF_Mips(R_MIPS_NONE, 0, a, 0); _globalGotVector.push_back(ga); } @@ -177,46 +180,6 @@ return Mips32ElELFType::TargetEndianness == llvm::support::little; } -#undef LLD_CASE -#define LLD_CASE(name) .Case(#name, llvm::ELF::name) - -ErrorOr -MipsLinkingContext::relocKindFromString(StringRef str) const { - int32_t ret = llvm::StringSwitch(str) - LLD_CASE(R_MIPS_NONE) - LLD_CASE(R_MIPS_32) - LLD_CASE(R_MIPS_HI16) - LLD_CASE(R_MIPS_LO16) - LLD_CASE(R_MIPS_GOT16) - LLD_CASE(R_MIPS_CALL16) - LLD_CASE(R_MIPS_JALR) - .Default(-1); - - if (ret == -1) - return make_error_code(YamlReaderError::illegal_value); - return ret; -} - -#undef LLD_CASE -#define LLD_CASE(name) \ - case llvm::ELF::name: \ - return std::string(#name); - -ErrorOr -MipsLinkingContext::stringFromRelocKind(Reference::Kind kind) const { - switch (kind) { - LLD_CASE(R_MIPS_NONE) - LLD_CASE(R_MIPS_32) - LLD_CASE(R_MIPS_HI16) - LLD_CASE(R_MIPS_LO16) - LLD_CASE(R_MIPS_GOT16) - LLD_CASE(R_MIPS_CALL16) - LLD_CASE(R_MIPS_JALR) - } - - return make_error_code(YamlReaderError::illegal_value); -} - void MipsLinkingContext::addPasses(PassManager &pm) { switch (getOutputELFType()) { case llvm::ELF::ET_DYN: Index: lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp =================================================================== --- lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp +++ lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp @@ -120,7 +120,10 @@ int64_t ahl = calcAHL(ri->addend(), loAddend); - switch (ri->kind()) { + if (ri->kindNamespace() != lld::Reference::KindNamespace::ELF) + continue; + assert(ri->kindArch() == Reference::KindArch::Mips); + switch (ri->kindValue()) { case R_MIPS_HI16: relocHi16(location, relocVAddress, targetVAddress, ahl, _targetHandler.getGPDispSymAddr(), @@ -146,7 +149,10 @@ uint64_t targetVAddress = writer.addressOfAtom(ref.target()); uint64_t relocVAddress = atom._virtualAddr + ref.offsetInAtom(); - switch (ref.kind()) { + if (ref.kindNamespace() != lld::Reference::KindNamespace::ELF) + return error_code::success(); + assert(ref.kindArch() == Reference::KindArch::Mips); + switch (ref.kindValue()) { case R_MIPS_NONE: break; case R_MIPS_32: @@ -171,16 +177,10 @@ case R_MIPS_JALR: // We do not do JALR optimization now. break; - case lld::Reference::kindLayoutAfter: - case lld::Reference::kindLayoutBefore: - case lld::Reference::kindInGroup: - break; default: { std::string str; llvm::raw_string_ostream s(str); - auto name = _context.stringFromRelocKind(ref.kind()); - s << "Unhandled relocation: " - << (name ? *name : "") << " (" << ref.kind() << ")"; + s << "Unhandled Mips relocation: " << ref.kindValue(); llvm_unreachable(s.str().c_str()); } } Index: lib/ReaderWriter/ELF/Mips/MipsSectionChunks.h =================================================================== --- lib/ReaderWriter/ELF/Mips/MipsSectionChunks.h +++ lib/ReaderWriter/ELF/Mips/MipsSectionChunks.h @@ -51,8 +51,11 @@ const Atom *ta = nullptr; for (const auto &r : *da) { - if (r->kind() == llvm::ELF::R_MIPS_32 || - r->kind() == llvm::ELF::R_MIPS_NONE) { + if (r->kindNamespace() != lld::Reference::KindNamespace::ELF) + continue; + assert(r->kindArch() == Reference::KindArch::Mips); + if (r->kindValue() == llvm::ELF::R_MIPS_32 || + r->kindValue() == llvm::ELF::R_MIPS_NONE) { ta = r->target(); break; } Index: lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h =================================================================== --- lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h +++ lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h @@ -59,8 +59,10 @@ createDynamicSymbolTable(); virtual bool createImplicitFiles(std::vector> &result); virtual void finalizeSymbolValues(); + virtual void registerRelocationNames(Registry ®istry); private: + static const Registry::KindStrings kindStrings[]; llvm::BumpPtrAllocator _alloc; MipsTargetLayout _targetLayout; MipsTargetRelocationHandler _relocationHandler; Index: lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp =================================================================== --- lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp +++ lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp @@ -173,3 +173,22 @@ gotSection ? gotSection->virtualAddr() + 0x7FF0 : 0; } } + +void MipsTargetHandler::registerRelocationNames(Registry ®istry) { + registry.addKindTable(Reference::KindNamespace::ELF, + Reference::KindArch::Mips, + kindStrings); +} + + +const Registry::KindStrings MipsTargetHandler::kindStrings[] = { + LLD_KIND_STRING_ENTRY(R_MIPS_NONE), + LLD_KIND_STRING_ENTRY(R_MIPS_32), + LLD_KIND_STRING_ENTRY(R_MIPS_HI16), + LLD_KIND_STRING_ENTRY(R_MIPS_LO16), + LLD_KIND_STRING_ENTRY(R_MIPS_GOT16), + LLD_KIND_STRING_ENTRY(R_MIPS_CALL16), + LLD_KIND_STRING_ENTRY(R_MIPS_JALR), + LLD_KIND_STRING_END +}; + \ No newline at end of file Index: lib/ReaderWriter/ELF/PPC/PPCLinkingContext.h =================================================================== --- lib/ReaderWriter/ELF/PPC/PPCLinkingContext.h +++ lib/ReaderWriter/ELF/PPC/PPCLinkingContext.h @@ -29,9 +29,6 @@ /// \brief PPC has no relative relocations defined virtual bool isRelativeReloc(const Reference &) const { return false; } - - virtual ErrorOr relocKindFromString(StringRef str) const; - virtual ErrorOr stringFromRelocKind(Reference::Kind kind) const; }; } // elf Index: lib/ReaderWriter/ELF/PPC/PPCLinkingContext.cpp =================================================================== --- lib/ReaderWriter/ELF/PPC/PPCLinkingContext.cpp +++ lib/ReaderWriter/ELF/PPC/PPCLinkingContext.cpp @@ -16,31 +16,3 @@ using namespace lld; -#define LLD_CASE(name) .Case(#name, llvm::ELF::name) - -ErrorOr -elf::PPCLinkingContext::relocKindFromString(StringRef str) const { - int32_t ret = llvm::StringSwitch(str) LLD_CASE(R_PPC_NONE) - LLD_CASE(R_PPC_ADDR32) LLD_CASE(R_PPC_REL24).Default(-1); - - if (ret == -1) - return make_error_code(YamlReaderError::illegal_value); - return ret; -} - -#undef LLD_CASE - -#define LLD_CASE(name) \ - case llvm::ELF::name: \ - return std::string(#name); - -ErrorOr -elf::PPCLinkingContext::stringFromRelocKind(Reference::Kind kind) const { - switch (kind) { - LLD_CASE(R_PPC_NONE) - LLD_CASE(R_PPC_ADDR32) - LLD_CASE(R_PPC_REL24) - } - - return make_error_code(YamlReaderError::illegal_value); -} Index: lib/ReaderWriter/ELF/PPC/PPCTargetHandler.h =================================================================== --- lib/ReaderWriter/ELF/PPC/PPCTargetHandler.h +++ lib/ReaderWriter/ELF/PPC/PPCTargetHandler.h @@ -37,6 +37,8 @@ public: PPCTargetHandler(PPCLinkingContext &targetInfo); + virtual void registerRelocationNames(Registry ®istry); + virtual TargetLayout &targetLayout() { return _targetLayout; } @@ -46,6 +48,8 @@ } private: + static const Registry::KindStrings kindStrings[]; + PPCTargetRelocationHandler _relocationHandler; TargetLayout _targetLayout; }; Index: lib/ReaderWriter/ELF/PPC/PPCTargetHandler.cpp =================================================================== --- lib/ReaderWriter/ELF/PPC/PPCTargetHandler.cpp +++ lib/ReaderWriter/ELF/PPC/PPCTargetHandler.cpp @@ -43,22 +43,18 @@ uint64_t targetVAddress = writer.addressOfAtom(ref.target()); uint64_t relocVAddress = atom._virtualAddr + ref.offsetInAtom(); - switch (ref.kind()) { + if (ref.kindNamespace() != Reference::KindNamespace::ELF) + return error_code::success(); + assert(ref.kindArch() == Reference::KindArch::PowerPC); + switch (ref.kindValue()) { case R_PPC_REL24: relocB24PCREL(location, relocVAddress, targetVAddress, ref.addend()); break; - case lld::Reference::kindLayoutAfter: - case lld::Reference::kindLayoutBefore: - case lld::Reference::kindInGroup: - break; - default : { std::string str; llvm::raw_string_ostream s(str); - auto name = _context.stringFromRelocKind(ref.kind()); - s << "Unhandled relocation: " << (name ? *name : "") << " (" - << ref.kind() << ")"; + s << "Unhandled PowerPC relocation: #" << ref.kindValue(); s.flush(); llvm_unreachable(str.c_str()); } @@ -70,3 +66,70 @@ PPCTargetHandler::PPCTargetHandler(PPCLinkingContext &targetInfo) : DefaultTargetHandler(targetInfo), _relocationHandler(targetInfo), _targetLayout(targetInfo) {} + + +void PPCTargetHandler::registerRelocationNames(Registry ®istry) { + registry.addKindTable(Reference::KindNamespace::ELF, + Reference::KindArch::PowerPC, + kindStrings); +} + +const Registry::KindStrings PPCTargetHandler::kindStrings[] = { + LLD_KIND_STRING_ENTRY(R_PPC_NONE), + LLD_KIND_STRING_ENTRY(R_PPC_ADDR32), + LLD_KIND_STRING_ENTRY(R_PPC_ADDR24), + LLD_KIND_STRING_ENTRY(R_PPC_ADDR16), + LLD_KIND_STRING_ENTRY(R_PPC_ADDR16_LO), + LLD_KIND_STRING_ENTRY(R_PPC_ADDR16_HI), + LLD_KIND_STRING_ENTRY(R_PPC_ADDR16_HA), + LLD_KIND_STRING_ENTRY(R_PPC_ADDR14), + LLD_KIND_STRING_ENTRY(R_PPC_ADDR14_BRTAKEN), + LLD_KIND_STRING_ENTRY(R_PPC_ADDR14_BRNTAKEN), + LLD_KIND_STRING_ENTRY(R_PPC_REL24), + LLD_KIND_STRING_ENTRY(R_PPC_REL14), + LLD_KIND_STRING_ENTRY(R_PPC_REL14_BRTAKEN), + LLD_KIND_STRING_ENTRY(R_PPC_REL14_BRNTAKEN), + LLD_KIND_STRING_ENTRY(R_PPC_GOT16), + LLD_KIND_STRING_ENTRY(R_PPC_GOT16_LO), + LLD_KIND_STRING_ENTRY(R_PPC_GOT16_HI), + LLD_KIND_STRING_ENTRY(R_PPC_GOT16_HA), + LLD_KIND_STRING_ENTRY(R_PPC_REL32), + LLD_KIND_STRING_ENTRY(R_PPC_TLS), + LLD_KIND_STRING_ENTRY(R_PPC_DTPMOD32), + LLD_KIND_STRING_ENTRY(R_PPC_TPREL16), + LLD_KIND_STRING_ENTRY(R_PPC_TPREL16_LO), + LLD_KIND_STRING_ENTRY(R_PPC_TPREL16_HI), + LLD_KIND_STRING_ENTRY(R_PPC_TPREL16_HA), + LLD_KIND_STRING_ENTRY(R_PPC_TPREL32), + LLD_KIND_STRING_ENTRY(R_PPC_DTPREL16), + LLD_KIND_STRING_ENTRY(R_PPC_DTPREL16_LO), + LLD_KIND_STRING_ENTRY(R_PPC_DTPREL16_HI), + LLD_KIND_STRING_ENTRY(R_PPC_DTPREL16_HA), + LLD_KIND_STRING_ENTRY(R_PPC_DTPREL32), + LLD_KIND_STRING_ENTRY(R_PPC_GOT_TLSGD16), + LLD_KIND_STRING_ENTRY(R_PPC_GOT_TLSGD16_LO), + LLD_KIND_STRING_ENTRY(R_PPC_GOT_TLSGD16_HI), + LLD_KIND_STRING_ENTRY(R_PPC_GOT_TLSGD16_HA), + LLD_KIND_STRING_ENTRY(R_PPC_GOT_TLSLD16), + LLD_KIND_STRING_ENTRY(R_PPC_GOT_TLSLD16_LO), + LLD_KIND_STRING_ENTRY(R_PPC_GOT_TLSLD16_HI), + LLD_KIND_STRING_ENTRY(R_PPC_GOT_TLSLD16_HA), + LLD_KIND_STRING_ENTRY(R_PPC_GOT_TPREL16), + LLD_KIND_STRING_ENTRY(R_PPC_GOT_TPREL16_LO), + LLD_KIND_STRING_ENTRY(R_PPC_GOT_TPREL16_HI), + LLD_KIND_STRING_ENTRY(R_PPC_GOT_TPREL16_HA), + LLD_KIND_STRING_ENTRY(R_PPC_GOT_DTPREL16), + LLD_KIND_STRING_ENTRY(R_PPC_GOT_DTPREL16_LO), + LLD_KIND_STRING_ENTRY(R_PPC_GOT_DTPREL16_HI), + LLD_KIND_STRING_ENTRY(R_PPC_GOT_DTPREL16_HA), + LLD_KIND_STRING_ENTRY(R_PPC_TLSGD), + LLD_KIND_STRING_ENTRY(R_PPC_TLSLD), + LLD_KIND_STRING_ENTRY(R_PPC_REL16), + LLD_KIND_STRING_ENTRY(R_PPC_REL16_LO), + LLD_KIND_STRING_ENTRY(R_PPC_REL16_HI), + LLD_KIND_STRING_ENTRY(R_PPC_REL16_HA), + LLD_KIND_STRING_END +}; + + + Index: lib/ReaderWriter/ELF/Reader.cpp =================================================================== --- lib/ReaderWriter/ELF/Reader.cpp +++ lib/ReaderWriter/ELF/Reader.cpp @@ -19,13 +19,14 @@ #include "CreateELF.h" #include "DynamicFile.h" #include "File.h" +#include "X86/X86TargetHandler.h" +#include "X86_64/X86_64TargetHandler.h" +#include "Hexagon/HexagonTargetHandler.h" #include "lld/Core/Reference.h" #include "lld/ReaderWriter/ELFLinkingContext.h" -#include "lld/ReaderWriter/FileArchive.h" +#include "lld/ReaderWriter/Reader.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" #include "llvm/Object/ELF.h" #include "llvm/Object/ObjectFile.h" @@ -48,14 +49,16 @@ using llvm::support::endianness; using namespace llvm::object; +namespace lld { namespace { + struct DynamicFileCreateELFTraits { typedef llvm::ErrorOr> result_type; template - static result_type create(const lld::ELFLinkingContext &ctx, - std::unique_ptr mb) { - return lld::elf::DynamicFile::create(ctx, std::move(mb)); + static result_type create(std::unique_ptr mb, + bool useUndefines) { + return lld::elf::DynamicFile::create(std::move(mb), useUndefines); } }; @@ -63,74 +66,90 @@ typedef std::unique_ptr result_type; template - static result_type create(const lld::ELFLinkingContext &ctx, - std::unique_ptr mb, + static result_type create(std::unique_ptr mb, + bool atomizeStrings, + TargetHandlerBase *handler, lld::error_code &ec) { return std::unique_ptr( - new lld::elf::ELFFile(ctx, std::move(mb), ec)); + new lld::elf::ELFFile(std::move(mb), atomizeStrings, handler,ec)); } }; -} -namespace lld { -namespace elf { -/// \brief A reader object that will instantiate correct File by examining the -/// memory buffer for ELF class and bit width -class ELFReader : public Reader { +class ELFObjectReader : public Reader { public: - ELFReader(const ELFLinkingContext &ctx) - : lld::Reader(ctx), _elfLinkingContext(ctx) {} - - error_code parseFile(std::unique_ptr &mb, - std::vector > &result) const { - using llvm::object::ELFType; - llvm::sys::fs::file_magic FileType = - llvm::sys::fs::identify_magic(mb->getBuffer()); - - std::size_t MaxAlignment = - 1ULL << llvm::countTrailingZeros(uintptr_t(mb->getBufferStart())); + ELFObjectReader(bool atomizeStrings, TargetHandlerBase* handler) + : _atomizeStrings(atomizeStrings), _handler(handler) { } + virtual bool canParse(file_magic magic, StringRef,const MemoryBuffer&) const { + return (magic == llvm::sys::fs::file_magic::elf_relocatable); + } + + virtual error_code + parseFile(std::unique_ptr &mb, const class Registry &, + std::vector> &result) const { error_code ec; - switch (FileType) { - case llvm::sys::fs::file_magic::elf_relocatable: { - std::unique_ptr f(createELF( - getElfArchType(&*mb), MaxAlignment, _elfLinkingContext, std::move(mb), - ec)); - if (ec) - return ec; - result.push_back(std::move(f)); - break; - } - case llvm::sys::fs::file_magic::elf_shared_object: { - // If the link doesn't allow dynamic libraries to be present during the - // link, let's not parse the file and just return - if (!_elfLinkingContext.allowLinkWithDynamicLibraries()) - return llvm::make_error_code(llvm::errc::executable_format_error); - auto f = createELF( - getElfArchType(&*mb), MaxAlignment, _elfLinkingContext, - std::move(mb)); - if (!f) - return f; - result.push_back(std::move(*f)); - break; - } - default: - return llvm::make_error_code(llvm::errc::executable_format_error); - break; - } - + std::size_t maxAlignment = + 1ULL << llvm::countTrailingZeros(uintptr_t(mb->getBufferStart())); + std::unique_ptr f(createELF( + getElfArchType(&*mb), maxAlignment, std::move(mb), + _atomizeStrings, _handler, ec)); if (ec) return ec; - + result.push_back(std::move(f)); return error_code::success(); } +private: + bool _atomizeStrings; + TargetHandlerBase *_handler; +}; + +class ELFDSOReader : public Reader { +public: + ELFDSOReader(bool useUndefines) : _useUndefines(useUndefines) { } + + virtual bool canParse(file_magic magic, StringRef, const MemoryBuffer&) const{ + return (magic == llvm::sys::fs::file_magic::elf_shared_object); + } + + virtual error_code + parseFile(std::unique_ptr &mb, const class Registry &, + std::vector> &result) const { + std::size_t maxAlignment = + 1ULL << llvm::countTrailingZeros(uintptr_t(mb->getBufferStart())); + auto f = createELF( + getElfArchType(&*mb), maxAlignment, + std::move(mb), _useUndefines); + if (!f) + return f; + std::unique_ptr f2(f->release()); + result.push_back(std::move(f2)); + return error_code::success(); + } private: - const ELFLinkingContext &_elfLinkingContext; + bool _useUndefines; }; -} // end namespace elf -std::unique_ptr createReaderELF(const ELFLinkingContext &context) { - return std::unique_ptr(new elf::ELFReader(context)); +} // anonymous + + +// This dynamic registration of a handler causes support for all ELF +// architectures to be pulled into the linker. If we want to support making a +// linker that only supports one ELF architecture, we'd need to change this +// to have a different registration method for each architecture. +void Registry::addSupportELFObjects(bool atomizeStrings, + TargetHandlerBase *handler) { + + // Tell registry about the ELF object file parser. + add(std::unique_ptr(new ELFObjectReader(atomizeStrings, handler))); + + // Tell registry about the relocation name to number mapping for this arch. + handler->registerRelocationNames(*this); +} + +void Registry::addSupportELFDynamicSharedObjects(bool useShlibUndefines) { + add(std::unique_ptr(new ELFDSOReader(useShlibUndefines))); } + + } // end namespace lld Index: lib/ReaderWriter/ELF/SectionChunks.h =================================================================== --- lib/ReaderWriter/ELF/SectionChunks.h +++ lib/ReaderWriter/ELF/SectionChunks.h @@ -31,13 +31,6 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileOutputBuffer.h" -static LLVM_ATTRIBUTE_UNUSED std::string -kindOrUnknown(llvm::ErrorOr k) { - if (k) - return *k; - return ""; -} - namespace lld { namespace elf { template class MergedSections; @@ -49,7 +42,7 @@ public: Section(const ELFLinkingContext &context, StringRef name, typename Chunk::Kind k = Chunk::Kind::ELFSection) - : Chunk(name, k, context), _parent(nullptr), _flags(0), _entSize(0), + : Chunk(name, k, context), _parent(nullptr), _flags(0), _entSize(0), _type(0), _link(0), _info(0), _segmentType(SHT_NULL) {} /// \brief Modify the section contents before assigning virtual addresses @@ -959,7 +952,7 @@ uint32_t index = _symbolTable ? _symbolTable->getSymbolTableIndex(rel.second->target()) : (uint32_t) STN_UNDEF; - r->setSymbolAndType(index, rel.second->kind()); + r->setSymbolAndType(index, rel.second->kindValue()); r->r_offset = writer->addressOfAtom(rel.first) + rel.second->offsetInAtom(); r->r_addend = 0; @@ -969,12 +962,11 @@ writer->addressOfAtom(rel.second->target()) + rel.second->addend(); dest += sizeof(Elf_Rela); DEBUG_WITH_TYPE( - "ELFRelocationTable", - llvm::dbgs() << kindOrUnknown(this->_context.stringFromRelocKind( - rel.second->kind())) << " relocation at " + "ELFRelocationTable", + llvm::dbgs() << rel.second->kindValue() << " relocation at " << rel.first->name() << "@" << r->r_offset << " to " << rel.second->target()->name() << "@" << r->r_addend - << "\n"); + << "\n";); } } Index: lib/ReaderWriter/ELF/X86/X86LinkingContext.h =================================================================== --- lib/ReaderWriter/ELF/X86/X86LinkingContext.h +++ lib/ReaderWriter/ELF/X86/X86LinkingContext.h @@ -29,7 +29,10 @@ /// a) for supporting IFUNC relocs - R_386_IRELATIVE /// b) for supporting relative relocs - R_386_RELATIVE virtual bool isRelativeReloc(const Reference &r) const { - switch (r.kind()) { + if (r.kindNamespace() != Reference::KindNamespace::ELF) + return false; + assert(r.kindArch() == Reference::KindArch::x86); + switch (r.kindValue()) { case llvm::ELF::R_386_IRELATIVE: case llvm::ELF::R_386_RELATIVE: return true; @@ -37,8 +40,6 @@ return false; } } - virtual ErrorOr relocKindFromString(StringRef str) const; - virtual ErrorOr stringFromRelocKind(Reference::Kind kind) const; }; } // end namespace elf } // end namespace lld Index: lib/ReaderWriter/ELF/X86/X86LinkingContext.cpp =================================================================== --- lib/ReaderWriter/ELF/X86/X86LinkingContext.cpp +++ lib/ReaderWriter/ELF/X86/X86LinkingContext.cpp @@ -16,33 +16,3 @@ using namespace lld; -#define LLD_CASE(name) .Case(#name, llvm::ELF::name) - -ErrorOr -elf::X86LinkingContext::relocKindFromString(StringRef str) const { - int32_t ret = llvm::StringSwitch(str) - LLD_CASE(R_386_NONE) - LLD_CASE(R_386_PC32) - LLD_CASE(R_386_32) - .Default(-1); - if (ret == -1) - return make_error_code(YamlReaderError::illegal_value); - return ret; -} - -#undef LLD_CASE - -#define LLD_CASE(name) \ - case llvm::ELF::name: \ - return std::string(#name); - -ErrorOr -elf::X86LinkingContext::stringFromRelocKind(Reference::Kind kind) const { - switch (kind) { - LLD_CASE(R_386_NONE) - LLD_CASE(R_386_PC32) - LLD_CASE(R_386_32) - } - - return make_error_code(YamlReaderError::illegal_value); -} Index: lib/ReaderWriter/ELF/X86/X86TargetHandler.h =================================================================== --- lib/ReaderWriter/ELF/X86/X86TargetHandler.h +++ lib/ReaderWriter/ELF/X86/X86TargetHandler.h @@ -13,8 +13,11 @@ #include "DefaultTargetHandler.h" #include "TargetLayout.h" +#include "lld/ReaderWriter/Reader.h" + namespace lld { namespace elf { + typedef llvm::object::ELFType X86ELFType; class X86LinkingContext; @@ -27,6 +30,8 @@ virtual error_code applyRelocation(ELFWriter &, llvm::FileOutputBuffer &, const lld::AtomLayout &, const Reference &) const; + + static const Registry::KindStrings kindStrings[]; private: const X86LinkingContext &_context; @@ -37,6 +42,8 @@ public: X86TargetHandler(X86LinkingContext &context); + virtual void registerRelocationNames(Registry ®istry); + virtual TargetLayout &targetLayout() { return _targetLayout; } @@ -46,6 +53,8 @@ } private: + static const Registry::KindStrings kindStrings[]; + X86TargetRelocationHandler _relocationHandler; TargetLayout _targetLayout; }; Index: lib/ReaderWriter/ELF/X86/X86TargetHandler.cpp =================================================================== --- lib/ReaderWriter/ELF/X86/X86TargetHandler.cpp +++ lib/ReaderWriter/ELF/X86/X86TargetHandler.cpp @@ -31,6 +31,59 @@ return 0; } + + +const Registry::KindStrings X86TargetHandler::kindStrings[] = { + LLD_KIND_STRING_ENTRY(R_386_NONE), + LLD_KIND_STRING_ENTRY(R_386_32), + LLD_KIND_STRING_ENTRY(R_386_PC32), + LLD_KIND_STRING_ENTRY(R_386_GOT32), + LLD_KIND_STRING_ENTRY(R_386_PLT32), + LLD_KIND_STRING_ENTRY(R_386_COPY), + LLD_KIND_STRING_ENTRY(R_386_GLOB_DAT), + LLD_KIND_STRING_ENTRY(R_386_JUMP_SLOT), + LLD_KIND_STRING_ENTRY(R_386_RELATIVE), + LLD_KIND_STRING_ENTRY(R_386_GOTOFF), + LLD_KIND_STRING_ENTRY(R_386_GOTPC), + LLD_KIND_STRING_ENTRY(R_386_32PLT), + LLD_KIND_STRING_ENTRY(R_386_TLS_TPOFF), + LLD_KIND_STRING_ENTRY(R_386_TLS_IE), + LLD_KIND_STRING_ENTRY(R_386_TLS_GOTIE), + LLD_KIND_STRING_ENTRY(R_386_TLS_LE), + LLD_KIND_STRING_ENTRY(R_386_TLS_GD), + LLD_KIND_STRING_ENTRY(R_386_TLS_LDM), + LLD_KIND_STRING_ENTRY(R_386_16), + LLD_KIND_STRING_ENTRY(R_386_PC16), + LLD_KIND_STRING_ENTRY(R_386_8), + LLD_KIND_STRING_ENTRY(R_386_PC8), + LLD_KIND_STRING_ENTRY(R_386_TLS_GD_32), + LLD_KIND_STRING_ENTRY(R_386_TLS_GD_PUSH), + LLD_KIND_STRING_ENTRY(R_386_TLS_GD_CALL), + LLD_KIND_STRING_ENTRY(R_386_TLS_GD_POP), + LLD_KIND_STRING_ENTRY(R_386_TLS_LDM_32), + LLD_KIND_STRING_ENTRY(R_386_TLS_LDM_PUSH), + LLD_KIND_STRING_ENTRY(R_386_TLS_LDM_CALL), + LLD_KIND_STRING_ENTRY(R_386_TLS_LDM_POP), + LLD_KIND_STRING_ENTRY(R_386_TLS_LDO_32), + LLD_KIND_STRING_ENTRY(R_386_TLS_IE_32), + LLD_KIND_STRING_ENTRY(R_386_TLS_LE_32), + LLD_KIND_STRING_ENTRY(R_386_TLS_DTPMOD32), + LLD_KIND_STRING_ENTRY(R_386_TLS_DTPOFF32), + LLD_KIND_STRING_ENTRY(R_386_TLS_TPOFF32), + LLD_KIND_STRING_ENTRY(R_386_TLS_GOTDESC), + LLD_KIND_STRING_ENTRY(R_386_TLS_DESC_CALL), + LLD_KIND_STRING_ENTRY(R_386_TLS_DESC), + LLD_KIND_STRING_ENTRY(R_386_IRELATIVE), + LLD_KIND_STRING_ENTRY(R_386_NUM), + LLD_KIND_STRING_END +}; + +void X86TargetHandler::registerRelocationNames(Registry ®istry) { + registry.addKindTable(Reference::KindNamespace::ELF, + Reference::KindArch::x86, + kindStrings); +} + error_code X86TargetRelocationHandler::applyRelocation( ELFWriter &writer, llvm::FileOutputBuffer &buf, const lld::AtomLayout &atom, const Reference &ref) const { @@ -39,23 +92,20 @@ uint64_t targetVAddress = writer.addressOfAtom(ref.target()); uint64_t relocVAddress = atom._virtualAddr + ref.offsetInAtom(); - switch (ref.kind()) { + if (ref.kindNamespace() != Reference::KindNamespace::ELF) + return error_code::success(); + assert(ref.kindArch() == Reference::KindArch::x86); + switch (ref.kindValue()) { case R_386_32: reloc32(location, relocVAddress, targetVAddress, ref.addend()); break; case R_386_PC32: relocPC32(location, relocVAddress, targetVAddress, ref.addend()); break; - case lld::Reference::kindLayoutAfter: - case lld::Reference::kindLayoutBefore: - case lld::Reference::kindInGroup: - break; default : { std::string str; llvm::raw_string_ostream s(str); - auto name = _context.stringFromRelocKind(ref.kind()); - s << "Unhandled relocation: " << (name ? *name : "") << " (" - << ref.kind() << ")"; + s << "Unhandled I386 relocation # " << ref.kindValue(); s.flush(); llvm_unreachable(str.c_str()); } Index: lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.h =================================================================== --- lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.h +++ lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.h @@ -43,7 +43,10 @@ virtual bool isDynamicRelocation(const DefinedAtom &, const Reference &r) const { - switch (r.kind()) { + if (r.kindNamespace() != Reference::KindNamespace::ELF) + return false; + assert(r.kindArch() == Reference::KindArch::x86_64); + switch (r.kindValue()) { case llvm::ELF::R_X86_64_RELATIVE: case llvm::ELF::R_X86_64_GLOB_DAT: case llvm::ELF::R_X86_64_COPY: @@ -54,7 +57,10 @@ } virtual bool isPLTRelocation(const DefinedAtom &, const Reference &r) const { - switch (r.kind()) { + if (r.kindNamespace() != Reference::KindNamespace::ELF) + return false; + assert(r.kindArch() == Reference::KindArch::x86_64); + switch (r.kindValue()) { case llvm::ELF::R_X86_64_JUMP_SLOT: case llvm::ELF::R_X86_64_IRELATIVE: return true; @@ -67,7 +73,10 @@ /// a) for supporting IFUNC - R_X86_64_IRELATIVE /// b) for supporting relative relocs - R_X86_64_RELATIVE virtual bool isRelativeReloc(const Reference &r) const { - switch (r.kind()) { + if (r.kindNamespace() != Reference::KindNamespace::ELF) + return false; + assert(r.kindArch() == Reference::KindArch::x86_64); + switch (r.kindValue()) { case llvm::ELF::R_X86_64_IRELATIVE: case llvm::ELF::R_X86_64_RELATIVE: return true; @@ -79,8 +88,6 @@ /// \brief Create Internal files for Init/Fini bool createInternalFiles(std::vector > &) const; - virtual ErrorOr relocKindFromString(StringRef str) const; - virtual ErrorOr stringFromRelocKind(Reference::Kind kind) const; }; } // end namespace elf } // end namespace lld Index: lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.cpp =================================================================== --- lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.cpp +++ lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.cpp @@ -63,13 +63,14 @@ class X86_64InitFiniFile : public SimpleFile { public: X86_64InitFiniFile(const ELFLinkingContext &context) - : SimpleFile(context, "command line option -init/-fini"), _ordinal(0) {} + : SimpleFile("command line option -init/-fini"), _ordinal(0) {} void addInitFunction(StringRef name) { Atom *initFunctionAtom = new (_allocator) SimpleUndefinedAtom(*this, name); X86_64InitAtom *initAtom = (new (_allocator) X86_64InitAtom(*this, name)); - initAtom->addReference(llvm::ELF::R_X86_64_64, 0, initFunctionAtom, 0); + initAtom->addReferenceELF_x86_64(llvm::ELF::R_X86_64_64, 0, + initFunctionAtom, 0); initAtom->setOrdinal(_ordinal++); addAtom(*initFunctionAtom); addAtom(*initAtom); @@ -79,7 +80,8 @@ Atom *finiFunctionAtom = new (_allocator) SimpleUndefinedAtom(*this, name); X86_64FiniAtom *finiAtom = (new (_allocator) X86_64FiniAtom(*this, name)); - finiAtom->addReference(llvm::ELF::R_X86_64_64, 0, finiFunctionAtom, 0); + finiAtom->addReferenceELF_x86_64(llvm::ELF::R_X86_64_64, 0, + finiFunctionAtom, 0); finiAtom->setOrdinal(_ordinal++); addAtom(*finiFunctionAtom); addAtom(*finiAtom); @@ -112,87 +114,3 @@ return true; } -#define LLD_CASE(name) .Case(#name, llvm::ELF::name) - -ErrorOr -elf::X86_64LinkingContext::relocKindFromString(StringRef str) const { - int32_t ret = llvm::StringSwitch(str) LLD_CASE(R_X86_64_NONE) - LLD_CASE(R_X86_64_64) LLD_CASE(R_X86_64_PC32) LLD_CASE(R_X86_64_GOT32) - LLD_CASE(R_X86_64_PLT32) LLD_CASE(R_X86_64_COPY) - LLD_CASE(R_X86_64_GLOB_DAT) LLD_CASE(R_X86_64_JUMP_SLOT) - LLD_CASE(R_X86_64_RELATIVE) LLD_CASE(R_X86_64_GOTPCREL) - LLD_CASE(R_X86_64_32) LLD_CASE(R_X86_64_32S) LLD_CASE(R_X86_64_16) - LLD_CASE(R_X86_64_PC16) LLD_CASE(R_X86_64_8) LLD_CASE(R_X86_64_PC8) - LLD_CASE(R_X86_64_DTPMOD64) LLD_CASE(R_X86_64_DTPOFF64) - LLD_CASE(R_X86_64_TPOFF64) LLD_CASE(R_X86_64_TLSGD) - LLD_CASE(R_X86_64_TLSLD) LLD_CASE(R_X86_64_DTPOFF32) - LLD_CASE(R_X86_64_GOTTPOFF) LLD_CASE(R_X86_64_TPOFF32) - LLD_CASE(R_X86_64_PC64) LLD_CASE(R_X86_64_GOTOFF64) - LLD_CASE(R_X86_64_GOTPC32) LLD_CASE(R_X86_64_GOT64) - LLD_CASE(R_X86_64_GOTPCREL64) LLD_CASE(R_X86_64_GOTPC64) - LLD_CASE(R_X86_64_GOTPLT64) LLD_CASE(R_X86_64_PLTOFF64) - LLD_CASE(R_X86_64_SIZE32) LLD_CASE(R_X86_64_SIZE64) - LLD_CASE(R_X86_64_GOTPC32_TLSDESC) LLD_CASE(R_X86_64_TLSDESC_CALL) - LLD_CASE(R_X86_64_TLSDESC) LLD_CASE(R_X86_64_IRELATIVE) - .Case("LLD_R_X86_64_GOTRELINDEX", LLD_R_X86_64_GOTRELINDEX) - .Default(-1); - - if (ret == -1) - return make_error_code(YamlReaderError::illegal_value); - return ret; -} - -#undef LLD_CASE - -#define LLD_CASE(name) \ - case llvm::ELF::name: \ - return std::string(#name); - -ErrorOr -elf::X86_64LinkingContext::stringFromRelocKind(Reference::Kind kind) const { - switch (kind) { - LLD_CASE(R_X86_64_NONE) - LLD_CASE(R_X86_64_64) - LLD_CASE(R_X86_64_PC32) - LLD_CASE(R_X86_64_GOT32) - LLD_CASE(R_X86_64_PLT32) - LLD_CASE(R_X86_64_COPY) - LLD_CASE(R_X86_64_GLOB_DAT) - LLD_CASE(R_X86_64_JUMP_SLOT) - LLD_CASE(R_X86_64_RELATIVE) - LLD_CASE(R_X86_64_GOTPCREL) - LLD_CASE(R_X86_64_32) - LLD_CASE(R_X86_64_32S) - LLD_CASE(R_X86_64_16) - LLD_CASE(R_X86_64_PC16) - LLD_CASE(R_X86_64_8) - LLD_CASE(R_X86_64_PC8) - LLD_CASE(R_X86_64_DTPMOD64) - LLD_CASE(R_X86_64_DTPOFF64) - LLD_CASE(R_X86_64_TPOFF64) - LLD_CASE(R_X86_64_TLSGD) - LLD_CASE(R_X86_64_TLSLD) - LLD_CASE(R_X86_64_DTPOFF32) - LLD_CASE(R_X86_64_GOTTPOFF) - LLD_CASE(R_X86_64_TPOFF32) - LLD_CASE(R_X86_64_PC64) - LLD_CASE(R_X86_64_GOTOFF64) - LLD_CASE(R_X86_64_GOTPC32) - LLD_CASE(R_X86_64_GOT64) - LLD_CASE(R_X86_64_GOTPCREL64) - LLD_CASE(R_X86_64_GOTPC64) - LLD_CASE(R_X86_64_GOTPLT64) - LLD_CASE(R_X86_64_PLTOFF64) - LLD_CASE(R_X86_64_SIZE32) - LLD_CASE(R_X86_64_SIZE64) - LLD_CASE(R_X86_64_GOTPC32_TLSDESC) - LLD_CASE(R_X86_64_TLSDESC_CALL) - LLD_CASE(R_X86_64_TLSDESC) - LLD_CASE(R_X86_64_IRELATIVE) - case LLD_R_X86_64_GOTRELINDEX: - return std::string("LLD_R_X86_64_GOTRELINDEX"); - } - - return make_error_code(YamlReaderError::illegal_value); -} - Index: lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.h =================================================================== --- lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.h +++ lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.h @@ -30,6 +30,8 @@ virtual int64_t relocAddend(const Reference &) const; + static const Registry::KindStrings kindStrings[]; + private: // Cached size of the TLS segment. mutable uint64_t _tlsSize; Index: lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.cpp =================================================================== --- lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.cpp +++ lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.cpp @@ -47,8 +47,13 @@ // TODO: Make sure that the result sign extends to the 64bit value. } + + int64_t X86_64TargetRelocationHandler::relocAddend(const Reference &ref) const { - switch (ref.kind()) { + if (ref.kindNamespace() != Reference::KindNamespace::ELF) + return false; + assert(ref.kindArch() == Reference::KindArch::x86_64); + switch (ref.kindValue()) { case R_X86_64_PC32: return 4; default: @@ -65,7 +70,10 @@ uint64_t targetVAddress = writer.addressOfAtom(ref.target()); uint64_t relocVAddress = atom._virtualAddr + ref.offsetInAtom(); - switch (ref.kind()) { + if (ref.kindNamespace() != Reference::KindNamespace::ELF) + return error_code::success(); + assert(ref.kindArch() == Reference::KindArch::x86_64); + switch (ref.kindValue()) { case R_X86_64_NONE: break; case R_X86_64_64: @@ -86,7 +94,8 @@ case R_X86_64_TPOFF32: { _tlsSize = _context.getTargetHandler().targetLayout().getTLSSize(); - if (ref.kind() == R_X86_64_TPOFF32 || ref.kind() == R_X86_64_DTPOFF32) { + if (ref.kindValue() == R_X86_64_TPOFF32 || + ref.kindValue() == R_X86_64_DTPOFF32) { int32_t result = (int32_t)(targetVAddress - _tlsSize); *reinterpret_cast(location) = result; } else { @@ -106,7 +115,7 @@ case LLD_R_X86_64_GOTRELINDEX: { const DefinedAtom *target = cast(ref.target()); for (const Reference *r : *target) { - if (r->kind() == R_X86_64_JUMP_SLOT) { + if (r->kindValue() == R_X86_64_JUMP_SLOT) { uint32_t index; if (!_context.getTargetHandler().targetLayout() .getPLTRelocationTable()->getRelocationIndex(*r, index)) @@ -123,19 +132,12 @@ case R_X86_64_JUMP_SLOT: case R_X86_64_GLOB_DAT: break; - - case lld::Reference::kindLayoutAfter: - case lld::Reference::kindLayoutBefore: - case lld::Reference::kindInGroup: - break; - default: { std::string str; llvm::raw_string_ostream s(str); - auto name = _context.stringFromRelocKind(ref.kind()); s << "Unhandled relocation: " << atom._atom->file().path() << ":" << atom._atom->name() << "@" << ref.offsetInAtom() << " " - << (name ? *name : "") << " (" << ref.kind() << ")"; + << "#" << ref.kindValue(); s.flush(); llvm_unreachable(str.c_str()); } Index: lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.cpp =================================================================== --- lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.cpp +++ lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.cpp @@ -83,7 +83,7 @@ class ELFPassFile : public SimpleFile { public: - ELFPassFile(const ELFLinkingContext &eti) : SimpleFile(eti, "ELFPassFile") { + ELFPassFile(const ELFLinkingContext &eti) : SimpleFile("ELFPassFile") { setOrdinal(eti.getNextOrdinalAndIncrement()); } @@ -94,7 +94,10 @@ template class RelocationPass : public Pass { /// \brief Handle a specific reference. void handleReference(const DefinedAtom &atom, const Reference &ref) { - switch (ref.kind()) { + if (ref.kindNamespace() != Reference::KindNamespace::ELF) + return; + assert(ref.kindArch() == Reference::KindArch::x86_64); + switch (ref.kindValue()) { case R_X86_64_32: case R_X86_64_32S: case R_X86_64_64: @@ -126,9 +129,9 @@ if (plt != _pltMap.end()) return plt->second; auto ga = new (_file._alloc) X86_64GOTAtom(_file, ".got.plt"); - ga->addReference(R_X86_64_IRELATIVE, 0, da, 0); + ga->addReferenceELF_x86_64(R_X86_64_IRELATIVE, 0, da, 0); auto pa = new (_file._alloc) X86_64PLTAtom(_file, ".plt"); - pa->addReference(R_X86_64_PC32, 2, ga, -4); + pa->addReferenceELF_x86_64(R_X86_64_PC32, 2, ga, -4); #ifndef NDEBUG ga->_name = "__got_ifunc_"; ga->_name += da->name(); @@ -158,7 +161,7 @@ auto got = _gotMap.find(atom); if (got == _gotMap.end()) { auto g = new (_file._alloc) X86_64GOTAtom(_file, ".got"); - g->addReference(R_X86_64_TPOFF64, 0, atom, 0); + g->addReferenceELF_x86_64(R_X86_64_TPOFF64, 0, atom, 0); #ifndef NDEBUG g->_name = "__got_tls_"; g->_name += atom->name(); @@ -174,7 +177,7 @@ /// the GOT. void handleGOTTPOFF(const Reference &ref) { const_cast(ref).setTarget(getGOTTPOFF(ref.target())); - const_cast(ref).setKind(R_X86_64_PC32); + const_cast(ref).setKindValue(R_X86_64_PC32); } /// \brief Create a GOT entry containing 0. @@ -192,7 +195,7 @@ auto got = _gotMap.find(da); if (got == _gotMap.end()) { auto g = new (_file._alloc) X86_64GOTAtom(_file, ".got"); - g->addReference(R_X86_64_64, 0, da, 0); + g->addReferenceELF_x86_64(R_X86_64_64, 0, da, 0); #ifndef NDEBUG g->_name = "__got_"; g->_name += da->name(); @@ -302,11 +305,11 @@ error_code handlePLT32(const Reference &ref) { // __tls_get_addr is handled elsewhere. if (ref.target() && ref.target()->name() == "__tls_get_addr") { - const_cast(ref).setKind(R_X86_64_NONE); + const_cast(ref).setKindValue(R_X86_64_NONE); return error_code::success(); } else // Static code doesn't need PLTs. - const_cast(ref).setKind(R_X86_64_PC32); + const_cast(ref).setKindValue(R_X86_64_PC32); // Handle IFUNC. if (const DefinedAtom *da = dyn_cast_or_null(ref.target())) @@ -338,8 +341,8 @@ _PLT0 = new (_file._alloc) X86_64PLT0Atom(_file); _got0 = new (_file._alloc) X86_64GOTAtom(_file, ".got.plt"); _got1 = new (_file._alloc) X86_64GOTAtom(_file, ".got.plt"); - _PLT0->addReference(R_X86_64_PC32, 2, _got0, -4); - _PLT0->addReference(R_X86_64_PC32, 8, _got1, -4); + _PLT0->addReferenceELF_x86_64(R_X86_64_PC32, 2, _got0, -4); + _PLT0->addReferenceELF_x86_64(R_X86_64_PC32, 8, _got1, -4); #ifndef NDEBUG _got0->_name = "__got0"; _got1->_name = "__got1"; @@ -352,14 +355,14 @@ if (plt != _pltMap.end()) return plt->second; auto ga = new (_file._alloc) X86_64GOTAtom(_file, ".got.plt"); - ga->addReference(R_X86_64_JUMP_SLOT, 0, a, 0); + ga->addReferenceELF_x86_64(R_X86_64_JUMP_SLOT, 0, a, 0); auto pa = new (_file._alloc) X86_64PLTAtom(_file, ".plt"); - pa->addReference(R_X86_64_PC32, 2, ga, -4); - pa->addReference(LLD_R_X86_64_GOTRELINDEX, 7, ga, 0); - pa->addReference(R_X86_64_PC32, 12, getPLT0(), -4); + pa->addReferenceELF_x86_64(R_X86_64_PC32, 2, ga, -4); + pa->addReferenceELF_x86_64(LLD_R_X86_64_GOTRELINDEX, 7, ga, 0); + pa->addReferenceELF_x86_64(R_X86_64_PC32, 12, getPLT0(), -4); // Set the starting address of the got entry to the second instruction in // the plt entry. - ga->addReference(R_X86_64_64, 0, pa, 6); + ga->addReferenceELF_x86_64(R_X86_64_64, 0, pa, 6); #ifndef NDEBUG ga->_name = "__got_"; ga->_name += a->name(); @@ -380,7 +383,7 @@ auto oa = new (_file._alloc) ObjectAtom(_file); // This needs to point to the atom that we just created. - oa->addReference(R_X86_64_COPY, 0, oa, 0); + oa->addReferenceELF_x86_64(R_X86_64_COPY, 0, oa, 0); oa->_name = a->name(); oa->_size = a->size(); @@ -405,7 +408,7 @@ error_code handlePLT32(const Reference &ref) { // Turn this into a PC32 to the PLT entry. - const_cast(ref).setKind(R_X86_64_PC32); + const_cast(ref).setKindValue(R_X86_64_PC32); // Handle IFUNC. if (const DefinedAtom *da = dyn_cast_or_null(ref.target())) @@ -420,7 +423,7 @@ auto got = _gotMap.find(sla); if (got == _gotMap.end()) { auto g = new (_file._alloc) X86_64GOTAtom(_file, ".got.dyn"); - g->addReference(R_X86_64_GLOB_DAT, 0, sla, 0); + g->addReferenceELF_x86_64(R_X86_64_GLOB_DAT, 0, sla, 0); #ifndef NDEBUG g->_name = "__got_"; g->_name += sla->name(); Index: lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.h =================================================================== --- lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.h +++ lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.h @@ -27,6 +27,8 @@ public: X86_64TargetHandler(X86_64LinkingContext &targetInfo); + virtual void registerRelocationNames(Registry ®istry); + virtual TargetLayout &targetLayout() { return _targetLayout; } @@ -40,10 +42,11 @@ private: class GOTFile : public SimpleFile { public: - GOTFile(const ELFLinkingContext &eti) : SimpleFile(eti, "GOTFile") {} + GOTFile(const ELFLinkingContext &eti) : SimpleFile("GOTFile") {} llvm::BumpPtrAllocator _alloc; }; + static const Registry::KindStrings kindStrings[]; std::unique_ptr _gotFile; X86_64TargetRelocationHandler _relocationHandler; TargetLayout _targetLayout; Index: lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.cpp =================================================================== --- lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.cpp +++ lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.cpp @@ -27,3 +27,53 @@ result.push_back(std::move(_gotFile)); return true; } + +void X86_64TargetHandler::registerRelocationNames(Registry ®istry) { + registry.addKindTable(Reference::KindNamespace::ELF, + Reference::KindArch::x86_64, + kindStrings); +} + +const Registry::KindStrings X86_64TargetHandler::kindStrings[] = { + LLD_KIND_STRING_ENTRY(R_X86_64_NONE), + LLD_KIND_STRING_ENTRY(R_X86_64_64), + LLD_KIND_STRING_ENTRY(R_X86_64_PC32), + LLD_KIND_STRING_ENTRY(R_X86_64_GOT32), + LLD_KIND_STRING_ENTRY(R_X86_64_PLT32), + LLD_KIND_STRING_ENTRY(R_X86_64_COPY), + LLD_KIND_STRING_ENTRY(R_X86_64_GLOB_DAT), + LLD_KIND_STRING_ENTRY(R_X86_64_JUMP_SLOT), + LLD_KIND_STRING_ENTRY(R_X86_64_RELATIVE), + LLD_KIND_STRING_ENTRY(R_X86_64_GOTPCREL), + LLD_KIND_STRING_ENTRY(R_X86_64_32), + LLD_KIND_STRING_ENTRY(R_X86_64_32S), + LLD_KIND_STRING_ENTRY(R_X86_64_16), + LLD_KIND_STRING_ENTRY(R_X86_64_PC16), + LLD_KIND_STRING_ENTRY(R_X86_64_8), + LLD_KIND_STRING_ENTRY(R_X86_64_PC8), + LLD_KIND_STRING_ENTRY(R_X86_64_DTPMOD64), + LLD_KIND_STRING_ENTRY(R_X86_64_DTPOFF64), + LLD_KIND_STRING_ENTRY(R_X86_64_TPOFF64), + LLD_KIND_STRING_ENTRY(R_X86_64_TLSGD), + LLD_KIND_STRING_ENTRY(R_X86_64_TLSLD), + LLD_KIND_STRING_ENTRY(R_X86_64_DTPOFF32), + LLD_KIND_STRING_ENTRY(R_X86_64_TPOFF32), + LLD_KIND_STRING_ENTRY(R_X86_64_PC64), + LLD_KIND_STRING_ENTRY(R_X86_64_GOTOFF64), + LLD_KIND_STRING_ENTRY(R_X86_64_GOTPC32), + LLD_KIND_STRING_ENTRY(R_X86_64_GOT64), + LLD_KIND_STRING_ENTRY(R_X86_64_GOT64), + LLD_KIND_STRING_ENTRY(R_X86_64_GOTPCREL64), + LLD_KIND_STRING_ENTRY(R_X86_64_GOTPC64), + LLD_KIND_STRING_ENTRY(R_X86_64_GOTPLT64), + LLD_KIND_STRING_ENTRY(R_X86_64_PLTOFF64), + LLD_KIND_STRING_ENTRY(R_X86_64_SIZE32), + LLD_KIND_STRING_ENTRY(R_X86_64_SIZE64), + LLD_KIND_STRING_ENTRY(R_X86_64_GOTPC32_TLSDESC), + LLD_KIND_STRING_ENTRY(R_X86_64_TLSDESC_CALL), + LLD_KIND_STRING_ENTRY(R_X86_64_TLSDESC), + LLD_KIND_STRING_ENTRY(R_X86_64_IRELATIVE), + LLD_KIND_STRING_ENTRY(LLD_R_X86_64_GOTRELINDEX), + LLD_KIND_STRING_END +}; + Index: lib/ReaderWriter/FileArchive.cpp =================================================================== --- lib/ReaderWriter/FileArchive.cpp +++ lib/ReaderWriter/FileArchive.cpp @@ -1,155 +1,249 @@ -//===- lld/ReaderWriter/FileArchive.cpp - Archive Library File -----------===// +//===- lib/ReaderWriter/FileArchive.cpp -----------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // -//===---------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// -#include "lld/ReaderWriter/FileArchive.h" +#include "lld/Core/ArchiveLibraryFile.h" +#include "lld/Core/LLVM.h" #include "llvm/ADT/Hashing.h" -#include "llvm/Object/ObjectFile.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Object/Archive.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/Format.h" #include "llvm/Support/MemoryBuffer.h" #include +#include + +using llvm::object::Archive; +using llvm::object::ObjectFile; +using llvm::object::SymbolRef; +using llvm::object::symbol_iterator; +using llvm::object::object_error; namespace lld { -/// \brief Check if any member of the archive contains an Atom with the -/// specified name and return the File object for that member, or nullptr. -const File *FileArchive::find(StringRef name, bool dataSymbolOnly) const { - auto member = _symbolMemberMap.find(name); - if (member == _symbolMemberMap.end()) - return nullptr; +namespace { - llvm::object::Archive::child_iterator ci = member->second; +/// \brief The FileArchive class represents an Archive Library file +class FileArchive : public lld::ArchiveLibraryFile { +public: + + virtual ~FileArchive() { } + + /// \brief Check if any member of the archive contains an Atom with the + /// specified name and return the File object for that member, or nullptr. + virtual const File *find(StringRef name, bool dataSymbolOnly) const { + auto member = _symbolMemberMap.find(name); + if (member == _symbolMemberMap.end()) + return nullptr; + Archive::child_iterator ci = member->second; - if (dataSymbolOnly) { - OwningPtr buff; - if (ci->getMemoryBuffer(buff, true)) + // Don't return a member already returned + const char *memberStart = ci->getBuffer().data(); + if (_membersInstantiated.count(memberStart)) return nullptr; - if (isDataSymbol(buff.take(), name)) + + if (dataSymbolOnly) { + OwningPtr buff; + if (ci->getMemoryBuffer(buff, true)) + return nullptr; + if (isDataSymbol(buff.take(), name)) + return nullptr; + } + + std::vector> result; + if (instantiateMember(ci, result)) return nullptr; + assert(result.size() == 1); + + // give up the pointer so that this object no longer manages it + return result[0].release(); } - std::vector > result; + /// \brief Load all members of the archive ? + virtual bool isWholeArchive() const { return _isWholeArchive; } - OwningPtr buff; - if (ci->getMemoryBuffer(buff, true)) - return nullptr; - if (_context.logInputFiles()) - llvm::outs() << buff->getBufferIdentifier() << "\n"; - std::unique_ptr mb(buff.take()); - if (_context.getDefaultReader().parseFile(mb, result)) - return nullptr; + /// \brief parse each member + virtual error_code + parseAllMembers(std::vector> &result) const { + for (auto mf = _archive->begin_children(), + me = _archive->end_children(); mf != me; ++mf) { + if (error_code ec=instantiateMember(mf, result)) + return ec; + } + return error_code::success(); + } - assert(result.size() == 1); + virtual const atom_collection &defined() const { + return _definedAtoms; + } - // give up the pointer so that this object no longer manages it - return result[0].release(); -} + virtual const atom_collection &undefined() const { + return _undefinedAtoms; + } + + virtual const atom_collection &sharedLibrary() const { + return _sharedLibraryAtoms; + } + + virtual const atom_collection &absolute() const { + return _absoluteAtoms; + } -/// \brief parse each member -error_code FileArchive::parseAllMembers( - std::vector > &result) const { - for (auto mf = _archive->begin_children(), me = _archive->end_children(); - mf != me; ++mf) { +protected: + error_code instantiateMember(Archive::child_iterator member, + std::vector> &result) const { OwningPtr buff; - if (error_code ec = mf->getMemoryBuffer(buff, true)) + if (error_code ec=member->getMemoryBuffer(buff, true)) return ec; - if (_context.logInputFiles()) + if (_logLoading) llvm::outs() << buff->getBufferIdentifier() << "\n"; - std::unique_ptr mbc(buff.take()); - if (error_code ec = _context.getDefaultReader().parseFile(mbc, result)) - return ec; + std::unique_ptr mb(buff.take()); + _registry.parseFile(mb, result); + const char *memberStart = member->getBuffer().data(); + _membersInstantiated.insert(memberStart); + return error_code::success(); } - return error_code::success(); -} -const ArchiveLibraryFile::atom_collection & -FileArchive::defined() const { - return _definedAtoms; -} - -const ArchiveLibraryFile::atom_collection & -FileArchive::undefined() const { - return _undefinedAtoms; -} -const ArchiveLibraryFile::atom_collection & -FileArchive::sharedLibrary() const { - return _sharedLibraryAtoms; -} + error_code isDataSymbol(MemoryBuffer *mb, StringRef symbol) const { + std::unique_ptr + obj(ObjectFile::createObjectFile(mb)); + error_code ec; + SymbolRef::Type symtype; + uint32_t symflags; + symbol_iterator ibegin = obj->begin_symbols(); + symbol_iterator iend = obj->end_symbols(); + StringRef symbolname; + + for (symbol_iterator i = ibegin; i != iend; i.increment(ec)) { + if (ec) return ec; + + // Get symbol name + if ((ec = (i->getName(symbolname)))) return ec; + + if (symbolname != symbol) + continue; + + // Get symbol flags + if ((ec = (i->getFlags(symflags)))) return ec; + + if (symflags <= SymbolRef::SF_Undefined) + continue; + + // Get Symbol Type + if ((ec = (i->getType(symtype)))) return ec; + + if (symtype == SymbolRef::ST_Data) { + return error_code::success(); + } + } + return object_error::parse_failed; + } -const ArchiveLibraryFile::atom_collection & -FileArchive::absolute() const { - return _absoluteAtoms; -} +private: + typedef std::unordered_map MemberMap; + typedef std::set InstantiatedSet; + + const Registry &_registry; + std::unique_ptr _archive; + mutable MemberMap _symbolMemberMap; + mutable InstantiatedSet _membersInstantiated; + atom_collection_vector _definedAtoms; + atom_collection_vector _undefinedAtoms; + atom_collection_vector _sharedLibraryAtoms; + atom_collection_vector _absoluteAtoms; + bool _isWholeArchive; + bool _logLoading; + +public: + /// only subclasses of ArchiveLibraryFile can be instantiated + FileArchive(const Registry ®istry, + Archive* archive, + StringRef path, + bool isWholeArchive, + bool logLoading) + : ArchiveLibraryFile(path), + _registry(registry), + _archive(std::move(archive)), + _isWholeArchive(isWholeArchive), + _logLoading(logLoading) { + } -error_code FileArchive::isDataSymbol(MemoryBuffer *mb, StringRef symbol) const { - std::unique_ptr obj( - llvm::object::ObjectFile::createObjectFile(mb)); - error_code ec; - llvm::object::SymbolRef::Type symtype; - uint32_t symflags; - llvm::object::symbol_iterator ibegin = obj->begin_symbols(); - llvm::object::symbol_iterator iend = obj->end_symbols(); - StringRef symbolname; + error_code buildTableOfContents() { + DEBUG_WITH_TYPE("FileArchive", + llvm::dbgs() << "Table of contents for archive '" + << _archive->getFileName() << "':\n"); + for (auto i = _archive->begin_symbols(), e = _archive->end_symbols(); + i != e; ++i) { + StringRef name; + error_code ec; + Archive::child_iterator member; + if ((ec = i->getName(name))) + return ec; + if ((ec = i->getMember(member))) + return ec; + DEBUG_WITH_TYPE("FileArchive", + llvm::dbgs() << llvm::format("0x%08llX ", member->getBuffer().data()) + << "'" << name << "'\n"); + _symbolMemberMap[name] = member; + } + return error_code::success(); + } - for (llvm::object::symbol_iterator i = ibegin; i != iend; i.increment(ec)) { - if (ec) - return ec; +}; // class FileArchive - // Get symbol name - if (error_code ec = i->getName(symbolname)) - return ec; - if (symbolname != symbol) - continue; - // Get symbol flags - if (error_code ec = i->getFlags(symflags)) +class ArchiveReader : public Reader { +public: + ArchiveReader(bool logLoading) : _logLoading(logLoading) { } + + virtual bool canParse(file_magic magic, StringRef, const MemoryBuffer&) const{ + return (magic == llvm::sys::fs::file_magic::archive); + } + + virtual error_code + parseFile(std::unique_ptr &mb, const Registry ®, + std::vector> &result) const { + // Make Archive object which will be owned by FileArchive object. + error_code ec; + Archive* archive = new Archive(mb.get(), ec); + if (ec) + return ec; + StringRef path = mb->getBufferIdentifier(); + // Construct FileArchive object. + std::unique_ptr file(new FileArchive(reg, archive, + path, false, _logLoading)); + ec = file->buildTableOfContents(); + if (ec) return ec; + + // Transfer ownership of memory buffer to Archive object. + mb.release(); + + result.push_back(std::move(file)); + return error_code::success(); + } +private: + bool _logLoading; +}; - if (symflags <= llvm::object::SymbolRef::SF_Undefined) - continue; - // Get Symbol Type - if (error_code ec = i->getType(symtype)) - return ec; +} // anonymous namespace - if (symtype == llvm::object::SymbolRef::ST_Data) { - return error_code::success(); - } - } - return llvm::object::object_error::parse_failed; -} -FileArchive::FileArchive(const LinkingContext &context, - std::unique_ptr mb, error_code &ec, - bool isWholeArchive) - : ArchiveLibraryFile(context, mb->getBufferIdentifier()), - _isWholeArchive(isWholeArchive) { - std::unique_ptr archive_obj( - new llvm::object::Archive(mb.release(), ec)); - if (ec) - return; - _archive.swap(archive_obj); - - // Cache symbols. - for (auto i = _archive->begin_symbols(), e = _archive->end_symbols(); i != e; - ++i) { - StringRef name; - llvm::object::Archive::child_iterator member; - if ((ec = i->getName(name))) - return; - if ((ec = i->getMember(member))) - return; - _symbolMemberMap[name] = member; - } +void Registry::addSupportArchives(bool logLoading) { + add(std::unique_ptr(new ArchiveReader(logLoading))); } } // end namespace lld + + Index: lib/ReaderWriter/MachO/ExecutableAtoms.hpp =================================================================== --- lib/ReaderWriter/MachO/ExecutableAtoms.hpp +++ lib/ReaderWriter/MachO/ExecutableAtoms.hpp @@ -30,7 +30,7 @@ class CRuntimeFile : public SimpleFile { public: CRuntimeFile(const MachOLinkingContext &context) - : SimpleFile(context, "C runtime"), + : SimpleFile("C runtime"), _undefMain(*this, context.entrySymbolName()) { // only main executables need _main if (context.outputFileType() == llvm::MachO::MH_EXECUTE) { Index: lib/ReaderWriter/MachO/GOTPass.hpp =================================================================== --- lib/ReaderWriter/MachO/GOTPass.hpp +++ lib/ReaderWriter/MachO/GOTPass.hpp @@ -29,7 +29,7 @@ return true; } - virtual bool isGOTAccess(int32_t, bool& canBypassGOT) { + virtual bool isGOTAccess(const Reference&, bool& canBypassGOT) { return false; } Index: lib/ReaderWriter/MachO/MachOLinkingContext.cpp =================================================================== --- lib/ReaderWriter/MachO/MachOLinkingContext.cpp +++ lib/ReaderWriter/MachO/MachOLinkingContext.cpp @@ -16,7 +16,6 @@ #include "lld/ReaderWriter/Reader.h" #include "lld/ReaderWriter/Writer.h" #include "lld/Passes/LayoutPass.h" -#include "lld/Passes/RoundTripNativePass.h" #include "lld/Passes/RoundTripYAMLPass.h" #include "llvm/ADT/StringExtras.h" @@ -93,6 +92,15 @@ return arch_unknown; } +StringRef MachOLinkingContext::nameFromArch(Arch arch) { + for (ArchInfo *info = _s_archInfos; !info->archName.empty(); ++info) { + if (info->arch == arch) + return info->archName; + } + return ""; +} + + uint32_t MachOLinkingContext::cpuTypeFromArch(Arch arch) { assert(arch != arch_unknown); for (ArchInfo *info = _s_archInfos; !info->archName.empty(); ++info) { @@ -293,14 +301,5 @@ return *_kindHandler; } -ErrorOr -MachOLinkingContext::relocKindFromString(StringRef str) const { - return kindHandler().stringToKind(str); -} - -ErrorOr -MachOLinkingContext::stringFromRelocKind(Reference::Kind kind) const { - return std::string(kindHandler().kindToString(kind)); -} } // end namespace lld Index: lib/ReaderWriter/MachO/MachONormalizedFile.h =================================================================== --- lib/ReaderWriter/MachO/MachONormalizedFile.h +++ lib/ReaderWriter/MachO/MachONormalizedFile.h @@ -260,7 +260,7 @@ /// Takes in-memory normalized dylib or object and parses it into lld::File ErrorOr> -normalizedToAtoms(const NormalizedFile &normalizedFile); +normalizedToAtoms(const NormalizedFile &normalizedFile, StringRef path); /// Takes atoms and generates a normalized macho-o view. ErrorOr> Index: lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp =================================================================== --- lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp +++ lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp @@ -23,6 +23,7 @@ #include "MachONormalizedFile.h" #include "MachONormalizedFileBinaryUtils.h" +#include "ReferenceKinds.h" #include "lld/Core/Error.h" #include "lld/Core/LLVM.h" @@ -306,5 +307,31 @@ } // namespace normalized } // namespace mach_o + +void Registry::addSupportMachOObjects(StringRef archName) { + MachOLinkingContext::Arch arch = MachOLinkingContext::archFromName(archName); + switch (arch) { + case MachOLinkingContext::arch_x86_64: + addKindTable(Reference::KindNamespace::mach_o, + Reference::KindArch::x86_64, + mach_o::KindHandler_x86_64::kindStrings); + break; + case MachOLinkingContext::arch_x86: + addKindTable(Reference::KindNamespace::mach_o, + Reference::KindArch::x86, + mach_o::KindHandler_x86::kindStrings); + break; + case MachOLinkingContext::arch_armv6: + case MachOLinkingContext::arch_armv7: + case MachOLinkingContext::arch_armv7s: + addKindTable(Reference::KindNamespace::mach_o, + Reference::KindArch::ARM, + mach_o::KindHandler_arm::kindStrings); + break; + default: + llvm_unreachable("mach-o arch not supported"); + } +} + } // namespace lld Index: lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp =================================================================== --- lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp +++ lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp @@ -436,7 +436,8 @@ if ( ref->target() != nullptr ) targetAddress = _atomToAddress[ref->target()]; uint64_t fixupAddress = _atomToAddress[ai.atom] + offset; - _context.kindHandler().applyFixup(ref->kind(), ref->addend(), + _context.kindHandler().applyFixup(ref->kindNamespace(), ref->kindArch(), + ref->kindValue(), ref->addend(), &atomContent[offset], fixupAddress, targetAddress); } @@ -578,7 +579,7 @@ const Atom *Util::targetOfLazyPointer(const DefinedAtom *lpAtom) { for (const Reference *ref : *lpAtom) { - if (_context.kindHandler().isLazyTarget(ref->kind())) { + if (_context.kindHandler().isLazyTarget(*ref)) { return ref->target(); } } @@ -736,7 +737,7 @@ uint64_t segmentOffset = _atomToAddress[atom] + ref->offsetInAtom() - segmentStartAddr; const Atom* targ = ref->target(); - if (_context.kindHandler().isPointer(ref->kind())) { + if (_context.kindHandler().isPointer(*ref)) { // A pointer to a DefinedAtom requires rebasing. if (dyn_cast(targ)) { RebaseLocation rebase; @@ -758,7 +759,7 @@ nFile.bindingInfo.push_back(bind); } } - if (_context.kindHandler().isLazyTarget(ref->kind())) { + if (_context.kindHandler().isLazyTarget(*ref)) { BindLocation bind; bind.segIndex = segmentIndex; bind.segOffset = segmentOffset; Index: lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp =================================================================== --- lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp +++ lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp @@ -19,6 +19,7 @@ #include "lld/Core/Error.h" #include "lld/Core/LLVM.h" +#include "lld/ReaderWriter/YamlContext.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" @@ -40,7 +41,7 @@ using namespace llvm::yaml; using namespace llvm::MachO; using namespace lld::mach_o::normalized; - +using lld::YamlContext; LLVM_YAML_IS_SEQUENCE_VECTOR(Segment); LLVM_YAML_IS_SEQUENCE_VECTOR(DependentDylib); @@ -303,7 +304,9 @@ template <> struct ScalarEnumerationTraits { static void enumeration(IO &io, RelocationInfoType &value) { - NormalizedFile *file = reinterpret_cast(io.getContext()); + YamlContext *info = reinterpret_cast(io.getContext()); + assert(info != nullptr); + NormalizedFile *file = info->_normalizeMachOFile; assert(file != nullptr); switch (file->arch) { case lld::MachOLinkingContext::arch_x86_64: @@ -574,6 +577,9 @@ io.mapOptional("lazy-bindings", file.lazyBindingInfo); io.mapOptional("exports", file.exportInfo); } + static StringRef validate(IO &io, NormalizedFile &file) { + return StringRef(); + } }; } // namespace llvm @@ -591,7 +597,9 @@ std::unique_ptr f(new NormalizedFile()); // Create YAML Input parser. - llvm::yaml::Input yin(mb->getBuffer(), f.get()); + YamlContext yamlContext; + yamlContext._normalizeMachOFile = f.get(); + llvm::yaml::Input yin(mb->getBuffer(), &yamlContext); // Fill NormalizedFile by parsing yaml. yin >> *f; @@ -612,7 +620,9 @@ NormalizedFile *f = const_cast(&file); // Create yaml Output writer, using yaml options for context. - llvm::yaml::Output yout(out, f); + YamlContext yamlContext; + yamlContext._normalizeMachOFile = f; + llvm::yaml::Output yout(out, &yamlContext); // Stream out yaml. yout << *f; Index: lib/ReaderWriter/MachO/ReferenceKinds.h =================================================================== --- lib/ReaderWriter/MachO/ReferenceKinds.h +++ lib/ReaderWriter/MachO/ReferenceKinds.h @@ -20,6 +20,32 @@ namespace lld { namespace mach_o { +// Additional Reference Kind values used internally. +enum { + LLD_X86_64_RELOC_GOT_LOAD_NOW_LEA = 100, + LLD_X86_64_RELOC_TLV_NOW_LEA = 101, + LLD_X86_64_RELOC_LAZY_TARGET = 102, + LLD_X86_64_RELOC_LAZY_IMMEDIATE = 103, + LLD_X86_64_RELOC_SIGNED_32 = 104, +}; +enum { + LLD_X86_RELOC_BRANCH32 = 100, // CALL or JMP 32-bit pc-rel + LLD_X86_RELOC_ABS32 = 101, // 32-bit absolute addr in instruction + LLD_X86_RELOC_FUNC_REL32 = 102, // 32-bit target from start of func + LLD_X86_RELOC_POINTER32 = 103, // 32-bit data pointer + LLD_X86_RELOC_LAZY_TARGET = 104, + LLD_X86_RELOC_LAZY_IMMEDIATE = 105 +}; +enum { + LLD_ARM_RELOC_THUMB_ABS_LO16 = 100, // thumb movw of absolute address + LLD_ARM_RELOC_THUMB_ABS_HI16 = 101, // thumb movt of absolute address + LLD_ARM_RELOC_THUMB_REL_LO16 = 102, // thumb movw of (target - pc) + LLD_ARM_RELOC_THUMB_REL_HI16 = 103, // thumb movt of (target - pc) + LLD_ARM_RELOC_ABS32 = 104, // 32-bit constant pointer + LLD_ARM_RELOC_POINTER32 = 105, // 32-bit data pointer + LLD_ARM_RELOC_LAZY_TARGET = 106, + LLD_ARM_RELOC_LAZY_IMMEDIATE = 107, +}; /// /// The KindHandler class is the abstract interface to Reference::Kind @@ -28,18 +54,19 @@ /// class KindHandler { public: - typedef Reference::Kind Kind; static std::unique_ptr create(MachOLinkingContext::Arch); virtual ~KindHandler(); - virtual Kind stringToKind(StringRef str) = 0; - virtual StringRef kindToString(Kind) = 0; - virtual bool isCallSite(Kind) = 0; - virtual bool isPointer(Kind) = 0; - virtual bool isLazyImmediate(Kind) = 0; - virtual bool isLazyTarget(Kind) = 0; - virtual void applyFixup(Kind kind, uint64_t addend, uint8_t *location, - uint64_t fixupAddress, uint64_t targetAddress) = 0; + + virtual bool isCallSite(const Reference&) = 0; + virtual bool isPointer(const Reference&) = 0; + virtual bool isLazyImmediate(const Reference&) = 0; + virtual bool isLazyTarget(const Reference&) = 0; + virtual void applyFixup(Reference::KindNamespace ns, + Reference::KindArch arch, uint16_t kindValue, + uint64_t addend, uint8_t *location, + uint64_t fixupAddress, + uint64_t targetAddress) = 0; protected: KindHandler(); @@ -49,94 +76,52 @@ class KindHandler_x86_64 : public KindHandler { public: - enum Kinds { - invalid, // used to denote an error creating a Reference - none, - branch32, // CALL or JMP 32-bit pc-rel - ripRel32, // RIP-rel access pc-rel to fix up location - ripRel32_1, // RIP-rel access pc-rel to fix up location + 1 - ripRel32_2, // RIP-rel access pc-rel to fix up location + 2 - ripRel32_4, // RIP-rel access pc-rel to fix up location + 4 - gotLoadRipRel32, // RIP-rel load of GOT slot (can be optimized) - gotLoadRipRel32NowLea, // RIP-rel movq load of GOT slot optimized to LEA - gotUseRipRel32, // RIP-rel non-load of GOT slot (not a movq load of GOT) - tlvLoadRipRel32, // RIP-rel load of thread local pointer (can be optimized) - tlvLoadRipRel32NowLea, // RIP-rel movq load of TLV pointer optimized to LEA - pointer64, // 64-bit data pointer - pointerRel32, // 32-bit pc-rel offset - lazyTarget, // Used in lazy pointers to reference ultimate target - lazyImmediate, // Location in stub where lazy info offset to be stored - subordinateFDE, // Reference to unwind info for this function - subordinateLSDA // Reference to excecption info for this function - }; + static const Registry::KindStrings kindStrings[]; + virtual ~KindHandler_x86_64(); - virtual Kind stringToKind(StringRef str); - virtual StringRef kindToString(Kind); - virtual bool isCallSite(Kind); - virtual bool isPointer(Kind); - virtual bool isLazyImmediate(Kind); - virtual bool isLazyTarget(Kind); - virtual void applyFixup(Kind kind, uint64_t addend, uint8_t *location, - uint64_t fixupAddress, uint64_t targetAddress); - + virtual bool isCallSite(const Reference&); + virtual bool isPointer(const Reference&); + virtual bool isLazyImmediate(const Reference&); + virtual bool isLazyTarget(const Reference&); + virtual void applyFixup(Reference::KindNamespace ns, + Reference::KindArch arch, uint16_t kindValue, + uint64_t addend, uint8_t *location, + uint64_t fixupAddress, uint64_t targetAddress); }; class KindHandler_x86 : public KindHandler { public: - enum Kinds { - invalid, // used to denote an error creating a Reference - none, - branch32, // CALL or JMP 32-bit pc-rel - abs32, // 32-bit absolute address embedded in instruction - funcRel32, // 32-bit offset to target from start of function - pointer32, // 32-bit data pointer - lazyTarget, // Used in lazy pointers to reference ultimate target - lazyImmediate, // Location in stub where lazy info offset to be stored - subordinateFDE, // Reference to unwind info for this function - subordinateLSDA // Reference to excecption info for this function - }; + + static const Registry::KindStrings kindStrings[]; virtual ~KindHandler_x86(); - virtual Kind stringToKind(StringRef str); - virtual StringRef kindToString(Kind); - virtual bool isCallSite(Kind); - virtual bool isPointer(Kind); - virtual bool isLazyImmediate(Kind); - virtual bool isLazyTarget(Kind); - virtual void applyFixup(Kind kind, uint64_t addend, uint8_t *location, - uint64_t fixupAddress, uint64_t targetAddress); + virtual bool isCallSite(const Reference&); + virtual bool isPointer(const Reference&); + virtual bool isLazyImmediate(const Reference&); + virtual bool isLazyTarget(const Reference&); + virtual void applyFixup(Reference::KindNamespace ns, + Reference::KindArch arch, uint16_t kindValue, + uint64_t addend, uint8_t *location, + uint64_t fixupAddress, uint64_t targetAddress); }; class KindHandler_arm : public KindHandler { public: - enum Kinds { - invalid, // used to denote an error creating a Reference - none, - thumbBranch22, // thumb b or bl with 22/24-bits of displacement - armBranch24, // arm b or bl with 24-bits of displacement - thumbAbsLow16, // thumb movw of absolute address - thumbAbsHigh16, // thumb movt of absolute address - thumbPcRelLow16, // thumb movw of (target - pc) - thumbPcRelHigh16,// thumb movt of (target - pc) - abs32, // 32-bit absolute address embedded in instructions - pointer32, // 32-bit data pointer - lazyTarget, // Used in lazy pointers to reference ultimate target - lazyImmediate, // Location in stub where lazy info offset to be stored - subordinateLSDA // Reference to excecption info for this function - }; + + static const Registry::KindStrings kindStrings[]; virtual ~KindHandler_arm(); - virtual Kind stringToKind(StringRef str); - virtual StringRef kindToString(Kind); - virtual bool isCallSite(Kind); - virtual bool isPointer(Kind); - virtual bool isLazyImmediate(Kind); - virtual bool isLazyTarget(Kind); - virtual void applyFixup(Kind kind, uint64_t addend, uint8_t *location, - uint64_t fixupAddress, uint64_t targetAddress); + virtual bool isCallSite(const Reference&); + virtual bool isPointer(const Reference&); + virtual bool isLazyImmediate(const Reference&); + virtual bool isLazyTarget(const Reference&); + virtual void applyFixup(Reference::KindNamespace ns, + Reference::KindArch arch, uint16_t kindValue, + uint64_t addend, uint8_t *location, + uint64_t fixupAddress, uint64_t targetAddress); }; Index: lib/ReaderWriter/MachO/ReferenceKinds.cpp =================================================================== --- lib/ReaderWriter/MachO/ReferenceKinds.cpp +++ lib/ReaderWriter/MachO/ReferenceKinds.cpp @@ -17,6 +17,8 @@ #include "llvm/Support/ErrorHandling.h" +using namespace llvm::MachO; + namespace lld { namespace mach_o { @@ -46,7 +48,6 @@ } } - //===----------------------------------------------------------------------===// // KindHandler_x86_64 //===----------------------------------------------------------------------===// @@ -54,133 +55,87 @@ KindHandler_x86_64::~KindHandler_x86_64() { } -Reference::Kind KindHandler_x86_64::stringToKind(StringRef str) { - return llvm::StringSwitch(str) - .Case("none", none) - .Case("branch32", branch32) - .Case("ripRel32", ripRel32) - .Case("ripRel32_1", ripRel32_1) - .Case("ripRel32_2", ripRel32_2) - .Case("ripRel32_4", ripRel32_4) - .Case("gotLoadRipRel32", gotLoadRipRel32) - .Case("gotLoadRipRel32NowLea", gotLoadRipRel32NowLea) - .Case("gotUseRipRel32", gotUseRipRel32) - .Case("tlvLoadRipRel32", tlvLoadRipRel32) - .Case("tlvLoadRipRel32NowLea", tlvLoadRipRel32NowLea) - .Case("pointer64", pointer64) - .Case("pointerRel32", pointerRel32) - .Case("lazyTarget", lazyTarget) - .Case("lazyImmediate", lazyImmediate) - .Case("subordinateFDE", subordinateFDE) - .Case("subordinateLSDA", subordinateLSDA) - .Default(invalid); - - llvm_unreachable("invalid x86_64 Reference kind"); -} - -StringRef KindHandler_x86_64::kindToString(Reference::Kind kind) { - switch ( (Kinds)kind ) { - case invalid: - return StringRef("invalid"); - case none: - return StringRef("none"); - case branch32: - return StringRef("branch32"); - case ripRel32: - return StringRef("ripRel32"); - case ripRel32_1: - return StringRef("ripRel32_1"); - case ripRel32_2: - return StringRef("ripRel32_2"); - case ripRel32_4: - return StringRef("ripRel32_4"); - case gotLoadRipRel32: - return StringRef("gotLoadRipRel32"); - case gotLoadRipRel32NowLea: - return StringRef("gotLoadRipRel32NowLea"); - case gotUseRipRel32: - return StringRef("gotUseRipRel32"); - case tlvLoadRipRel32: - return StringRef("tlvLoadRipRel32"); - case tlvLoadRipRel32NowLea: - return StringRef("tlvLoadRipRel32NowLea"); - case pointer64: - return StringRef("pointer64"); - case pointerRel32: - return StringRef("pointerRel32"); - case lazyTarget: - return StringRef("lazyTarget"); - case lazyImmediate: - return StringRef("lazyImmediate"); - case subordinateFDE: - return StringRef("subordinateFDE"); - case subordinateLSDA: - return StringRef("subordinateLSDA"); - } - llvm_unreachable("invalid x86_64 Reference kind"); -} -bool KindHandler_x86_64::isCallSite(Kind kind) { - return (kind == branch32); +const Registry::KindStrings KindHandler_x86_64::kindStrings[] = { + LLD_KIND_STRING_ENTRY(X86_64_RELOC_UNSIGNED), + LLD_KIND_STRING_ENTRY(X86_64_RELOC_BRANCH), + LLD_KIND_STRING_ENTRY(X86_64_RELOC_SIGNED), + LLD_KIND_STRING_ENTRY(X86_64_RELOC_SIGNED_1), + LLD_KIND_STRING_ENTRY(X86_64_RELOC_SIGNED_2), + LLD_KIND_STRING_ENTRY(X86_64_RELOC_SIGNED_4), + LLD_KIND_STRING_ENTRY(X86_64_RELOC_GOT_LOAD), + LLD_KIND_STRING_ENTRY(X86_64_RELOC_GOT), + LLD_KIND_STRING_ENTRY(X86_64_RELOC_TLV), + LLD_KIND_STRING_ENTRY(LLD_X86_64_RELOC_GOT_LOAD_NOW_LEA), + LLD_KIND_STRING_ENTRY(LLD_X86_64_RELOC_TLV_NOW_LEA), + LLD_KIND_STRING_ENTRY(LLD_X86_64_RELOC_LAZY_TARGET), + LLD_KIND_STRING_ENTRY(LLD_X86_64_RELOC_LAZY_IMMEDIATE), + LLD_KIND_STRING_END +}; + +bool KindHandler_x86_64::isCallSite(const Reference &ref) { + return (ref.kindValue() == X86_64_RELOC_BRANCH); } -bool KindHandler_x86_64::isPointer(Kind kind) { - return (kind == pointer64); +bool KindHandler_x86_64::isPointer(const Reference &ref) { + return (ref.kindValue() == X86_64_RELOC_UNSIGNED); } -bool KindHandler_x86_64::isLazyImmediate(Kind kind) { - return (kind == lazyImmediate); +bool KindHandler_x86_64::isLazyImmediate(const Reference &ref) { + return (ref.kindValue() == LLD_X86_64_RELOC_LAZY_IMMEDIATE); } -bool KindHandler_x86_64::isLazyTarget(Kind kind) { - return (kind == lazyTarget); +bool KindHandler_x86_64::isLazyTarget(const Reference &ref) { + return (ref.kindValue() == LLD_X86_64_RELOC_LAZY_TARGET); } -void KindHandler_x86_64::applyFixup(Kind kind, uint64_t addend, +void KindHandler_x86_64::applyFixup(Reference::KindNamespace ns, + Reference::KindArch arch, uint16_t kindValue, + uint64_t addend, uint8_t *location, uint64_t fixupAddress, uint64_t targetAddress) { + if (ns != Reference::KindNamespace::mach_o) + return; + assert(arch == Reference::KindArch::x86_64); int32_t *loc32 = reinterpret_cast(location); uint64_t* loc64 = reinterpret_cast(location); - switch ( (Kinds)kind ) { - case branch32: - case ripRel32: - case gotLoadRipRel32: - case gotUseRipRel32: - case tlvLoadRipRel32: + switch ( kindValue ) { + case X86_64_RELOC_BRANCH: + case X86_64_RELOC_SIGNED: + case X86_64_RELOC_GOT_LOAD: + case X86_64_RELOC_GOT: + case X86_64_RELOC_TLV: *loc32 = (targetAddress - (fixupAddress+4)) + addend; break; - case pointer64: + case X86_64_RELOC_UNSIGNED: *loc64 = targetAddress + addend; break; - case ripRel32_1: + case X86_64_RELOC_SIGNED_1: *loc32 = (targetAddress - (fixupAddress+5)) + addend; break; - case ripRel32_2: + case X86_64_RELOC_SIGNED_2: *loc32 = (targetAddress - (fixupAddress+6)) + addend; break; - case ripRel32_4: + case X86_64_RELOC_SIGNED_4: *loc32 = (targetAddress - (fixupAddress+8)) + addend; break; - case pointerRel32: + case LLD_X86_64_RELOC_SIGNED_32: *loc32 = (targetAddress - fixupAddress) + addend; break; - case gotLoadRipRel32NowLea: - case tlvLoadRipRel32NowLea: + case LLD_X86_64_RELOC_GOT_LOAD_NOW_LEA: + case LLD_X86_64_RELOC_TLV_NOW_LEA: // Change MOVQ to LEA assert(location[-2] == 0x8B); location[-2] = 0x8D; *loc32 = (targetAddress - (fixupAddress+4)) + addend; break; - case none: - case lazyTarget: - case lazyImmediate: - case subordinateFDE: - case subordinateLSDA: + case LLD_X86_64_RELOC_LAZY_TARGET: + case LLD_X86_64_RELOC_LAZY_IMMEDIATE: // do nothing break; - case invalid: - assert(0 && "invalid Reference Kind"); + default: + llvm_unreachable("invalid x86_64 Reference Kind"); break; } } @@ -193,88 +148,61 @@ KindHandler_x86::~KindHandler_x86() { } -Reference::Kind KindHandler_x86::stringToKind(StringRef str) { - return llvm::StringSwitch(str) - .Case("none", none) - .Case("branch32", branch32) - .Case("abs32", abs32) - .Case("funcRel32", funcRel32) - .Case("pointer32", pointer32) - .Case("lazyTarget", lazyTarget) - .Case("lazyImmediate", lazyImmediate) - .Default(invalid); - - llvm_unreachable("invalid x86 Reference kind"); -} - -StringRef KindHandler_x86::kindToString(Reference::Kind kind) { - switch ( (Kinds)kind ) { - case invalid: - return StringRef("invalid"); - case none: - return StringRef("none"); - case branch32: - return StringRef("branch32"); - case abs32: - return StringRef("abs32"); - case funcRel32: - return StringRef("funcRel32"); - case pointer32: - return StringRef("pointer32"); - case lazyTarget: - return StringRef("lazyTarget"); - case lazyImmediate: - return StringRef("lazyImmediate"); - case subordinateFDE: - return StringRef("subordinateFDE"); - case subordinateLSDA: - return StringRef("subordinateLSDA"); - } - llvm_unreachable("invalid x86 Reference kind"); -} +const Registry::KindStrings KindHandler_x86::kindStrings[] = { + LLD_KIND_STRING_ENTRY(LLD_X86_RELOC_BRANCH32), + LLD_KIND_STRING_ENTRY(LLD_X86_RELOC_ABS32), + LLD_KIND_STRING_ENTRY(LLD_X86_RELOC_FUNC_REL32), + LLD_KIND_STRING_ENTRY(LLD_X86_RELOC_POINTER32), + LLD_KIND_STRING_ENTRY(LLD_X86_RELOC_LAZY_TARGET), + LLD_KIND_STRING_ENTRY(LLD_X86_RELOC_LAZY_IMMEDIATE), + LLD_KIND_STRING_END +}; -bool KindHandler_x86::isCallSite(Kind kind) { - return (kind == branch32); +bool KindHandler_x86::isCallSite(const Reference &ref) { + return (ref.kindValue() == LLD_X86_RELOC_BRANCH32); } -bool KindHandler_x86::isPointer(Kind kind) { - return (kind == pointer32); +bool KindHandler_x86::isPointer(const Reference &ref) { + return (ref.kindValue() == LLD_X86_RELOC_POINTER32); } -bool KindHandler_x86::isLazyImmediate(Kind kind) { - return (kind == lazyImmediate); +bool KindHandler_x86::isLazyImmediate(const Reference &ref) { + return (ref.kindValue() == LLD_X86_RELOC_LAZY_TARGET); } -bool KindHandler_x86::isLazyTarget(Kind kind) { - return (kind == lazyTarget); +bool KindHandler_x86::isLazyTarget(const Reference &ref) { + return (ref.kindValue() == LLD_X86_RELOC_LAZY_TARGET); } -void KindHandler_x86::applyFixup(Kind kind, uint64_t addend, uint8_t *location, - uint64_t fixupAddress, uint64_t targetAddress) { +void KindHandler_x86::applyFixup(Reference::KindNamespace ns, + Reference::KindArch arch, uint16_t kindValue, + uint64_t addend, uint8_t *location, + uint64_t fixupAddress, + uint64_t targetAddress) { + if (ns != Reference::KindNamespace::mach_o) + return; + assert(arch == Reference::KindArch::x86); int32_t *loc32 = reinterpret_cast(location); - switch ( (Kinds)kind ) { - case branch32: + switch (kindValue) { + case LLD_X86_RELOC_BRANCH32: *loc32 = (targetAddress - (fixupAddress+4)) + addend; break; - case pointer32: - case abs32: + case LLD_X86_RELOC_POINTER32: + case LLD_X86_RELOC_ABS32: *loc32 = targetAddress + addend; break; - case funcRel32: + case LLD_X86_RELOC_FUNC_REL32: *loc32 = targetAddress + addend; break; - case none: - case lazyTarget: - case lazyImmediate: - case subordinateFDE: - case subordinateLSDA: + case LLD_X86_RELOC_LAZY_TARGET: + case LLD_X86_RELOC_LAZY_IMMEDIATE: // do nothing break; - case invalid: - assert(0 && "invalid Reference Kind"); + default: + llvm_unreachable("invalid x86 Reference Kind"); break; } } @@ -287,112 +215,80 @@ KindHandler_arm::~KindHandler_arm() { } -Reference::Kind KindHandler_arm::stringToKind(StringRef str) { - return llvm::StringSwitch(str) - .Case("none", none) - .Case("thumbBranch22", thumbBranch22) - .Case("armBranch24", armBranch24) - .Case("thumbAbsLow16", thumbAbsLow16) - .Case("thumbAbsHigh16", thumbAbsHigh16) - .Case("thumbPcRelLow16", thumbPcRelLow16) - .Case("thumbPcRelHigh16", thumbPcRelHigh16) - .Case("abs32", abs32) - .Case("pointer32", pointer32) - .Case("lazyTarget", lazyTarget) - .Case("lazyImmediate", lazyImmediate) - .Case("subordinateLSDA", subordinateLSDA) - .Default(invalid); - - llvm_unreachable("invalid ARM Reference kind"); -} - -StringRef KindHandler_arm::kindToString(Reference::Kind kind) { - switch ( (Kinds)kind ) { - case invalid: - return StringRef("invalid"); - case none: - return StringRef("none"); - case thumbBranch22: - return StringRef("thumbBranch22"); - case armBranch24: - return StringRef("armBranch24"); - case thumbAbsLow16: - return StringRef("thumbAbsLow16"); - case thumbAbsHigh16: - return StringRef("thumbAbsHigh16"); - case thumbPcRelLow16: - return StringRef("thumbPcRelLow16"); - case thumbPcRelHigh16: - return StringRef("thumbPcRelHigh16"); - case abs32: - return StringRef("abs32"); - case pointer32: - return StringRef("pointer32"); - case lazyTarget: - return StringRef("lazyTarget"); - case lazyImmediate: - return StringRef("lazyImmediate"); - case subordinateLSDA: - return StringRef("subordinateLSDA"); - } - llvm_unreachable("invalid ARM Reference kind"); -} +const Registry::KindStrings KindHandler_arm::kindStrings[] = { + LLD_KIND_STRING_ENTRY(ARM_RELOC_BR24), + LLD_KIND_STRING_ENTRY(ARM_THUMB_RELOC_BR22), + LLD_KIND_STRING_ENTRY(LLD_ARM_RELOC_THUMB_ABS_LO16), + LLD_KIND_STRING_ENTRY(LLD_ARM_RELOC_THUMB_ABS_HI16), + LLD_KIND_STRING_ENTRY(LLD_ARM_RELOC_THUMB_REL_LO16), + LLD_KIND_STRING_ENTRY(LLD_ARM_RELOC_THUMB_REL_HI16), + LLD_KIND_STRING_ENTRY(LLD_ARM_RELOC_ABS32), + LLD_KIND_STRING_ENTRY(LLD_ARM_RELOC_POINTER32), + LLD_KIND_STRING_ENTRY(LLD_ARM_RELOC_LAZY_TARGET), + LLD_KIND_STRING_ENTRY(LLD_ARM_RELOC_LAZY_IMMEDIATE), + LLD_KIND_STRING_END +}; -bool KindHandler_arm::isCallSite(Kind kind) { - return (kind == thumbBranch22) || (kind == armBranch24); +bool KindHandler_arm::isCallSite(const Reference &ref) { + return (ref.kindValue() == ARM_THUMB_RELOC_BR22) || + (ref.kindValue() == ARM_RELOC_BR24); } -bool KindHandler_arm::isPointer(Kind kind) { - return (kind == pointer32); +bool KindHandler_arm::isPointer(const Reference &ref) { + return (ref.kindValue() == LLD_ARM_RELOC_POINTER32); } -bool KindHandler_arm::isLazyImmediate(Kind kind) { - return (kind == lazyImmediate); +bool KindHandler_arm::isLazyImmediate(const Reference &ref) { + return (ref.kindValue() == LLD_ARM_RELOC_LAZY_IMMEDIATE); } -bool KindHandler_arm::isLazyTarget(Kind kind) { - return (kind == lazyTarget); +bool KindHandler_arm::isLazyTarget(const Reference &ref) { + return (ref.kindValue() == LLD_ARM_RELOC_LAZY_TARGET); } -void KindHandler_arm::applyFixup(Kind kind, uint64_t addend, uint8_t *location, - uint64_t fixupAddress, uint64_t targetAddress) { +void KindHandler_arm::applyFixup(Reference::KindNamespace ns, + Reference::KindArch arch, uint16_t kindValue, + uint64_t addend, uint8_t *location, + uint64_t fixupAddress, + uint64_t targetAddress) { + if (ns != Reference::KindNamespace::mach_o) + return; + assert(arch == Reference::KindArch::ARM); //int32_t *loc32 = reinterpret_cast(location); - switch ( (Kinds)kind ) { - case thumbBranch22: + switch ( kindValue ) { + case ARM_THUMB_RELOC_BR22: // FIXME break; - case armBranch24: + case ARM_RELOC_BR24: // FIXME break; - case thumbAbsLow16: + case LLD_ARM_RELOC_THUMB_ABS_LO16: // FIXME break; - case thumbAbsHigh16: + case LLD_ARM_RELOC_THUMB_ABS_HI16: // FIXME break; - case thumbPcRelLow16: + case LLD_ARM_RELOC_THUMB_REL_LO16: // FIXME break; - case thumbPcRelHigh16: + case LLD_ARM_RELOC_THUMB_REL_HI16: // FIXME break; - case abs32: + case LLD_ARM_RELOC_ABS32: // FIXME break; - case pointer32: + case LLD_ARM_RELOC_POINTER32: // FIXME break; - case none: - case lazyTarget: - case lazyImmediate: - case subordinateLSDA: + case LLD_ARM_RELOC_LAZY_TARGET: + case LLD_ARM_RELOC_LAZY_IMMEDIATE: // do nothing break; - case invalid: - assert(0 && "invalid Reference Kind"); + default: + llvm_unreachable("invalid ARM Reference Kind"); break; } } Index: lib/ReaderWriter/MachO/StubAtoms_x86.hpp =================================================================== --- lib/ReaderWriter/MachO/StubAtoms_x86.hpp +++ lib/ReaderWriter/MachO/StubAtoms_x86.hpp @@ -31,7 +31,9 @@ public: X86StubAtom(const File &file, const Atom &lazyPointer) : SimpleDefinedAtom(file) { - this->addReference(KindHandler_x86::abs32, 2, &lazyPointer, 0); + this->addReference(Reference::KindNamespace::mach_o, + Reference::KindArch::x86, + LLD_X86_RELOC_ABS32, 2, &lazyPointer, 0); } virtual ContentType contentType() const { @@ -63,8 +65,12 @@ X86StubHelperCommonAtom(const File &file, const Atom &cache, const Atom &binder) : SimpleDefinedAtom(file) { - this->addReference(KindHandler_x86::abs32, 1, &cache, 0); - this->addReference(KindHandler_x86::abs32, 7, &binder, 0); + this->addReference(Reference::KindNamespace::mach_o, + Reference::KindArch::x86, + LLD_X86_RELOC_ABS32, 1, &cache, 0); + this->addReference(Reference::KindNamespace::mach_o, + Reference::KindArch::x86, + LLD_X86_RELOC_ABS32, 7, &binder, 0); } virtual ContentType contentType() const { @@ -97,8 +103,12 @@ public: X86StubHelperAtom(const File &file, const Atom &helperCommon) : SimpleDefinedAtom(file) { - this->addReference(KindHandler_x86::lazyImmediate, 1, this, 0); - this->addReference(KindHandler_x86::branch32, 6, &helperCommon, 0); + this->addReference(Reference::KindNamespace::mach_o, + Reference::KindArch::x86, + LLD_X86_RELOC_LAZY_IMMEDIATE, 1, this, 0); + this->addReference(Reference::KindNamespace::mach_o, + Reference::KindArch::x86, + LLD_X86_RELOC_BRANCH32, 6, &helperCommon, 0); } virtual ContentType contentType() const { @@ -130,8 +140,12 @@ public: X86LazyPointerAtom(const File &file, const Atom &helper, const Atom &shlib) : SimpleDefinedAtom(file) { - this->addReference(KindHandler_x86::pointer32, 0, &helper, 0); - this->addReference(KindHandler_x86::lazyTarget, 0, &shlib, 0); + this->addReference(Reference::KindNamespace::mach_o, + Reference::KindArch::x86, + LLD_X86_RELOC_POINTER32, 0, &helper, 0); + this->addReference(Reference::KindNamespace::mach_o, + Reference::KindArch::x86, + LLD_X86_RELOC_LAZY_TARGET, 0, &shlib, 0); } virtual ContentType contentType() const { @@ -167,7 +181,9 @@ X86NonLazyPointerAtom(const File &file, const Atom &shlib) : SimpleDefinedAtom(file) { - this->addReference(KindHandler_x86::pointer32, 0, &shlib, 0); + this->addReference(Reference::KindNamespace::mach_o, + Reference::KindArch::x86, + LLD_X86_RELOC_POINTER32, 0, &shlib, 0); } virtual ContentType contentType() const { Index: lib/ReaderWriter/MachO/StubAtoms_x86_64.hpp =================================================================== --- lib/ReaderWriter/MachO/StubAtoms_x86_64.hpp +++ lib/ReaderWriter/MachO/StubAtoms_x86_64.hpp @@ -20,6 +20,7 @@ #include "ReferenceKinds.h" using llvm::makeArrayRef; +using namespace llvm::MachO; namespace lld { namespace mach_o { @@ -31,7 +32,9 @@ public: X86_64StubAtom(const File &file, const Atom &lazyPointer) : SimpleDefinedAtom(file) { - this->addReference(KindHandler_x86_64::ripRel32, 2, &lazyPointer, 0); + this->addReference(Reference::KindNamespace::mach_o, + Reference::KindArch::x86_64, + X86_64_RELOC_SIGNED, 2, &lazyPointer, 0); } virtual ContentType contentType() const { @@ -62,8 +65,12 @@ X86_64StubHelperCommonAtom(const File &file, const Atom &cache, const Atom &binder) : SimpleDefinedAtom(file) { - this->addReference(KindHandler_x86_64::ripRel32, 3, &cache, 0); - this->addReference(KindHandler_x86_64::ripRel32, 11, &binder, 0); + this->addReference(Reference::KindNamespace::mach_o, + Reference::KindArch::x86_64, + X86_64_RELOC_SIGNED, 3, &cache, 0); + this->addReference(Reference::KindNamespace::mach_o, + Reference::KindArch::x86_64, + X86_64_RELOC_SIGNED, 11, &binder, 0); } virtual ContentType contentType() const { @@ -96,8 +103,12 @@ public: X86_64StubHelperAtom(const File &file, const Atom &helperCommon) : SimpleDefinedAtom(file) { - this->addReference(KindHandler_x86_64::lazyImmediate, 1, this, 0); - this->addReference(KindHandler_x86_64::ripRel32, 6, &helperCommon, 0); + this->addReference(Reference::KindNamespace::mach_o, + Reference::KindArch::x86_64, + LLD_X86_64_RELOC_LAZY_IMMEDIATE, 1, this, 0); + this->addReference(Reference::KindNamespace::mach_o, + Reference::KindArch::x86_64, + X86_64_RELOC_SIGNED, 6, &helperCommon, 0); } virtual ContentType contentType() const { @@ -129,8 +140,12 @@ X86_64LazyPointerAtom(const File &file, const Atom &helper, const Atom &shlib) : SimpleDefinedAtom(file) { - this->addReference(KindHandler_x86_64::pointer64, 0, &helper, 0); - this->addReference(KindHandler_x86_64::lazyTarget, 0, &shlib, 0); + this->addReference(Reference::KindNamespace::mach_o, + Reference::KindArch::x86_64, + X86_64_RELOC_UNSIGNED, 0, &helper, 0); + this->addReference(Reference::KindNamespace::mach_o, + Reference::KindArch::x86_64, + LLD_X86_64_RELOC_LAZY_TARGET, 0, &shlib, 0); } virtual ContentType contentType() const { @@ -166,7 +181,9 @@ X86_64NonLazyPointerAtom(const File &file, const Atom &shlib) : SimpleDefinedAtom(file) { - this->addReference(KindHandler_x86_64::pointer64, 0, &shlib, 0); + this->addReference(Reference::KindNamespace::mach_o, + Reference::KindArch::x86_64, + X86_64_RELOC_UNSIGNED, 0, &shlib, 0); } virtual ContentType contentType() const { Index: lib/ReaderWriter/MachO/StubsPass.hpp =================================================================== --- lib/ReaderWriter/MachO/StubsPass.hpp +++ lib/ReaderWriter/MachO/StubsPass.hpp @@ -41,8 +41,8 @@ return true; } - virtual bool isCallSite(int32_t kind) { - return _kindHandler.isCallSite(kind); + virtual bool isCallSite(const Reference &ref) { + return _kindHandler.isCallSite(ref); } virtual const DefinedAtom* getStub(const Atom& target) { @@ -150,10 +150,10 @@ class File : public SimpleFile { public: File(const MachOLinkingContext &context) - : SimpleFile(context, "MachO Stubs pass") {} + : SimpleFile("MachO Stubs pass") {} }; - const MachOLinkingContext &_context; + const MachOLinkingContext &_context; mach_o::KindHandler &_kindHandler; File _file; llvm::DenseMap _targetToStub; Index: lib/ReaderWriter/Native/NativeFileFormat.h =================================================================== --- lib/ReaderWriter/Native/NativeFileFormat.h +++ lib/ReaderWriter/Native/NativeFileFormat.h @@ -202,8 +202,10 @@ enum { noTarget = UINT16_MAX }; - uint16_t offsetInAtom; - int16_t kind; + uint32_t offsetInAtom; + uint16_t kindValue; + uint8_t kindNamespace; + uint8_t kindArch; uint16_t targetIndex; uint16_t addendIndex; }; @@ -218,7 +220,9 @@ }; uint64_t offsetInAtom; int64_t addend; - int32_t kind; + uint16_t kindValue; + uint8_t kindNamespace; + uint8_t kindArch; uint32_t targetIndex; }; Index: lib/ReaderWriter/Native/ReaderNative.cpp =================================================================== --- lib/ReaderWriter/Native/ReaderNative.cpp +++ lib/ReaderWriter/Native/ReaderNative.cpp @@ -214,8 +214,9 @@ class NativeReferenceV1 : public Reference { public: NativeReferenceV1(const File& f, const NativeReferenceIvarsV1* ivarData) - : _file(&f), _ivarData(ivarData) { - setKind(ivarData->kind); + : Reference((KindNamespace)ivarData->kindNamespace, + (KindArch)ivarData->kindArch, ivarData->kindValue), + _file(&f), _ivarData(ivarData) { } virtual uint64_t offsetInAtom() const { @@ -240,8 +241,9 @@ class NativeReferenceV2 : public Reference { public: NativeReferenceV2(const File& f, const NativeReferenceIvarsV2* ivarData) - : _file(&f), _ivarData(ivarData) { - setKind(ivarData->kind); + : Reference((KindNamespace)ivarData->kindNamespace, + (KindArch)ivarData->kindArch, ivarData->kindValue), + _file(&f), _ivarData(ivarData) { } virtual uint64_t offsetInAtom() const { @@ -267,8 +269,7 @@ /// Instantiates a File object from a native object file. Ownership /// of the MemoryBuffer is transferred to the resulting File object. - static error_code make(const LinkingContext &context, - std::unique_ptr mb, + static error_code make(std::unique_ptr mb, std::vector > &result) { const uint8_t *const base = reinterpret_cast(mb->getBufferStart()); @@ -293,7 +294,7 @@ << header->chunkCount << "\n"); // instantiate NativeFile object and add values to it as found - std::unique_ptr file(new File(context, std::move(mb), path)); + std::unique_ptr file(new File(std::move(mb), path)); // process each chunk for (uint32_t i = 0; i < header->chunkCount; ++i) { @@ -360,7 +361,7 @@ for (const Reference *r : *a) { llvm::dbgs() << " offset=" << llvm::format("0x%03X", r->offsetInAtom()) - << ", kind=" << r->kind() + << ", kind=" << r->kindValue() << ", target=" << r->target() << "\n"; } } @@ -397,7 +398,6 @@ virtual const atom_collection &absolute() const { return _absoluteAtoms; } - virtual const LinkingContext &getLinkingContext() const { return _context; } private: friend NativeDefinedAtomV1; @@ -792,14 +792,12 @@ } // private constructor, only called by make() - File(const LinkingContext &context, std::unique_ptr mb, - StringRef path) + File(std::unique_ptr mb, StringRef path) : lld::File(path, kindObject), _buffer(std::move(mb)), // Reader now takes ownership of buffer _header(nullptr), _targetsTable(nullptr), _targetsTableCount(0), _strings(nullptr), _stringsMaxOffset(0), _addends(nullptr), - _addendsMaxIndex(0), _contentStart(nullptr), _contentEnd(nullptr), - _context(context) { + _addendsMaxIndex(0), _contentStart(nullptr), _contentEnd(nullptr) { _header = reinterpret_cast(_buffer->getBufferStart()); } @@ -845,7 +843,7 @@ }; - std::unique_ptr _buffer; + std::unique_ptr _buffer; const NativeFileHeader* _header; AtomArray _definedAtoms; AtomArray _undefinedAtoms; @@ -862,10 +860,9 @@ const char* _strings; uint32_t _stringsMaxOffset; const Reference::Addend* _addends; - uint32_t _addendsMaxIndex; - const uint8_t *_contentStart; - const uint8_t *_contentEnd; - const LinkingContext &_context; + uint32_t _addendsMaxIndex; + const uint8_t *_contentStart; + const uint8_t *_contentEnd; }; inline const lld::File &NativeDefinedAtomV1::file() const { @@ -1002,19 +999,34 @@ llvm_unreachable("setAddend() not supported"); } -class Reader : public lld::Reader { -public: - Reader(const LinkingContext &context) : lld::Reader(context) {} +} // end namespace native + +namespace { + +class NativeReader : public Reader { +public: + virtual bool canParse(file_magic magic, StringRef, + const MemoryBuffer& mb) const { + const NativeFileHeader *const header = + reinterpret_cast(mb.getBufferStart()); + return (memcmp(header->magic, NATIVE_FILE_HEADER_MAGIC, + sizeof(header->magic)) == 0); + } + virtual error_code - parseFile(std::unique_ptr &mb, - std::vector > &result) const { - return File::make(_context, std::move(mb), result); + parseFile(std::unique_ptr &mb, const class Registry &, + std::vector> &result) const { + return lld::native::File::make(std::move(mb), result); + return error_code::success(); } }; -} // end namespace native -std::unique_ptr createReaderNative(const LinkingContext &context) { - return std::unique_ptr(new lld::native::Reader(context)); + } + +void Registry::addSupportNativeObjects() { + add(std::unique_ptr(new NativeReader())); +} + } // end namespace lld Index: lib/ReaderWriter/Native/WriterNative.cpp =================================================================== --- lib/ReaderWriter/Native/WriterNative.cpp +++ lib/ReaderWriter/Native/WriterNative.cpp @@ -155,7 +155,9 @@ for (const NativeReferenceIvarsV2 &v2 : _referencesV2) { NativeReferenceIvarsV1 v1; v1.offsetInAtom = v2.offsetInAtom; - v1.kind = v2.kind; + v1.kindNamespace = v2.kindNamespace; + v1.kindArch = v2.kindArch; + v1.kindValue = v2.kindValue; v1.targetIndex = (v2.targetIndex == NativeReferenceIvarsV2::noTarget) ? NativeReferenceIvarsV1::noTarget : v2.targetIndex; v1.addendIndex = this->getAddendIndex(v2.addend); @@ -431,7 +433,9 @@ for (const Reference *ref : atom) { NativeReferenceIvarsV2 nref; nref.offsetInAtom = ref->offsetInAtom(); - nref.kind = ref->kind(); + nref.kindNamespace = (uint8_t)ref->kindNamespace(); + nref.kindArch = (uint8_t)ref->kindArch(); + nref.kindValue = ref->kindValue(); nref.targetIndex = this->getTargetIndex(ref->target()); nref.addend = ref->addend(); _referencesV2.push_back(nref); Index: lib/ReaderWriter/PECOFF/Atoms.h =================================================================== --- lib/ReaderWriter/PECOFF/Atoms.h +++ lib/ReaderWriter/PECOFF/Atoms.h @@ -27,13 +27,11 @@ /// to be fixed up so that the address points to atom Y's address. class COFFReference LLVM_FINAL : public Reference { public: - explicit COFFReference(Kind kind) : _target(nullptr), _offsetInAtom(0) { - _kind = kind; - } - - COFFReference(const Atom *target, uint32_t offsetInAtom, uint16_t relocType) - : _target(target), _offsetInAtom(offsetInAtom) { - setKind(static_cast(relocType)); + COFFReference(const Atom *target, uint32_t offsetInAtom, uint16_t relocType, + Reference::KindNamespace ns=Reference::KindNamespace::COFF, + Reference::KindArch arch=Reference::KindArch::x86) + : Reference(ns, arch, relocType), + _target(target), _offsetInAtom(offsetInAtom) { } virtual const Atom *target() const { return _target; } @@ -326,7 +324,7 @@ class VirtualFile : public SimpleFile { public: VirtualFile(const LinkingContext &ctx) - : SimpleFile(ctx, ""), _nextOrdinal(0) { + : SimpleFile(""), _nextOrdinal(0) { setOrdinal(ctx.getNextOrdinalAndIncrement()); } @@ -343,8 +341,9 @@ //===----------------------------------------------------------------------===// template -void addLayoutEdge(T *a, U *b, lld::Reference::Kind kind) { - auto ref = new COFFReference(kind); +void addLayoutEdge(T *a, U *b, uint32_t which) { + auto ref = new COFFReference(nullptr, 0, which, Reference::KindNamespace::all, + Reference::KindArch::all); ref->setTarget(b); a->addReference(std::unique_ptr(ref)); } Index: lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.h =================================================================== --- lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.h +++ lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.h @@ -21,7 +21,7 @@ class LinkerGeneratedSymbolFile : public SimpleFile { public: LinkerGeneratedSymbolFile(const PECOFFLinkingContext &ctx) - : SimpleFile(ctx, ""), + : SimpleFile(""), _imageBaseAtom(*this, ctx.decorateSymbol("__ImageBase"), Atom::scopeGlobal, ctx.getBaseAddress()) { addAtom(_imageBaseAtom); Index: lib/ReaderWriter/PECOFF/PECOFFLinkingContext.cpp =================================================================== --- lib/ReaderWriter/PECOFF/PECOFFLinkingContext.cpp +++ lib/ReaderWriter/PECOFF/PECOFFLinkingContext.cpp @@ -78,7 +78,6 @@ return false; } - _reader = createReaderPECOFF(*this); _writer = createWriterPECOFF(*this); return true; } @@ -87,7 +86,7 @@ if (entrySymbolName().empty()) return nullptr; std::unique_ptr entryFile( - new SimpleFile(*this, "command line option /entry")); + new SimpleFile("command line option /entry")); entryFile->addAtom( *(new (_allocator) SimpleUndefinedAtom(*entryFile, entrySymbolName()))); return std::move(entryFile); @@ -97,7 +96,7 @@ if (_initialUndefinedSymbols.empty()) return nullptr; std::unique_ptr undefinedSymFile( - new SimpleFile(*this, "command line option /c (or) /include")); + new SimpleFile("command line option /c (or) /include")); for (auto undefSymStr : _initialUndefinedSymbols) undefinedSymFile->addAtom(*(new (_allocator) SimpleUndefinedAtom( *undefinedSymFile, undefSymStr))); @@ -215,40 +214,6 @@ Writer &PECOFFLinkingContext::writer() const { return *_writer; } -ErrorOr -PECOFFLinkingContext::relocKindFromString(StringRef str) const { -#define LLD_CASE(name) .Case(#name, llvm::COFF::name) - int32_t ret = llvm::StringSwitch(str) - LLD_CASE(IMAGE_REL_I386_ABSOLUTE) - LLD_CASE(IMAGE_REL_I386_DIR32) - LLD_CASE(IMAGE_REL_I386_DIR32NB) - LLD_CASE(IMAGE_REL_I386_SECTION) - LLD_CASE(IMAGE_REL_I386_SECREL) - LLD_CASE(IMAGE_REL_I386_REL32) - .Default(-1); -#undef LLD_CASE - if (ret == -1) - return make_error_code(YamlReaderError::illegal_value); - return ret; -} - -ErrorOr -PECOFFLinkingContext::stringFromRelocKind(Reference::Kind kind) const { - switch (kind) { -#define LLD_CASE(name) \ - case llvm::COFF::name: \ - return std::string(#name); - - LLD_CASE(IMAGE_REL_I386_ABSOLUTE) - LLD_CASE(IMAGE_REL_I386_DIR32) - LLD_CASE(IMAGE_REL_I386_DIR32NB) - LLD_CASE(IMAGE_REL_I386_SECTION) - LLD_CASE(IMAGE_REL_I386_SECREL) - LLD_CASE(IMAGE_REL_I386_REL32) -#undef LLD_CASE - } - return make_error_code(YamlReaderError::illegal_value); -} void PECOFFLinkingContext::setSectionSetMask(StringRef sectionName, uint32_t newFlags) { @@ -277,7 +242,8 @@ uint32_t clearMask = (ci == _sectionClearMask.end()) ? 0 : ci->second; return (flags | setMask) & ~clearMask; } - + + void PECOFFLinkingContext::addPasses(PassManager &pm) { pm.add(std::unique_ptr(new pecoff::SetSubsystemPass(*this))); pm.add(std::unique_ptr(new pecoff::EdataPass(*this))); Index: lib/ReaderWriter/PECOFF/ReaderCOFF.cpp =================================================================== --- lib/ReaderWriter/PECOFF/ReaderCOFF.cpp +++ lib/ReaderWriter/PECOFF/ReaderCOFF.cpp @@ -62,8 +62,10 @@ SectionToAtomsT; public: - FileCOFF(const PECOFFLinkingContext &context, - std::unique_ptr mb, error_code &ec); + typedef const std::map StringMap; + + FileCOFF(std::unique_ptr mb, StringMap &altNames, + error_code &ec); virtual const atom_collection &defined() const { return _definedAtoms; @@ -81,11 +83,10 @@ return _absoluteAtoms; } - virtual const LinkingContext &getLinkingContext() const { return _context; } - StringRef getLinkerDirectives() const { return _directives; } private: + error_code readSymbolTable(vector &result); void createAbsoluteAtoms(const SymbolVectorT &symbols, @@ -94,17 +95,20 @@ error_code createUndefinedAtoms(const SymbolVectorT &symbols, vector &result); - error_code createDefinedSymbols(const SymbolVectorT &symbols, + error_code createDefinedSymbols(const SymbolVectorT &symbols, + StringMap &altNames, vector &result); error_code cacheSectionAttributes(); error_code AtomizeDefinedSymbolsInSection(const coff_section *section, + StringMap &altNames, vector &symbols, vector &atoms); error_code AtomizeDefinedSymbols(SectionToSymbolsT &definedSymbols, + StringMap &altNames, vector &definedAtoms); error_code findAtomAt(const coff_section *section, uint32_t targetAddress, @@ -156,7 +160,6 @@ _definedAtomLocations; mutable llvm::BumpPtrAllocator _alloc; - const PECOFFLinkingContext &_context; uint64_t _ordinal; }; @@ -173,33 +176,6 @@ llvm::BumpPtrAllocator _alloc; }; -class ReaderCOFF : public Reader { -public: - explicit ReaderCOFF(PECOFFLinkingContext &context) - : Reader(context), _PECOFFLinkingContext(context) {} - - error_code parseFile(std::unique_ptr &mb, - std::vector > &result) const; - -private: - error_code handleDirectiveSection(StringRef directives) const; - - ErrorOr - writeResToTemporaryFile(std::unique_ptr mb) const; - - ErrorOr - convertResourceFileToCOFF(std::unique_ptr mb) const; - - error_code convertAndParseResourceFile( - std::unique_ptr &mb, - std::vector > &result) const; - - error_code parseCOFFFile(std::unique_ptr &mb, - std::vector > &result) const; - - PECOFFLinkingContext &_PECOFFLinkingContext; - mutable BumpPtrStringSaver _stringSaver; -}; // Converts the COFF symbol attribute to the LLD's atom attribute. Atom::Scope getScope(const coff_symbol *symbol) { @@ -278,10 +254,9 @@ } } -FileCOFF::FileCOFF(const PECOFFLinkingContext &context, - std::unique_ptr mb, error_code &ec) - : File(mb->getBufferIdentifier(), kindObject), _context(context), - _ordinal(0) { +FileCOFF::FileCOFF(std::unique_ptr mb, StringMap &altNames, + error_code &ec) + : File(mb->getBufferIdentifier(), kindObject), _ordinal(0) { OwningPtr bin; ec = llvm::object::createBinary(mb.release(), bin); if (ec) @@ -304,7 +279,7 @@ createAbsoluteAtoms(symbols, _absoluteAtoms._atoms); if ((ec = createUndefinedAtoms(symbols, _undefinedAtoms._atoms))) return; - if ((ec = createDefinedSymbols(symbols, _definedAtoms._atoms))) + if ((ec = createDefinedSymbols(symbols, altNames, _definedAtoms._atoms))) return; if ((ec = addRelocationReferenceToAtoms())) @@ -427,6 +402,7 @@ /// the other two, because in order to create the atom for the defined symbol /// we need to know the adjacent symbols. error_code FileCOFF::createDefinedSymbols(const SymbolVectorT &symbols, + StringMap &altNames, vector &result) { // A defined atom can be merged if its section attribute allows its contents // to be merged. In COFF, it's not very easy to get the section attribute @@ -499,7 +475,7 @@ } // Atomize the defined symbols. - if (error_code ec = AtomizeDefinedSymbols(definedSymbols, result)) + if (error_code ec = AtomizeDefinedSymbols(definedSymbols, altNames, result)) return ec; return error_code::success(); @@ -552,6 +528,7 @@ /// assumed to have been defined in the \p section. error_code FileCOFF::AtomizeDefinedSymbolsInSection(const coff_section *section, + StringMap &altNames, vector &symbols, vector &atoms) { // Sort symbols by position. @@ -626,13 +603,11 @@ // if this is the last symbol, take up the remaining data. const uint8_t *end = (si + 1 == se) ? secData.data() + secData.size() : secData.data() + (*(si + 1))->Value; - StringRef symbolName = _symbolName[*si]; - StringRef alias = _context.getAlternateName(symbolName); - - if (!alias.empty()) { + auto pos = altNames.find(_symbolName[*si]); + if (pos != altNames.end()) { auto *atom = new (_alloc) COFFDefinedAtom( - *this, alias, sectionName, getScope(*si), type, isComdat, perms, - DefinedAtom::mergeAsWeak, ArrayRef(), _ordinal++); + *this, pos->second, sectionName, getScope(*si), type, isComdat, + perms, DefinedAtom::mergeAsWeak, ArrayRef(), _ordinal++); atoms.push_back(atom); _symbolAtom[*si] = atom; _definedAtomLocations[section][(*si)->Value].push_back(atom); @@ -655,6 +630,7 @@ error_code FileCOFF::AtomizeDefinedSymbols(SectionToSymbolsT &definedSymbols, + StringMap &altNames, vector &definedAtoms) { // For each section, make atoms for all the symbols defined in the // section, and append the atoms to the result objects. @@ -662,7 +638,8 @@ const coff_section *section = i.first; vector &symbols = i.second; vector atoms; - if (error_code ec = AtomizeDefinedSymbolsInSection(section, symbols, atoms)) + if (error_code ec = AtomizeDefinedSymbolsInSection(section, altNames, + symbols, atoms)) return ec; // Connect atoms with layout-before/layout-after edges. @@ -815,126 +792,6 @@ return error_code::success(); } -error_code -ReaderCOFF::parseFile(std::unique_ptr &mb, - std::vector > &result) const { - StringRef magic(mb->getBufferStart(), mb->getBufferSize()); - - // The input file should be a resource file, an archive file, a regular COFF - // file, or an import library member file. Try to parse in that order. If - // the input file does not start with a known magic, parseCOFFImportLibrary - // will return an error object. - llvm::sys::fs::file_magic fileType = llvm::sys::fs::identify_magic(magic); - - if (fileType == llvm::sys::fs::file_magic::windows_resource) - return convertAndParseResourceFile(mb, result); - if (fileType == llvm::sys::fs::file_magic::coff_import_library) - return lld::pecoff::parseCOFFImportLibrary(_context, mb, result); - return parseCOFFFile(mb, result); -} - -// Interpret the contents of .drectve section. If exists, the section contains -// a string containing command line options. The linker is expected to -// interpret the options as if they were given via the command line. -// -// The section mainly contains /defaultlib (-l in Unix), but can contain any -// options as long as they are valid. -error_code ReaderCOFF::handleDirectiveSection(StringRef directives) const { - DEBUG(llvm::dbgs() << ".drectve: " << directives << "\n"); - - // Split the string into tokens, as the shell would do for argv. - SmallVector tokens; - tokens.push_back("link"); // argv[0] is the command name. Will be ignored. - llvm::cl::TokenizeWindowsCommandLine(directives, _stringSaver, tokens); - tokens.push_back(nullptr); - - // Calls the command line parser to interpret the token string as if they - // were given via the command line. - int argc = tokens.size() - 1; - const char **argv = &tokens[0]; - std::string errorMessage; - llvm::raw_string_ostream stream(errorMessage); - bool parseFailed = !WinLinkDriver::parse(argc, argv, _PECOFFLinkingContext, - stream, /*isDirective*/ true); - stream.flush(); - - // Print error message if error. - if (parseFailed) { - llvm::errs() << "Failed to parse '" << directives << "'\n" - << "Reason: " << errorMessage; - return make_error_code(llvm::object::object_error::invalid_file_type); - } - if (!errorMessage.empty()) { - llvm::errs() << "lld warning: " << errorMessage << "\n"; - } - return error_code::success(); -} - -ErrorOr -ReaderCOFF::writeResToTemporaryFile(std::unique_ptr mb) const { - // Get a temporary file path for .res file. - SmallString<128> tempFilePath; - if (error_code ec = - llvm::sys::fs::createTemporaryFile("tmp", "res", tempFilePath)) - return ec; - - // Write the memory buffer contents to .res file, so that we can run - // cvtres.exe on it. - OwningPtr buffer; - if (error_code ec = llvm::FileOutputBuffer::create( - tempFilePath.str(), mb->getBufferSize(), buffer)) - return ec; - memcpy(buffer->getBufferStart(), mb->getBufferStart(), mb->getBufferSize()); - if (error_code ec = buffer->commit()) - return ec; - - // Convert SmallString -> StringRef -> std::string. - return tempFilePath.str().str(); -} - -ErrorOr -ReaderCOFF::convertResourceFileToCOFF(std::unique_ptr mb) const { - // Write the resource file to a temporary file. - ErrorOr inFilePath = writeResToTemporaryFile(std::move(mb)); - if (!inFilePath) - return error_code(inFilePath); - llvm::FileRemover inFileRemover(*inFilePath); - - // Create an output file path. - SmallString<128> outFilePath; - if (error_code ec = - llvm::sys::fs::createTemporaryFile("tmp", "obj", outFilePath)) - return ec; - std::string outFileArg = ("/out:" + outFilePath).str(); - - // Construct CVTRES.EXE command line and execute it. - std::string program = "cvtres.exe"; - std::string programPath = llvm::sys::FindProgramByName(program); - if (programPath.empty()) { - llvm::errs() << "Unable to find " << program << " in PATH\n"; - return llvm::errc::broken_pipe; - } - std::vector args; - args.push_back(programPath.c_str()); - args.push_back("/machine:x86"); - args.push_back("/readonly"); - args.push_back("/nologo"); - args.push_back(outFileArg.c_str()); - args.push_back(inFilePath->c_str()); - args.push_back(nullptr); - - DEBUG({ - for (const char **p = &args[0]; *p; ++p) - llvm::dbgs() << *p << " "; - llvm::dbgs() << "\n"; - }); - - if (llvm::sys::ExecuteAndWait(programPath.c_str(), &args[0]) != 0) { - llvm::errs() << program << " failed\n"; - return llvm::errc::broken_pipe; - } - return outFilePath.str().str(); -} // Convert .res file to .coff file and then parse it. Resource file is a file // containing various types of data, such as icons, translation texts, @@ -943,57 +800,231 @@ // // The linker is not capable to handle RC files directly. Instead, it runs // cvtres.exe on RC files and then then link its outputs. -error_code ReaderCOFF::convertAndParseResourceFile( - std::unique_ptr &mb, - std::vector > &result) const { - // Convert an RC to a COFF - ErrorOr coffFilePath = convertResourceFileToCOFF(std::move(mb)); - if (!coffFilePath) - return error_code(coffFilePath); - llvm::FileRemover coffFileRemover(*coffFilePath); - - // Read and parse the COFF - OwningPtr opmb; - if (error_code ec = MemoryBuffer::getFile(*coffFilePath, opmb)) - return ec; - std::unique_ptr newmb(opmb.take()); - return parseCOFFFile(newmb, result); -} +class ResourceFileReader : public Reader { +public: + virtual bool canParse(file_magic magic, StringRef ext, + const MemoryBuffer&) const { + return (magic == llvm::sys::fs::file_magic::windows_resource); + } + + virtual error_code + parseFile(std::unique_ptr &mb, const class Registry &, + std::vector > &result) const { + // Convert RC file to COFF + ErrorOr coffPath = convertResourceFileToCOFF(std::move(mb)); + if (!coffPath) + return error_code(coffPath); + llvm::FileRemover coffFileRemover(*coffPath); + + // Read and parse the COFF + OwningPtr opmb; + if (error_code ec = MemoryBuffer::getFile(*coffPath, opmb)) + return ec; + std::unique_ptr newmb(opmb.take()); + error_code ec; + FileCOFF::StringMap emptyMap; + std::unique_ptr file(new FileCOFF(std::move(newmb), emptyMap,ec)); + if (ec) + return ec; + result.push_back(std::move(file)); + return error_code::success(); + } + +private: + static ErrorOr + writeResToTemporaryFile(std::unique_ptr mb) { + // Get a temporary file path for .res file. + SmallString<128> tempFilePath; + if (error_code ec = + llvm::sys::fs::createTemporaryFile("tmp", "res", tempFilePath)) + return ec; -error_code -ReaderCOFF::parseCOFFFile(std::unique_ptr &mb, - std::vector > &result) const { - // Parse the memory buffer as PECOFF file. - error_code ec; - std::unique_ptr file( - new FileCOFF(_PECOFFLinkingContext, std::move(mb), ec)); - if (ec) - return ec; + // Write the memory buffer contents to .res file, so that we can run + // cvtres.exe on it. + OwningPtr buffer; + if (error_code ec = llvm::FileOutputBuffer::create( + tempFilePath.str(), mb->getBufferSize(), buffer)) + return ec; + memcpy(buffer->getBufferStart(), mb->getBufferStart(), mb->getBufferSize()); + if (error_code ec = buffer->commit()) + return ec; + + // Convert SmallString -> StringRef -> std::string. + return tempFilePath.str().str(); + } - DEBUG({ - llvm::dbgs() << "Defined atoms:\n"; - for (const auto &atom : file->defined()) { - llvm::dbgs() << " " << atom->name() << "\n"; - for (const Reference *ref : *atom) - llvm::dbgs() << " @" << ref->offsetInAtom() << " -> " - << ref->target()->name() << "\n"; - } - }); - - // Interpret .drectve section if the section has contents. - StringRef directives = file->getLinkerDirectives(); - if (!directives.empty()) - if (error_code ec = handleDirectiveSection(directives)) + static ErrorOr + convertResourceFileToCOFF(std::unique_ptr mb) { + // Write the resource file to a temporary file. + ErrorOr inFilePath = writeResToTemporaryFile(std::move(mb)); + if (!inFilePath) + return error_code(inFilePath); + llvm::FileRemover inFileRemover(*inFilePath); + + // Create an output file path. + SmallString<128> outFilePath; + if (error_code ec = + llvm::sys::fs::createTemporaryFile("tmp", "obj", outFilePath)) return ec; + std::string outFileArg = ("/out:" + outFilePath).str(); + + // Construct CVTRES.EXE command line and execute it. + std::string program = "cvtres.exe"; + std::string programPath = llvm::sys::FindProgramByName(program); + if (programPath.empty()) { + llvm::errs() << "Unable to find " << program << " in PATH\n"; + return llvm::errc::broken_pipe; + } + std::vector args; + args.push_back(programPath.c_str()); + args.push_back("/machine:x86"); + args.push_back("/readonly"); + args.push_back("/nologo"); + args.push_back(outFileArg.c_str()); + args.push_back(inFilePath->c_str()); + args.push_back(nullptr); + + DEBUG({ + for (const char **p = &args[0]; *p; ++p) + llvm::dbgs() << *p << " "; + llvm::dbgs() << "\n"; + }); + + if (llvm::sys::ExecuteAndWait(programPath.c_str(), &args[0]) != 0) { + llvm::errs() << program << " failed\n"; + return llvm::errc::broken_pipe; + } + return outFilePath.str().str(); + } +}; + + +class COFFObjectReader : public Reader { +public: + COFFObjectReader(PECOFFLinkingContext &ctx) : _context(ctx) { } + + virtual bool canParse(file_magic magic, StringRef ext, + const MemoryBuffer&) const { + return (magic == llvm::sys::fs::file_magic::coff_object); + } + + virtual error_code + parseFile(std::unique_ptr &mb, const Registry ®istry, + std::vector > &result) const { + // Parse the memory buffer as PECOFF file. + error_code ec; + std::unique_ptr file(new FileCOFF(std::move(mb), + _context.alternateNames(), ec)); + if (ec) + return ec; + + // Interpret .drectve section if the section has contents. + StringRef directives = file->getLinkerDirectives(); + if (!directives.empty()) + if (error_code ec2 = handleDirectiveSection(registry, directives)) + return ec2; + + result.push_back(std::move(file)); + return error_code::success(); + } + +private: + // Interpret the contents of .drectve section. If exists, the section contains + // a string containing command line options. The linker is expected to + // interpret the options as if they were given via the command line. + // + // The section mainly contains /defaultlib (-l in Unix), but can contain any + // options as long as they are valid. + error_code handleDirectiveSection(const Registry ®istry, + StringRef directives) const { + DEBUG(llvm::dbgs() << ".drectve: " << directives << "\n"); + + // Split the string into tokens, as the shell would do for argv. + SmallVector tokens; + tokens.push_back("link"); // argv[0] is the command name. Will be ignored. + llvm::cl::TokenizeWindowsCommandLine(directives, _stringSaver, tokens); + tokens.push_back(nullptr); + + // Calls the command line parser to interpret the token string as if they + // were given via the command line. + int argc = tokens.size() - 1; + const char **argv = &tokens[0]; + std::string errorMessage; + llvm::raw_string_ostream stream(errorMessage); + bool parseFailed = !WinLinkDriver::parse(argc, argv, _context, stream, + /*isDirective*/ true); + stream.flush(); + // Print error message if error. + if (parseFailed) { + llvm::errs() << "Failed to parse '" << directives << "'\n" + << "Reason: " << errorMessage; + return make_error_code(llvm::object::object_error::invalid_file_type); + } + if (!errorMessage.empty()) { + llvm::errs() << "lld warning: " << errorMessage << "\n"; + } + return error_code::success(); + } + + PECOFFLinkingContext &_context; + mutable BumpPtrStringSaver _stringSaver; +}; + +using namespace llvm::COFF; + +const Registry::KindStrings kindStringsI386[] = { + LLD_KIND_STRING_ENTRY(IMAGE_REL_I386_ABSOLUTE), + LLD_KIND_STRING_ENTRY(IMAGE_REL_I386_DIR16), + LLD_KIND_STRING_ENTRY(IMAGE_REL_I386_REL16), + LLD_KIND_STRING_ENTRY(IMAGE_REL_I386_DIR32), + LLD_KIND_STRING_ENTRY(IMAGE_REL_I386_DIR32NB), + LLD_KIND_STRING_ENTRY(IMAGE_REL_I386_SEG12), + LLD_KIND_STRING_ENTRY(IMAGE_REL_I386_SECTION), + LLD_KIND_STRING_ENTRY(IMAGE_REL_I386_SECREL), + LLD_KIND_STRING_ENTRY(IMAGE_REL_I386_TOKEN), + LLD_KIND_STRING_ENTRY(IMAGE_REL_I386_SECREL7), + LLD_KIND_STRING_ENTRY(IMAGE_REL_I386_REL32), + {0, ""} // marks end of table +}; + +const Registry::KindStrings kindStringsAMD64[] = { + LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_ABSOLUTE), + LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_ADDR64), + LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_ADDR32), + LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_ADDR32NB), + LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_REL32), + LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_REL32_1), + LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_REL32_2), + LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_REL32_3), + LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_REL32_4), + LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_REL32_5), + LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_SECTION), + LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_SECREL), + LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_SECREL7), + LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_TOKEN), + LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_SREL32), + LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_PAIR), + LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_SSPAN32), + LLD_KIND_STRING_END +}; - result.push_back(std::move(file)); - return error_code::success(); -} } // end namespace anonymous + + namespace lld { -std::unique_ptr createReaderPECOFF(PECOFFLinkingContext &context) { - return std::unique_ptr(new ReaderCOFF(context)); + +void Registry::addSupportCOFFObjects(PECOFFLinkingContext &ctx) { + add(std::unique_ptr(new COFFObjectReader(ctx))); + addKindTable(Reference::KindNamespace::COFF, Reference::KindArch::x86, + kindStringsI386); + addKindTable(Reference::KindNamespace::COFF, Reference::KindArch::x86_64, + kindStringsAMD64); } + +void Registry::addSupportWindowsResourceFiles() { + add(std::unique_ptr(new ResourceFileReader())); +} + } Index: lib/ReaderWriter/PECOFF/ReaderImportHeader.cpp =================================================================== --- lib/ReaderWriter/PECOFF/ReaderImportHeader.cpp +++ lib/ReaderWriter/PECOFF/ReaderImportHeader.cpp @@ -125,6 +125,7 @@ #include "lld/Core/File.h" #include "lld/Core/Error.h" #include "lld/Core/SharedLibraryAtom.h" +#include "lld/ReaderWriter/PECOFFLinkingContext.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/Object/COFF.h" @@ -143,10 +144,10 @@ #include using namespace lld; +using namespace lld::pecoff; using namespace llvm; namespace lld { -namespace pecoff { namespace { @@ -174,9 +175,8 @@ class FileImportLibrary : public File { public: - FileImportLibrary(const LinkingContext &context, - std::unique_ptr mb, error_code &ec) - : File(mb->getBufferIdentifier(), kindSharedLibrary), _context(context) { + FileImportLibrary(std::unique_ptr mb, error_code &ec) + : File(mb->getBufferIdentifier(), kindSharedLibrary) { const char *buf = mb->getBufferStart(); const char *end = mb->getBufferEnd(); @@ -231,8 +231,6 @@ return _noAbsoluteAtoms; } - virtual const LinkingContext &getLinkingContext() const { return _context; } - private: const COFFSharedLibraryAtom *addSharedLibraryAtom(uint16_t hint, StringRef symbolName, @@ -256,7 +254,6 @@ atom_collection_vector _definedAtoms; atom_collection_vector _sharedLibraryAtoms; - const LinkingContext &_context; mutable llvm::BumpPtrAllocator _alloc; // Does the same thing as StringRef::ltrim() but removes at most one @@ -294,8 +291,37 @@ } }; +class COFFImportLibraryReader : public Reader { +public: + virtual bool canParse(file_magic magic, StringRef, const MemoryBuffer&) const{ + return (magic == llvm::sys::fs::file_magic::coff_import_library); + } + + virtual error_code + parseFile(std::unique_ptr &mb, const class Registry &, + std::vector > &result) const { + // Check the file magic. + const char *buf = mb->getBufferStart(); + const char *end = mb->getBufferEnd(); + // Error if the file is too small or does not start with the magic. + if (end - buf < static_cast(sizeof(COFF::ImportHeader)) || + memcmp(buf, "\0\0\xFF\xFF", 4)) + return make_error_code(NativeReaderError::unknown_file_format); + + error_code ec; + auto file = std::unique_ptr(new FileImportLibrary(std::move(mb), ec)); + if (ec) + return ec; + result.push_back(std::move(file)); + return error_code::success(); + } + +}; + } // end anonymous namespace +namespace pecoff { + error_code parseCOFFImportLibrary(const LinkingContext &targetInfo, std::unique_ptr &mb, std::vector > &result) { @@ -309,7 +335,7 @@ error_code ec; auto file = std::unique_ptr( - new FileImportLibrary(targetInfo, std::move(mb), ec)); + new FileImportLibrary(std::move(mb), ec)); if (ec) return ec; result.push_back(std::move(file)); @@ -317,4 +343,9 @@ } } // end namespace pecoff + +void Registry::addSupportCOFFImportLibraries() { + add(std::unique_ptr(new COFFImportLibraryReader())); +} + } // end namespace lld Index: lib/ReaderWriter/PECOFF/WriterPECOFF.cpp =================================================================== --- lib/ReaderWriter/PECOFF/WriterPECOFF.cpp +++ lib/ReaderWriter/PECOFF/WriterPECOFF.cpp @@ -454,10 +454,9 @@ for (const auto *layout : _atomLayouts) { const DefinedAtom *atom = cast(layout->_atom); for (const Reference *ref : *atom) { - // Skip if this reference is not for relocation. - if (ref->kind() < lld::Reference::kindTargetLow) + // Skip if this reference is not for COFF relocation. + if (ref->kindNamespace() != Reference::KindNamespace::COFF) continue; - auto relocSite32 = reinterpret_cast( buffer + layout->_fileOffset + ref->offsetInAtom()); auto relocSite16 = reinterpret_cast(relocSite32); @@ -465,8 +464,7 @@ // Also account for whatever offset is already stored at the relocation // site. targetAddr += *relocSite32; - - switch (ref->kind()) { + switch (ref->kindValue()) { case llvm::COFF::IMAGE_REL_I386_ABSOLUTE: // This relocation is no-op. break; @@ -539,7 +537,8 @@ for (const auto *layout : _atomLayouts) { const DefinedAtom *atom = cast(layout->_atom); for (const Reference *ref : *atom) - if (ref->kind() == llvm::COFF::IMAGE_REL_I386_DIR32) + if ((ref->kindNamespace() == Reference::KindNamespace::COFF) && + (ref->kindValue() == llvm::COFF::IMAGE_REL_I386_DIR32)) relocSites.push_back(layout->_virtualAddr + ref->offsetInAtom()); } } Index: lib/ReaderWriter/Reader.cpp =================================================================== --- lib/ReaderWriter/Reader.cpp +++ lib/ReaderWriter/Reader.cpp @@ -11,10 +11,98 @@ #include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Support/FileUtilities.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/system_error.h" namespace lld { + Reader::~Reader() { } + +void Registry::add(std::unique_ptr reader) { + _readers.push_back(std::move(reader)); +} + +error_code +Registry::parseFile(std::unique_ptr &mb, + std::vector> &result) const { + // Get file type. + StringRef content(mb->getBufferStart(), mb->getBufferSize()); + llvm::sys::fs::file_magic fileType = llvm::sys::fs::identify_magic(content); + // Get file extension. + StringRef extension = ""; + StringRef path = mb->getBufferIdentifier(); + size_t lastDot = path.rfind('.'); + if (lastDot != StringRef::npos) { + extension = path.substr(lastDot); + } + + // Ask each registered reader if it can handle this file type or extension. + for (const std::unique_ptr &reader : _readers) { + if (reader->canParse(fileType, extension, *mb)) { + return reader->parseFile(mb, *this, result); + } + } + + // No Reader could parse this file. + return llvm::make_error_code(llvm::errc::executable_format_error); +} + +static const Registry::KindStrings kindStrings[] = { + { Reference::kindInGroup, "in-group" }, + { Reference::kindLayoutAfter, "layout-after" }, + { Reference::kindLayoutBefore, "layout-before" }, + LLD_KIND_STRING_END +}; + +Registry::Registry() { + addKindTable(Reference::KindNamespace::all, Reference::KindArch::all, + kindStrings); +} + +void Registry::addKindTable(Reference::KindNamespace ns, + Reference::KindArch arch, + const KindStrings array[]) { + KindEntry entry = {ns, arch, array}; + _kindEntries.push_back(entry); +} + +bool Registry::referenceKindFromString(StringRef inputStr, + Reference::KindNamespace &ns, + Reference::KindArch &arch, + uint16_t &value) const { + for (const KindEntry &entry : _kindEntries) { + for (const KindStrings *pair=entry.array; !pair->name.empty(); ++pair) { + if (!inputStr.equals(pair->name)) + continue; + ns = entry.ns; + arch = entry.arch; + value = pair->value; + return true; + } + } + return false; +} + + +bool Registry::referenceKindToString(Reference::KindNamespace ns, + Reference::KindArch arch, + uint16_t value, StringRef &str) const { + for (const KindEntry &entry : _kindEntries) { + if (entry.ns != ns) + continue; + if (entry.arch != arch) + continue; + for (const KindStrings *pair=entry.array; !pair->name.empty(); ++pair) { + if (pair->value != value) + continue; + str = pair->name; + return true; + } + } + return false; +} + + } // end namespace lld Index: lib/ReaderWriter/YAML/ReaderWriterYAML.cpp =================================================================== --- lib/ReaderWriter/YAML/ReaderWriterYAML.cpp +++ lib/ReaderWriter/YAML/ReaderWriterYAML.cpp @@ -10,6 +10,7 @@ #include "lld/ReaderWriter/Reader.h" #include "lld/ReaderWriter/Simple.h" #include "lld/ReaderWriter/Writer.h" +#include "lld/ReaderWriter/YamlContext.h" #include "lld/Core/ArchiveLibraryFile.h" #include "lld/Core/DefinedAtom.h" @@ -46,18 +47,6 @@ /// how the mapping is done to and from YAML. namespace { -/// Most of the traits are context-free and always do the same transformation. -/// But, there are some traits that need some contextual information to properly -/// do their transform. This struct is available via io.getContext() and -/// supplies contextual information. -class ContextInfo { -public: - ContextInfo(const LinkingContext &context) - : _currentFile(nullptr), _context(context) {} - - lld::File *_currentFile; - const LinkingContext &_context; -}; /// Used when writing yaml files. /// In most cases, atoms names are unambiguous, so references can just @@ -260,9 +249,13 @@ // more readable than just true/false. LLVM_YAML_STRONG_TYPEDEF(bool, ShlibCanBeNull) -// lld::Reference::Kind is a typedef of int32. We need a stronger -// type to make template matching work, so invent RefKind. -LLVM_YAML_STRONG_TYPEDEF(lld::Reference::Kind, RefKind) +// lld::Reference::Kind is a tuple of . +// For yaml, we just want one string that encapsulates the tuple. +struct RefKind { + Reference::KindNamespace ns; + Reference::KindArch arch; + uint16_t value; +}; } // namespace anon @@ -276,49 +269,26 @@ // This is a custom formatter for RefKind template <> struct ScalarTraits { - static void output(const RefKind &value, void *ctxt, raw_ostream &out) { + static void output(const RefKind &kind, void *ctxt, raw_ostream &out) { assert(ctxt != nullptr); - ContextInfo *info = reinterpret_cast(ctxt); - switch (value) { - case lld::Reference::kindLayoutAfter: - out << "layout-after"; - break; - case lld::Reference::kindLayoutBefore: - out << "layout-before"; - break; - case lld::Reference::kindInGroup: - out << "in-group"; - break; - default: - if (auto relocStr = info->_context.stringFromRelocKind(value)) - out << *relocStr; - else - out << ""; - break; - } + YamlContext *info = reinterpret_cast(ctxt); + assert(info->_registry); + StringRef str; + if (info->_registry->referenceKindToString(kind.ns, kind.arch, kind.value, + str)) + out << str; + else + out << (int)(kind.ns) << "-" << (int)(kind.arch) << "-" << kind.value; } - static StringRef input(StringRef scalar, void *ctxt, RefKind &value) { + static StringRef input(StringRef scalar, void *ctxt, RefKind &kind) { assert(ctxt != nullptr); - ContextInfo *info = reinterpret_cast(ctxt); - auto relocKind = info->_context.relocKindFromString(scalar); - if (!relocKind) { - if (scalar.equals("layout-after")) { - value = lld::Reference::kindLayoutAfter; - return StringRef(); - } - if (scalar.equals("layout-before")) { - value = lld::Reference::kindLayoutBefore; - return StringRef(); - } - if (scalar.equals("in-group")) { - value = lld::Reference::kindInGroup; - return StringRef(); - } - return "Invalid relocation kind"; - } - value = *relocKind; - return StringRef(); + YamlContext *info = reinterpret_cast(ctxt); + assert(info->_registry); + if (info->_registry->referenceKindFromString(scalar, kind.ns, kind.arch, + kind.value)) + return StringRef(); + return StringRef("unknown reference kind"); } }; @@ -595,12 +565,9 @@ class NormArchiveFile : public lld::ArchiveLibraryFile { public: NormArchiveFile(IO &io) - : ArchiveLibraryFile(((ContextInfo *)io.getContext())->_context, ""), - _path() {} + : ArchiveLibraryFile(""), _path() {} NormArchiveFile(IO &io, const lld::File *file) - : ArchiveLibraryFile(((ContextInfo *)io.getContext())->_context, - file->path()), - _path(file->path()) { + : ArchiveLibraryFile(file->path()), _path(file->path()) { // If we want to support writing archives, this constructor would // need to populate _members. } @@ -639,15 +606,20 @@ return nullptr; } + virtual error_code parseAllMembers( + std::vector> &result) const { + return error_code::success(); + } + StringRef _path; std::vector _members; }; class NormalizedFile : public lld::File { public: - NormalizedFile(IO &io) : File("", kindObject), _IO(io), _rnb(nullptr) {} + NormalizedFile(IO &io) : File("", kindObject), _io(io), _rnb(nullptr) {} NormalizedFile(IO &io, const lld::File *file) - : File(file->path(), kindObject), _IO(io), + : File(file->path(), kindObject), _io(io), _rnb(new RefNameBuilder(*file)), _path(file->path()) { for (const lld::DefinedAtom *a : file->defined()) _definedAtoms.push_back(a); @@ -674,10 +646,6 @@ return _absoluteAtoms; } - virtual const LinkingContext &getLinkingContext() const { - return ((ContextInfo *)_IO.getContext())->_context; - } - // Allocate a new copy of this string and keep track of allocations // in _stringCopies, so they can be freed when File is destroyed. StringRef copyString(StringRef str) { @@ -691,7 +659,7 @@ return r; } - IO &_IO; + IO &_io; RefNameBuilder *_rnb; StringRef _path; AtomList _definedAtoms; @@ -706,7 +674,6 @@ FileKinds kind = fileKindObjectAtoms; // If reading, peek ahead to see what kind of file this is. io.mapOptional("kind", kind, fileKindObjectAtoms); - // switch (kind) { case fileKindObjectAtoms: mappingAtoms(io, file); @@ -725,9 +692,9 @@ static void mappingAtoms(IO &io, const lld::File *&file) { MappingNormalizationHeap keys(io, file); - ContextInfo *info = reinterpret_cast(io.getContext()); + YamlContext *info = reinterpret_cast(io.getContext()); assert(info != nullptr); - info->_currentFile = keys.operator->(); + info->_file = keys.operator->(); io.mapOptional("path", keys->_path); io.mapOptional("defined-atoms", keys->_definedAtoms); @@ -750,19 +717,26 @@ class NormalizedReference : public lld::Reference { public: NormalizedReference(IO &io) - : _target(nullptr), _targetName(), _offset(0), _addend(0) {} + : lld::Reference(lld::Reference::KindNamespace::all, + lld::Reference::KindArch::all, 0), + _target(nullptr), _targetName(), _offset(0), _addend(0) {} NormalizedReference(IO &io, const lld::Reference *ref) - : _target(nullptr), _targetName(targetName(io, ref)), - _offset(ref->offsetInAtom()), _addend(ref->addend()), - _mappedKind(ref->kind()) {} + : lld::Reference(ref->kindNamespace(), ref->kindArch(), + ref->kindValue()), + _target(nullptr), _targetName(targetName(io, ref)), + _offset(ref->offsetInAtom()), _addend(ref->addend()) { + _mappedKind.ns = ref->kindNamespace(); + _mappedKind.arch = ref->kindArch(); + _mappedKind.value = ref->kindValue(); + } const lld::Reference *denormalize(IO &io) { - ContextInfo *info = reinterpret_cast(io.getContext()); + YamlContext *info = reinterpret_cast(io.getContext()); assert(info != nullptr); typedef MappingTraits::NormalizedFile NormalizedFile; NormalizedFile *f = - reinterpret_cast(info->_currentFile); + reinterpret_cast(info->_file); if (!_targetName.empty()) _targetName = f->copyString(_targetName); DEBUG_WITH_TYPE("WriterYAML", llvm::dbgs() @@ -770,7 +744,9 @@ << _targetName << "' (" << (void *)_targetName.data() << ", " << _targetName.size() << ")\n"); - setKind(_mappedKind); + setKindNamespace(_mappedKind.ns); + setKindArch(_mappedKind.arch); + setKindValue(_mappedKind.value); return this; } void bind(const RefNameResolver &); @@ -830,11 +806,11 @@ _content.push_back(x); } const lld::DefinedAtom *denormalize(IO &io) { - ContextInfo *info = reinterpret_cast(io.getContext()); + YamlContext *info = reinterpret_cast(io.getContext()); assert(info != nullptr); typedef MappingTraits::NormalizedFile NormalizedFile; NormalizedFile *f = - reinterpret_cast(info->_currentFile); + reinterpret_cast(info->_file); if (!_name.empty()) _name = f->copyString(_name); if (!_refName.empty()) @@ -850,10 +826,10 @@ void bind(const RefNameResolver &); // Extract current File object from YAML I/O parsing context const lld::File &fileFromContext(IO &io) { - ContextInfo *info = reinterpret_cast(io.getContext()); + YamlContext *info = reinterpret_cast(io.getContext()); assert(info != nullptr); - assert(info->_currentFile != nullptr); - return *info->_currentFile; + assert(info->_file != nullptr); + return *info->_file; } virtual const lld::File &file() const { return _file; } @@ -927,10 +903,10 @@ if (io.outputting()) { // If writing YAML, check if atom needs a ref-name. typedef MappingTraits::NormalizedFile NormalizedFile; - ContextInfo *info = reinterpret_cast(io.getContext()); + YamlContext *info = reinterpret_cast(io.getContext()); assert(info != nullptr); NormalizedFile *f = - reinterpret_cast(info->_currentFile); + reinterpret_cast(info->_file); assert(f); assert(f->_rnb); if (f->_rnb->hasRefName(atom)) { @@ -980,11 +956,11 @@ _canBeNull(atom->canBeNull()), _fallback(atom->fallback()) {} const lld::UndefinedAtom *denormalize(IO &io) { - ContextInfo *info = reinterpret_cast(io.getContext()); + YamlContext *info = reinterpret_cast(io.getContext()); assert(info != nullptr); typedef MappingTraits::NormalizedFile NormalizedFile; NormalizedFile *f = - reinterpret_cast(info->_currentFile); + reinterpret_cast(info->_file); if (!_name.empty()) _name = f->copyString(_name); @@ -997,10 +973,10 @@ // Extract current File object from YAML I/O parsing context const lld::File &fileFromContext(IO &io) { - ContextInfo *info = reinterpret_cast(io.getContext()); + YamlContext *info = reinterpret_cast(io.getContext()); assert(info != nullptr); - assert(info->_currentFile != nullptr); - return *info->_currentFile; + assert(info->_file != nullptr); + return *info->_file; } virtual const lld::File &file() const { return _file; } @@ -1040,11 +1016,11 @@ _type(atom->type()), _size(atom->size()) {} const lld::SharedLibraryAtom *denormalize(IO &io) { - ContextInfo *info = reinterpret_cast(io.getContext()); + YamlContext *info = reinterpret_cast(io.getContext()); assert(info != nullptr); typedef MappingTraits::NormalizedFile NormalizedFile; NormalizedFile *f = - reinterpret_cast(info->_currentFile); + reinterpret_cast(info->_file); if (!_name.empty()) _name = f->copyString(_name); if (!_loadName.empty()) @@ -1059,10 +1035,10 @@ // Extract current File object from YAML I/O parsing context const lld::File &fileFromContext(IO &io) { - ContextInfo *info = reinterpret_cast(io.getContext()); + YamlContext *info = reinterpret_cast(io.getContext()); assert(info != nullptr); - assert(info->_currentFile != nullptr); - return *info->_currentFile; + assert(info->_file != nullptr); + return *info->_file; } virtual const lld::File &file() const { return _file; } @@ -1104,11 +1080,11 @@ : _file(fileFromContext(io)), _name(atom->name()), _scope(atom->scope()), _value(atom->value()) {} const lld::AbsoluteAtom *denormalize(IO &io) { - ContextInfo *info = reinterpret_cast(io.getContext()); + YamlContext *info = reinterpret_cast(io.getContext()); assert(info != nullptr); typedef MappingTraits::NormalizedFile NormalizedFile; NormalizedFile *f = - reinterpret_cast(info->_currentFile); + reinterpret_cast(info->_file); if (!_name.empty()) _name = f->copyString(_name); @@ -1120,10 +1096,10 @@ } // Extract current File object from YAML I/O parsing context const lld::File &fileFromContext(IO &io) { - ContextInfo *info = reinterpret_cast(io.getContext()); + YamlContext *info = reinterpret_cast(io.getContext()); assert(info != nullptr); - assert(info->_currentFile != nullptr); - return *info->_currentFile; + assert(info->_file != nullptr); + return *info->_file; } virtual const lld::File &file() const { return _file; } @@ -1144,10 +1120,10 @@ if (io.outputting()) { typedef MappingTraits::NormalizedFile NormalizedFile; - ContextInfo *info = reinterpret_cast(io.getContext()); + YamlContext *info = reinterpret_cast(io.getContext()); assert(info != nullptr); NormalizedFile *f = - reinterpret_cast(info->_currentFile); + reinterpret_cast(info->_file); assert(f); assert(f->_rnb); if (f->_rnb->hasRefName(atom)) { @@ -1226,10 +1202,10 @@ IO &io, const lld::Reference *ref) { if (ref->target() == nullptr) return StringRef(); - ContextInfo *info = reinterpret_cast(io.getContext()); + YamlContext *info = reinterpret_cast(io.getContext()); assert(info != nullptr); typedef MappingTraits::NormalizedFile NormalizedFile; - NormalizedFile *f = reinterpret_cast(info->_currentFile); + NormalizedFile *f = reinterpret_cast(info->_file); RefNameBuilder *rnb = f->_rnb; if (rnb->hasRefName(ref->target())) return rnb->refName(ref->target()); @@ -1251,8 +1227,10 @@ return llvm::make_error_code(llvm::errc::no_such_file_or_directory); // Create yaml Output writer, using yaml options for context. - ContextInfo context(_context); - llvm::yaml::Output yout(out, &context); + YamlContext yamlContext; + yamlContext._linkingContext = &_context; + yamlContext._registry = &_context.registry(); + llvm::yaml::Output yout(out, &yamlContext); // Write yaml output. const lld::File *fileRef = &file; @@ -1265,12 +1243,21 @@ const LinkingContext &_context; }; -class ReaderYAML : public Reader { +} // end namespace yaml + +namespace { + +class YAMLReader : public Reader { public: - ReaderYAML(const LinkingContext &context) : Reader(context) {} + YAMLReader(const Registry ®istry) : _registry(registry) { } - error_code parseFile(std::unique_ptr &mb, - std::vector > &result) const { + virtual bool canParse(file_magic, StringRef ext, const MemoryBuffer&) const { + return (ext.equals(".objtxt") || ext.equals(".yaml")); + } + + virtual error_code + parseFile(std::unique_ptr &mb, const class Registry &, + std::vector> &result) const { // Note: we do not take ownership of the MemoryBuffer. That is // because yaml may produce multiple File objects, so there is no // *one* File to take ownership. Therefore, the yaml File objects @@ -1278,15 +1265,16 @@ // Otherwise the strings will become invalid when this MemoryBuffer // is deallocated. - // Create YAML Input parser. - ContextInfo context(_context); - llvm::yaml::Input yin(mb->getBuffer(), &context); + // Create YAML Input Reader. + YamlContext yamlContext; + yamlContext._registry = &_registry; + llvm::yaml::Input yin(mb->getBuffer(), &yamlContext); // Fill vector with File objects created by parsing yaml. std::vector createdFiles; yin >> createdFiles; - // Quit now if there were parsing errors. + // Error out now if there were parsing errors. if (yin.error()) return make_error_code(lld::YamlReaderError::illegal_value); @@ -1297,14 +1285,20 @@ } return make_error_code(lld::YamlReaderError::success); } -}; -} // end namespace yaml +private: + const Registry &_registry; +}; + + +} // anonymous namespace + +void Registry::addSupportYamlFiles() { + add(std::unique_ptr(new YAMLReader(*this))); +} + std::unique_ptr createWriterYAML(const LinkingContext &context) { return std::unique_ptr(new lld::yaml::Writer(context)); } -std::unique_ptr createReaderYAML(const LinkingContext &context) { - return std::unique_ptr(new lld::yaml::ReaderYAML(context)); -} } // end namespace lld Index: test/darwin/hello-world.objtxt =================================================================== --- test/darwin/hello-world.objtxt +++ test/darwin/hello-world.objtxt @@ -4,7 +4,7 @@ # Test that hello-world can be linked into a mach-o executable # ---- +--- !atoms defined-atoms: - name: _main type: code @@ -14,10 +14,10 @@ 31, C0, 5D, C3 ] references: - offset: 7 - kind: ripRel32 + kind: X86_64_RELOC_SIGNED target: LC1 - offset: 12 - kind: branch32 + kind: X86_64_RELOC_BRANCH target: _printf - ref-name: LC1 Index: test/elf/reloc.test =================================================================== --- test/elf/reloc.test +++ test/elf/reloc.test @@ -1,4 +1,4 @@ -RUN: lld -flavor gnu -target x86_64 --merge-strings -r --output-filetype=yaml \ +RUN: lld -flavor gnu -target i386 --merge-strings -r --output-filetype=yaml \ RUN: %p/Inputs/reloc-test.elf-i386 | FileCheck %s -check-prefix ELF-i386 ELF-i386: defined-atoms: @@ -23,10 +23,10 @@ ELF-i386: section-choice: custom-required ELF-i386: section-name: .text.startup ELF-i386: references: -ELF-i386: - kind: R_X86_64_64 +ELF-i386: - kind: R_386_32 ELF-i386: offset: 12 ELF-i386: target: [[STRNAMEA]] -ELF-i386: - kind: R_X86_64_PC32 +ELF-i386: - kind: R_386_PC32 ELF-i386: offset: 17 ELF-i386: target: puts ELF-i386: addend: 252 Index: unittests/DriverTests/InputGraphTest.cpp =================================================================== --- unittests/DriverTests/InputGraphTest.cpp +++ unittests/DriverTests/InputGraphTest.cpp @@ -26,15 +26,6 @@ class MyLinkingContext : public LinkingContext { public: - virtual Reader &getDefaultReader() const { return *_yamlReader; } - - virtual ErrorOr relocKindFromString(StringRef str) const { - return make_error_code(YamlReaderError::illegal_value); - } - - virtual ErrorOr stringFromRelocKind(Reference::Kind k) const { - return make_error_code(YamlReaderError::illegal_value); - } virtual Writer &writer() const { llvm_unreachable("no writer!"); } @@ -126,7 +117,7 @@ class MyObjFile : public SimpleFile { public: MyObjFile(LinkingContext &context, StringRef path) - : SimpleFile(context, path) {} + : SimpleFile(path) {} }; class InputGraphTest : public testing::Test {