diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2016-07-23 20:48:50 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2016-07-23 20:48:50 +0000 |
commit | 1c98619801a5705c688e683be3ef9d70169a0686 (patch) | |
tree | 8422105cd1a94c368315f2db16b9ac746cf7c000 /include | |
parent | f4f3ce4613680903220815690ad79fc7ba0a2e26 (diff) | |
download | src-1c98619801a5705c688e683be3ef9d70169a0686.tar.gz src-1c98619801a5705c688e683be3ef9d70169a0686.zip |
Vendor import of lld release_39 branch r276489:vendor/lld/lld-release_39-r276489
Notes
Notes:
svn path=/vendor/lld/dist/; revision=303239
svn path=/vendor/lld/lld-release_39-r276489/; revision=303240; tag=vendor/lld/lld-release_39-r276489
Diffstat (limited to 'include')
29 files changed, 449 insertions, 3432 deletions
diff --git a/include/lld/Core/Alias.h b/include/lld/Core/Alias.h deleted file mode 100644 index fa999292fbd3..000000000000 --- a/include/lld/Core/Alias.h +++ /dev/null @@ -1,100 +0,0 @@ -//===- lld/Core/Alias.h - Alias atoms -------------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// \brief Provide alias atoms. -/// -//===----------------------------------------------------------------------===// - -#ifndef LLD_CORE_ALIAS_H -#define LLD_CORE_ALIAS_H - -#include "lld/Core/LLVM.h" -#include "lld/Core/Simple.h" -#include "llvm/ADT/Optional.h" -#include <string> - -namespace lld { - -// An AliasAtom is a zero-size atom representing an alias for other atom. It has -// a LayoutAfter reference to the target atom, so that this atom and the target -// atom will be laid out at the same location in the final result. Initially -// the target atom is an undefined atom. Resolver will replace it with a defined -// one. -// -// It does not have attributes itself. Most member function calls are forwarded -// to the target atom. -class AliasAtom : public SimpleDefinedAtom { -public: - AliasAtom(const File &file, StringRef name) - : SimpleDefinedAtom(file), _name(name) {} - - StringRef name() const override { return _name; } - uint64_t size() const override { return 0; } - ArrayRef<uint8_t> rawContent() const override { return ArrayRef<uint8_t>(); } - - Scope scope() const override { - getTarget(); - return _target ? _target->scope() : scopeLinkageUnit; - } - - Merge merge() const override { - if (_merge.hasValue()) - return _merge.getValue(); - getTarget(); - return _target ? _target->merge() : mergeNo; - } - - void setMerge(Merge val) { _merge = val; } - - ContentType contentType() const override { - getTarget(); - return _target ? _target->contentType() : typeUnknown; - } - - Interposable interposable() const override { - getTarget(); - return _target ? _target->interposable() : interposeNo; - } - - SectionChoice sectionChoice() const override { - getTarget(); - return _target ? _target->sectionChoice() : sectionBasedOnContent; - } - - StringRef customSectionName() const override { - getTarget(); - return _target ? _target->customSectionName() : StringRef(""); - } - - DeadStripKind deadStrip() const override { return _deadStrip; } - void setDeadStrip(DeadStripKind val) { _deadStrip = val; } - -private: - void getTarget() const { - if (_target) - return; - for (const Reference *r : *this) { - if (r->kindNamespace() == lld::Reference::KindNamespace::all && - r->kindValue() == lld::Reference::kindLayoutAfter) { - _target = dyn_cast<DefinedAtom>(r->target()); - return; - } - } - } - - std::string _name; - mutable const DefinedAtom *_target = nullptr; - llvm::Optional<Merge> _merge = DefinedAtom::mergeNo; - DeadStripKind _deadStrip = DefinedAtom::deadStripNormal; -}; - -} // end namespace lld - -#endif diff --git a/include/lld/Core/ArchiveLibraryFile.h b/include/lld/Core/ArchiveLibraryFile.h index ff379d4f3ecf..2c736e7d6c61 100644 --- a/include/lld/Core/ArchiveLibraryFile.h +++ b/include/lld/Core/ArchiveLibraryFile.h @@ -11,7 +11,6 @@ #define LLD_CORE_ARCHIVE_LIBRARY_FILE_H #include "lld/Core/File.h" -#include "lld/Core/Parallel.h" #include <set> namespace lld { @@ -33,23 +32,11 @@ public: /// 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 File *find(StringRef name, bool dataSymbolOnly) = 0; + virtual File *find(StringRef name) = 0; virtual std::error_code parseAllMembers(std::vector<std::unique_ptr<File>> &result) = 0; - // Parses a member file containing a given symbol, so that when you - // need the file find() can return that immediately. Calling this function - // has no side effect other than pre-instantiating a file. Calling this - // function doesn't affect correctness. - virtual void preload(TaskGroup &group, StringRef symbolName) {} - - /// Returns a set of all defined symbols in the archive, i.e. all - /// resolvable symbol using this file. - virtual std::set<StringRef> getDefinedSymbols() { - return std::set<StringRef>(); - } - protected: /// only subclasses of ArchiveLibraryFile can be instantiated ArchiveLibraryFile(StringRef path) : File(path, kindArchiveLibrary) {} diff --git a/include/lld/Core/Atom.h b/include/lld/Core/Atom.h index 27fdde022ba7..42ca2bb8af8c 100644 --- a/include/lld/Core/Atom.h +++ b/include/lld/Core/Atom.h @@ -16,6 +16,9 @@ namespace lld { class File; +template<typename T> +class OwningAtomPtr; + /// /// The linker has a Graph Theory model of linking. An object file is seen /// as a set of Atoms with References to other Atoms. Each Atom is a node @@ -24,6 +27,7 @@ class File; /// undefined symbol (extern declaration). /// class Atom { + template<typename T> friend class OwningAtomPtr; public: /// Whether this atom is defined or a proxy for an undefined symbol enum Definition { @@ -71,6 +75,55 @@ private: Definition _definition; }; +/// Class which owns an atom pointer and runs the atom destructor when the +/// owning pointer goes out of scope. +template<typename T> +class OwningAtomPtr { +private: + OwningAtomPtr(const OwningAtomPtr &) = delete; + void operator=(const OwningAtomPtr&) = delete; +public: + OwningAtomPtr() : atom(nullptr) { } + OwningAtomPtr(T *atom) : atom(atom) { } + + ~OwningAtomPtr() { + if (atom) + runDestructor(atom); + } + + void runDestructor(Atom *atom) { + atom->~Atom(); + } + + OwningAtomPtr(OwningAtomPtr &&ptr) : atom(ptr.atom) { + ptr.atom = nullptr; + } + + void operator=(OwningAtomPtr&& ptr) { + if (atom) + runDestructor(atom); + atom = ptr.atom; + ptr.atom = nullptr; + } + + T *const &get() const { + return atom; + } + + T *&get() { + return atom; + } + + T *release() { + auto *v = atom; + atom = nullptr; + return v; + } + +private: + T *atom; +}; + } // namespace lld #endif // LLD_CORE_ATOM_H diff --git a/include/lld/Core/DefinedAtom.h b/include/lld/Core/DefinedAtom.h index e4d4488ccdca..e3193f8aaf2e 100644 --- a/include/lld/Core/DefinedAtom.h +++ b/include/lld/Core/DefinedAtom.h @@ -11,11 +11,12 @@ #define LLD_CORE_DEFINED_ATOM_H #include "lld/Core/Atom.h" +#include "lld/Core/Reference.h" #include "lld/Core/LLVM.h" +#include "llvm/Support/ErrorHandling.h" namespace lld { class File; -class Reference; /// \brief The fundamental unit of linking. /// @@ -105,6 +106,7 @@ public: enum ContentType { typeUnknown, // for use with definitionUndefined + typeMachHeader, // atom representing mach_header [Darwin] typeCode, // executable code typeResolver, // function which returns address of target typeBranchIsland, // linker created for large binaries @@ -127,6 +129,7 @@ public: typeObjC1Class, // ObjC1 class [Darwin] typeLazyPointer, // pointer through which a stub jumps typeLazyDylibPointer, // pointer through which a stub jumps [Darwin] + typeNonLazyPointer, // pointer to external symbol typeCFString, // NS/CFString object [Darwin] typeGOT, // pointer to external symbol typeInitializerPtr, // pointer to initializer function @@ -134,6 +137,8 @@ public: typeCStringPtr, // pointer to UTF8 C string [Darwin] typeObjCClassPtr, // pointer to ObjC class [Darwin] typeObjC2CategoryList, // pointers to ObjC category [Darwin] + typeObjCImageInfo, // pointer to ObjC class [Darwin] + typeObjCMethodList, // pointer to ObjC method list [Darwin] typeDTraceDOF, // runtime data for Dtrace [Darwin] typeInterposingTuples, // tuples of interposing info for dyld [Darwin] typeTempLTO, // temporary atom for bitcode reader @@ -143,14 +148,7 @@ public: typeTLVInitialData, // initial data for a TLV [Darwin] typeTLVInitialZeroFill, // TLV initial zero fill data [Darwin] typeTLVInitializerPtr, // pointer to thread local initializer [Darwin] - typeMachHeader, // atom representing mach_header [Darwin] - typeThreadZeroFill, // Uninitialized thread local data(TBSS) [ELF] - typeThreadData, // Initialized thread local data(TDATA) [ELF] - typeRONote, // Identifies readonly note sections [ELF] - typeRWNote, // Identifies readwrite note sections [ELF] - typeNoAlloc, // Identifies non allocatable sections [ELF] - typeGroupComdat, // Identifies a section group [ELF, COFF] - typeGnuLinkOnce, // Identifies a gnu.linkonce section [ELF] + typeDSOHandle, // atom representing DSO handle [Darwin] typeSectCreate, // Created via the -sectcreate option [Darwin] }; @@ -218,11 +216,6 @@ public: /// /// This is used by the linker to order the layout of Atoms so that the /// resulting image is stable and reproducible. - /// - /// Note that this should not be confused with ordinals of exported symbols in - /// Windows DLLs. In Windows terminology, ordinals are symbols' export table - /// indices (small integers) which can be used instead of symbol names to - /// refer items in a DLL. virtual uint64_t ordinal() const = 0; /// \brief the number of bytes of space this atom's content will occupy in the @@ -307,8 +300,12 @@ public: return _atom.derefIterator(_it); } + bool operator==(const reference_iterator &other) const { + return _it == other._it; + } + bool operator!=(const reference_iterator &other) const { - return _it != other._it; + return !(*this == other); } reference_iterator &operator++() { @@ -326,6 +323,14 @@ public: /// \brief Returns an iterator to the end of this Atom's References. virtual reference_iterator end() const = 0; + /// Adds a reference to this atom. + virtual void addReference(Reference::KindNamespace ns, + Reference::KindArch arch, + Reference::KindValue kindValue, uint64_t off, + const Atom *target, Reference::Addend a) { + llvm_unreachable("Subclass does not permit adding references"); + } + static bool classof(const Atom *a) { return a->definition() == definitionRegular; } @@ -338,16 +343,15 @@ public: ContentType atomContentType = contentType(); return !(atomContentType == DefinedAtom::typeZeroFill || atomContentType == DefinedAtom::typeZeroFillFast || - atomContentType == DefinedAtom::typeTLVInitialZeroFill || - atomContentType == DefinedAtom::typeThreadZeroFill); + atomContentType == DefinedAtom::typeTLVInitialZeroFill); } - /// Utility function to check if the atom belongs to a group section - /// that represents section groups or .gnu.linkonce sections. - bool isGroupParent() const { + /// Utility function to check if relocations in this atom to other defined + /// atoms can be implicitly generated, and so we don't need to explicitly + /// emit those relocations. + bool relocsToDefinedCanBeImplicit() const { ContentType atomContentType = contentType(); - return (atomContentType == DefinedAtom::typeGroupComdat || - atomContentType == DefinedAtom::typeGnuLinkOnce); + return atomContentType == typeCFI; } // Returns true if lhs should be placed before rhs in the final output. @@ -359,6 +363,8 @@ protected: // constructor. DefinedAtom() : Atom(definitionRegular) { } + ~DefinedAtom() override = default; + /// \brief Returns a pointer to the Reference object that the abstract /// iterator "points" to. virtual const Reference *derefIterator(const void *iter) const = 0; diff --git a/include/lld/Core/Error.h b/include/lld/Core/Error.h index a7e61f91d8e9..b0bf73b1cb7b 100644 --- a/include/lld/Core/Error.h +++ b/include/lld/Core/Error.h @@ -15,6 +15,8 @@ #define LLD_CORE_ERROR_H #include "lld/Core/LLVM.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Support/Error.h" #include <system_error> namespace lld { @@ -30,39 +32,37 @@ inline std::error_code make_error_code(YamlReaderError e) { return std::error_code(static_cast<int>(e), YamlReaderCategory()); } -const std::error_category &LinkerScriptReaderCategory(); - -enum class LinkerScriptReaderError { - success = 0, - parse_error, - unknown_symbol_in_expr, - unrecognized_function_in_expr, - unknown_phdr_ids, - extra_program_phdr, - misplaced_program_phdr, - program_phdr_wrong_phdrs, -}; - -inline std::error_code make_error_code(LinkerScriptReaderError e) { - return std::error_code(static_cast<int>(e), LinkerScriptReaderCategory()); -} - /// Creates an error_code object that has associated with it an arbitrary /// error messsage. The value() of the error_code will always be non-zero /// but its value is meaningless. The messsage() will be (a copy of) the /// supplied error string. /// Note: Once ErrorOr<> is updated to work with errors other than error_code, /// this can be updated to return some other kind of error. -std::error_code make_dynamic_error_code(const char *msg); std::error_code make_dynamic_error_code(StringRef msg); -std::error_code make_dynamic_error_code(const Twine &msg); + +/// Generic error. +/// +/// For errors that don't require their own specific sub-error (most errors) +/// this class can be used to describe the error via a string message. +class GenericError : public llvm::ErrorInfo<GenericError> { +public: + static char ID; + GenericError(Twine Msg); + const std::string &getMessage() const { return Msg; } + void log(llvm::raw_ostream &OS) const override; + + std::error_code convertToErrorCode() const override { + return make_dynamic_error_code(getMessage()); + } + +private: + std::string Msg; +}; } // end namespace lld namespace std { template <> struct is_error_code_enum<lld::YamlReaderError> : std::true_type {}; -template <> -struct is_error_code_enum<lld::LinkerScriptReaderError> : std::true_type {}; } #endif diff --git a/include/lld/Core/File.h b/include/lld/Core/File.h index 494e50065340..20418688dfa0 100644 --- a/include/lld/Core/File.h +++ b/include/lld/Core/File.h @@ -14,8 +14,8 @@ #include "lld/Core/DefinedAtom.h" #include "lld/Core/SharedLibraryAtom.h" #include "lld/Core/UndefinedAtom.h" -#include "lld/Core/range.h" #include "llvm/ADT/Optional.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/Twine.h" #include "llvm/Support/ErrorHandling.h" #include <functional> @@ -45,9 +45,18 @@ public: /// \brief Kinds of files that are supported. enum Kind { - kindObject, ///< object file (.o) - kindSharedLibrary, ///< shared library (.so) - kindArchiveLibrary ///< archive (.a) + kindErrorObject, ///< a error object file (.o) + kindNormalizedObject, ///< a normalized file (.o) + kindMachObject, ///< a MachO object file (.o) + kindCEntryObject, ///< a file for CEntries + kindHeaderObject, ///< a file for file headers + kindEntryObject, ///< a file for the entry + kindUndefinedSymsObject, ///< a file for undefined symbols + kindStubHelperObject, ///< a file for stub helpers + kindResolverMergedObject, ///< the resolver merged file. + kindSectCreateObject, ///< a sect create object file (.o) + kindSharedLibrary, ///< shared library (.so) + kindArchiveLibrary ///< archive (.a) }; /// \brief Returns file kind. Need for dyn_cast<> on File objects. @@ -97,17 +106,69 @@ public: } /// The type of atom mutable container. - template <typename T> using AtomVector = std::vector<const T *>; + template <typename T> using AtomVector = std::vector<OwningAtomPtr<T>>; - /// The range type for the atoms. It's backed by a std::vector, but hides - /// its member functions so that you can only call begin or end. + /// The range type for the atoms. template <typename T> class AtomRange { public: - AtomRange(AtomVector<T> v) : _v(v) {} - typename AtomVector<T>::const_iterator begin() const { return _v.begin(); } - typename AtomVector<T>::const_iterator end() const { return _v.end(); } - typename AtomVector<T>::iterator begin() { return _v.begin(); } - typename AtomVector<T>::iterator end() { return _v.end(); } + AtomRange(AtomVector<T> &v) : _v(v) {} + AtomRange(const AtomVector<T> &v) : _v(const_cast<AtomVector<T> &>(v)) {} + + typedef std::pointer_to_unary_function<const OwningAtomPtr<T>&, + const T*> ConstDerefFn; + + typedef std::pointer_to_unary_function<OwningAtomPtr<T>&, T*> DerefFn; + + typedef llvm::mapped_iterator<typename AtomVector<T>::const_iterator, + ConstDerefFn> ConstItTy; + typedef llvm::mapped_iterator<typename AtomVector<T>::iterator, + DerefFn> ItTy; + + static const T* DerefConst(const OwningAtomPtr<T> &p) { + return p.get(); + } + + static T* Deref(OwningAtomPtr<T> &p) { + return p.get(); + } + + ConstItTy begin() const { + return ConstItTy(_v.begin(), ConstDerefFn(DerefConst)); + } + ConstItTy end() const { + return ConstItTy(_v.end(), ConstDerefFn(DerefConst)); + } + + ItTy begin() { + return ItTy(_v.begin(), DerefFn(Deref)); + } + ItTy end() { + return ItTy(_v.end(), DerefFn(Deref)); + } + + llvm::iterator_range<typename AtomVector<T>::iterator> owning_ptrs() { + return llvm::make_range(_v.begin(), _v.end()); + } + + llvm::iterator_range<typename AtomVector<T>::iterator> owning_ptrs() const { + return llvm::make_range(_v.begin(), _v.end()); + } + + bool empty() const { + return _v.empty(); + } + + size_t size() const { + return _v.size(); + } + + const OwningAtomPtr<T> &operator[](size_t idx) const { + return _v[idx]; + } + + OwningAtomPtr<T> &operator[](size_t idx) { + return _v[idx]; + } private: AtomVector<T> &_v; @@ -115,19 +176,25 @@ public: /// \brief Must be implemented to return the AtomVector object for /// all DefinedAtoms in this File. - virtual const AtomVector<DefinedAtom> &defined() const = 0; + virtual const AtomRange<DefinedAtom> defined() const = 0; /// \brief Must be implemented to return the AtomVector object for /// all UndefinedAtomw in this File. - virtual const AtomVector<UndefinedAtom> &undefined() const = 0; + virtual const AtomRange<UndefinedAtom> undefined() const = 0; /// \brief Must be implemented to return the AtomVector object for /// all SharedLibraryAtoms in this File. - virtual const AtomVector<SharedLibraryAtom> &sharedLibrary() const = 0; + virtual const AtomRange<SharedLibraryAtom> sharedLibrary() const = 0; /// \brief Must be implemented to return the AtomVector object for /// all AbsoluteAtoms in this File. - virtual const AtomVector<AbsoluteAtom> &absolute() const = 0; + virtual const AtomRange<AbsoluteAtom> absolute() const = 0; + + /// Drop all of the atoms owned by this file. This will result in all of + /// the atoms running their destructors. + /// This is required because atoms may be allocated on a BumpPtrAllocator + /// of a different file. We need to destruct all atoms before any files. + virtual void clearAtoms() = 0; /// \brief If a file is parsed using a different method than doParse(), /// one must use this method to set the last error status, so that @@ -137,14 +204,6 @@ public: std::error_code parse(); - // This function is called just before the core linker tries to use - // a file. Currently the PECOFF reader uses this to trigger the - // driver to parse .drectve section (which contains command line options). - // If you want to do something having side effects, don't do that in - // doParse() because a file could be pre-loaded speculatively. - // Use this hook instead. - virtual void beforeLink() {} - // Usually each file owns a std::unique_ptr<MemoryBuffer>. // However, there's one special case. If a file is an archive file, // the archive file and its children all shares the same memory buffer. @@ -190,23 +249,26 @@ private: class ErrorFile : public File { public: ErrorFile(StringRef path, std::error_code ec) - : File(path, kindObject), _ec(ec) {} + : File(path, kindErrorObject), _ec(ec) {} std::error_code doParse() override { return _ec; } - const AtomVector<DefinedAtom> &defined() const override { + const AtomRange<DefinedAtom> defined() const override { llvm_unreachable("internal error"); } - const AtomVector<UndefinedAtom> &undefined() const override { + const AtomRange<UndefinedAtom> undefined() const override { llvm_unreachable("internal error"); } - const AtomVector<SharedLibraryAtom> &sharedLibrary() const override { + const AtomRange<SharedLibraryAtom> sharedLibrary() const override { llvm_unreachable("internal error"); } - const AtomVector<AbsoluteAtom> &absolute() const override { + const AtomRange<AbsoluteAtom> absolute() const override { llvm_unreachable("internal error"); } + void clearAtoms() override { + } + private: std::error_code _ec; }; diff --git a/include/lld/Core/LLVM.h b/include/lld/Core/LLVM.h index d532c17fbfdf..ccf08859f4ae 100644 --- a/include/lld/Core/LLVM.h +++ b/include/lld/Core/LLVM.h @@ -23,6 +23,7 @@ namespace llvm { // ADT's. + class Error; class StringRef; class Twine; class MemoryBuffer; @@ -38,6 +39,9 @@ namespace llvm { template<typename T> class ErrorOr; + template<typename T> + class Expected; + class raw_ostream; // TODO: DenseMap, ... } @@ -51,6 +55,7 @@ namespace lld { using llvm::cast_or_null; // ADT's. + using llvm::Error; using llvm::StringRef; using llvm::Twine; using llvm::MemoryBuffer; @@ -61,6 +66,7 @@ namespace lld { using llvm::SmallVectorImpl; using llvm::SaveAndRestore; using llvm::ErrorOr; + using llvm::Expected; using llvm::raw_ostream; } // end namespace lld. diff --git a/include/lld/Core/LinkingContext.h b/include/lld/Core/LinkingContext.h index a723854b3c91..7e4edaf22cf3 100644 --- a/include/lld/Core/LinkingContext.h +++ b/include/lld/Core/LinkingContext.h @@ -13,9 +13,7 @@ #include "lld/Core/Error.h" #include "lld/Core/LLVM.h" #include "lld/Core/Node.h" -#include "lld/Core/Parallel.h" #include "lld/Core/Reference.h" -#include "lld/Core/range.h" #include "lld/Core/Reader.h" #include "llvm/Support/ErrorOr.h" #include "llvm/Support/raw_ostream.h" @@ -33,16 +31,9 @@ class SharedLibraryFile; /// /// The base class LinkingContext contains the options needed by core linking. /// Subclasses of LinkingContext have additional options needed by specific -/// Writers. For example, ELFLinkingContext has methods that supplies -/// options to the ELF Writer and ELF Passes. +/// Writers. class LinkingContext { public: - /// \brief The types of output file that the linker creates. - enum class OutputFileType : uint8_t { - Default, // The default output type for this target - YAML, // The output type is set to YAML - }; - virtual ~LinkingContext(); /// \name Methods needed by core linking @@ -78,28 +69,6 @@ public: _deadStripRoots.push_back(symbolName); } - /// Archive files (aka static libraries) are normally lazily loaded. That is, - /// object files within an archive are only loaded and linked in, if the - /// object file contains a DefinedAtom which will replace an existing - /// UndefinedAtom. If this method returns true, core linking will also look - /// for archive members to replace existing tentative definitions in addition - /// to replacing undefines. Note: a "tentative definition" (also called a - /// "common" symbols) is a C (but not C++) concept. They are modeled in lld - /// as a DefinedAtom with merge() of mergeAsTentative. - bool searchArchivesToOverrideTentativeDefinitions() const { - return _searchArchivesToOverrideTentativeDefinitions; - } - - /// Normally core linking will turn a tentative definition into a real - /// definition if not replaced by a real DefinedAtom from some object file. - /// If this method returns true, core linking will search all supplied - /// dynamic shared libraries for symbol names that match remaining tentative - /// definitions. If any are found, the corresponding tentative definition - /// atom is replaced with SharedLibraryAtom. - bool searchSharedLibrariesToOverrideTentativeDefinitions() const { - return _searchSharedLibrariesToOverrideTentativeDefinitions; - } - /// Normally, every UndefinedAtom must be replaced by a DefinedAtom or a /// SharedLibraryAtom for the link to be successful. This method controls /// whether core linking prints out a list of remaining UndefinedAtoms. @@ -114,35 +83,6 @@ public: /// whether core linking considers remaining undefines to be an error. bool allowRemainingUndefines() const { return _allowRemainingUndefines; } - /// In the lld model, a SharedLibraryAtom is a proxy atom for something - /// that will be found in a dynamic shared library when the program runs. - /// A SharedLibraryAtom optionally contains the name of the shared library - /// in which to find the symbol name at runtime. Core linking may merge - /// two SharedLibraryAtom with the same name. If this method returns true, - /// when merging core linking will also verify that they both have the same - /// loadName() and if not print a warning. - /// - /// \todo This should be a method core linking calls so that drivers can - /// format the warning as needed. - bool warnIfCoalesableAtomsHaveDifferentLoadName() const { - return _warnIfCoalesableAtomsHaveDifferentLoadName; - } - - /// In C/C++ you can mark a function's prototype with - /// __attribute__((weak_import)) or __attribute__((weak)) to say the function - /// may not be available at runtime and/or build time and in which case its - /// address will evaluate to NULL. In lld this is modeled using the - /// UndefinedAtom::canBeNull() method. During core linking, UndefinedAtom - /// with the same name are automatically merged. If this method returns - /// true, core link also verfies that the canBeNull() value for merged - /// UndefinedAtoms are the same and warns if not. - /// - /// \todo This should be a method core linking calls so that drivers can - /// format the warning as needed. - bool warnIfCoalesableAtomsHaveDifferentCanBeNull() const { - return _warnIfCoalesableAtomsHaveDifferentCanBeNull; - } - /// Normally, every UndefinedAtom must be replaced by a DefinedAtom or a /// SharedLibraryAtom for the link to be successful. This method controls /// whether core linking considers remaining undefines from the shared library @@ -176,20 +116,7 @@ public: } void setDeadStripping(bool enable) { _deadStrip = enable; } - void setAllowDuplicates(bool enable) { _allowDuplicates = enable; } void setGlobalsAreDeadStripRoots(bool v) { _globalsAreDeadStripRoots = v; } - void setSearchArchivesToOverrideTentativeDefinitions(bool search) { - _searchArchivesToOverrideTentativeDefinitions = search; - } - void setSearchSharedLibrariesToOverrideTentativeDefinitions(bool search) { - _searchSharedLibrariesToOverrideTentativeDefinitions = search; - } - void setWarnIfCoalesableAtomsHaveDifferentCanBeNull(bool warn) { - _warnIfCoalesableAtomsHaveDifferentCanBeNull = warn; - } - void setWarnIfCoalesableAtomsHaveDifferentLoadName(bool warn) { - _warnIfCoalesableAtomsHaveDifferentLoadName = warn; - } void setPrintRemainingUndefines(bool print) { _printRemainingUndefines = print; } @@ -199,27 +126,11 @@ public: void setAllowShlibUndefines(bool allow) { _allowShlibUndefines = allow; } void setLogInputFiles(bool log) { _logInputFiles = log; } - // Returns true if multiple definitions should not be treated as a - // fatal error. - bool getAllowDuplicates() const { return _allowDuplicates; } - void appendLLVMOption(const char *opt) { _llvmOptions.push_back(opt); } - void addAlias(StringRef from, StringRef to) { _aliasSymbols[from] = to; } - const std::map<std::string, std::string> &getAliases() const { - return _aliasSymbols; - } - std::vector<std::unique_ptr<Node>> &getNodes() { return _nodes; } const std::vector<std::unique_ptr<Node>> &getNodes() const { return _nodes; } - /// Notify the LinkingContext when the symbol table found a name collision. - /// The useNew parameter specifies which the symbol table plans to keep, - /// but that can be changed by the LinkingContext. This is also an - /// opportunity for flavor specific processing. - virtual void notifySymbolTableCoalesce(const Atom *existingAtom, - const Atom *newAtom, bool &useNew) {} - /// This method adds undefined symbols specified by the -u option to the to /// the list of undefined symbols known to the linker. This option essentially /// forces an undefined symbol to be created. You may also need to call @@ -242,7 +153,7 @@ public: /// Return the list of undefined symbols that are specified in the /// linker command line, using the -u option. - range<const StringRef *> initialUndefinedSymbols() const { + ArrayRef<StringRef> initialUndefinedSymbols() const { return _initialUndefinedSymbols; } @@ -255,9 +166,7 @@ public: bool validate(raw_ostream &diagnostics); /// Formats symbol name for use in error messages. - virtual std::string demangle(StringRef symbolName) const { - return symbolName; - } + virtual std::string demangle(StringRef symbolName) const = 0; /// @} /// \name Methods used by Driver::link() @@ -269,19 +178,6 @@ public: /// the linker to write to an in-memory buffer. StringRef outputPath() const { return _outputPath; } - /// Set the various output file types that the linker would - /// create - bool setOutputFileType(StringRef outputFileType) { - if (outputFileType.equals_lower("yaml")) { - _outputFileType = OutputFileType::YAML; - return true; - } - return false; - } - - /// Returns the output file type that that the linker needs to create. - OutputFileType outputFileType() const { return _outputFileType; } - /// Accessor for Register object embedded in LinkingContext. const Registry ®istry() const { return _registry; } Registry ®istry() { return _registry; } @@ -289,25 +185,30 @@ public: /// 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 /// how file format specific atoms can be added to the link. - virtual void createImplicitFiles(std::vector<std::unique_ptr<File>> &); + virtual void createImplicitFiles(std::vector<std::unique_ptr<File>> &) = 0; /// This method is called by core linking to build the list of Passes to be /// run on the merged/linked graph of all input files. - virtual void addPasses(PassManager &pm); + virtual void addPasses(PassManager &pm) = 0; /// Calls through to the writeFile() method on the specified Writer. /// /// \param linkedFile This is the merged/linked graph of all input file Atoms. - virtual std::error_code writeFile(const File &linkedFile) const; + virtual llvm::Error writeFile(const File &linkedFile) const; /// Return the next ordinal and Increment it. virtual uint64_t getNextOrdinalAndIncrement() const { return _nextOrdinal++; } // This function is called just before the Resolver kicks in. // Derived classes may use it to change the list of input files. - virtual void finalizeInputFiles() {} + virtual void finalizeInputFiles() = 0; - TaskGroup &getTaskGroup() { return _taskGroup; } + /// Callback invoked for each file the Resolver decides we are going to load. + /// This can be used to update context state based on the file, and emit + /// errors for any differences between the context state and a loaded file. + /// For example, we can error if we try to load a file which is a different + /// arch from that being linked. + virtual llvm::Error handleLoadedFile(File &file) = 0; /// @} protected: @@ -324,36 +225,25 @@ protected: virtual std::unique_ptr<File> createUndefinedSymbolFile() const; std::unique_ptr<File> createUndefinedSymbolFile(StringRef filename) const; - /// Method to create an internal file for alias symbols - std::unique_ptr<File> createAliasSymbolFile() const; - StringRef _outputPath; StringRef _entrySymbolName; - bool _deadStrip; - bool _allowDuplicates; - bool _globalsAreDeadStripRoots; - bool _searchArchivesToOverrideTentativeDefinitions; - bool _searchSharedLibrariesToOverrideTentativeDefinitions; - bool _warnIfCoalesableAtomsHaveDifferentCanBeNull; - bool _warnIfCoalesableAtomsHaveDifferentLoadName; - bool _printRemainingUndefines; - bool _allowRemainingUndefines; - bool _logInputFiles; - bool _allowShlibUndefines; - OutputFileType _outputFileType; + bool _deadStrip = false; + bool _globalsAreDeadStripRoots = false; + bool _printRemainingUndefines = true; + bool _allowRemainingUndefines = false; + bool _logInputFiles = false; + bool _allowShlibUndefines = false; std::vector<StringRef> _deadStripRoots; - std::map<std::string, std::string> _aliasSymbols; std::vector<const char *> _llvmOptions; StringRefVector _initialUndefinedSymbols; std::vector<std::unique_ptr<Node>> _nodes; mutable llvm::BumpPtrAllocator _allocator; - mutable uint64_t _nextOrdinal; + mutable uint64_t _nextOrdinal = 0; Registry _registry; private: /// Validate the subclass bits. Only called by validate. virtual bool validateImpl(raw_ostream &diagnostics) = 0; - TaskGroup _taskGroup; }; } // end namespace lld diff --git a/include/lld/Core/Node.h b/include/lld/Core/Node.h index cd38fbd4a482..8de0ecdbba6a 100644 --- a/include/lld/Core/Node.h +++ b/include/lld/Core/Node.h @@ -57,7 +57,7 @@ private: class FileNode : public Node { public: explicit FileNode(std::unique_ptr<File> f) - : Node(Node::Kind::File), _file(std::move(f)), _asNeeded(false) {} + : Node(Node::Kind::File), _file(std::move(f)) {} static bool classof(const Node *a) { return a->kind() == Node::Kind::File; @@ -65,12 +65,8 @@ public: File *getFile() { return _file.get(); } - void setAsNeeded(bool val) { _asNeeded = val; } - bool asNeeded() const { return _asNeeded; } - protected: std::unique_ptr<File> _file; - bool _asNeeded; }; } // namespace lld diff --git a/include/lld/Core/Parallel.h b/include/lld/Core/Parallel.h index e2c38308b768..2dde97d9e3f0 100644 --- a/include/lld/Core/Parallel.h +++ b/include/lld/Core/Parallel.h @@ -12,7 +12,6 @@ #include "lld/Core/Instrumentation.h" #include "lld/Core/LLVM.h" -#include "lld/Core/range.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/thread.h" @@ -63,41 +62,6 @@ public: } }; -/// \brief An implementation of future. std::future and std::promise in -/// old libstdc++ have a threading bug; there is a small chance that a -/// call of future::get throws an exception in the normal use case. -/// We want to use our own future implementation until we drop support -/// of old versions of libstdc++. -/// https://gcc.gnu.org/ml/gcc-patches/2014-05/msg01389.html -template<typename T> class Future { -public: - Future() : _hasValue(false) {} - - void set(T &&val) { - assert(!_hasValue); - { - std::unique_lock<std::mutex> lock(_mutex); - _val = val; - _hasValue = true; - } - _cond.notify_all(); - } - - T &get() { - std::unique_lock<std::mutex> lock(_mutex); - if (_hasValue) - return _val; - _cond.wait(lock, [&] { return _hasValue; }); - return _val; - } - -private: - T _val; - bool _hasValue; - std::mutex _mutex; - std::condition_variable _cond; -}; - // Classes in this namespace are implementation details of this header. namespace internal { diff --git a/include/lld/Core/Pass.h b/include/lld/Core/Pass.h index 2e49cd1b8eee..0527f02cd362 100644 --- a/include/lld/Core/Pass.h +++ b/include/lld/Core/Pass.h @@ -13,7 +13,7 @@ #include "lld/Core/Atom.h" #include "lld/Core/File.h" #include "lld/Core/Reference.h" -#include "lld/Core/range.h" +#include "llvm/Support/Error.h" #include <vector> namespace lld { @@ -34,7 +34,7 @@ public: virtual ~Pass() { } /// Do the actual work of the Pass. - virtual std::error_code perform(SimpleFile &mergedFile) = 0; + virtual llvm::Error perform(SimpleFile &mergedFile) = 0; protected: // Only subclassess can be instantiated. diff --git a/include/lld/Core/PassManager.h b/include/lld/Core/PassManager.h index 62aa119f8f76..71a25cc7f3cd 100644 --- a/include/lld/Core/PassManager.h +++ b/include/lld/Core/PassManager.h @@ -12,6 +12,7 @@ #include "lld/Core/LLVM.h" #include "lld/Core/Pass.h" +#include "llvm/Support/Error.h" #include <memory> #include <vector> @@ -31,11 +32,11 @@ public: _passes.push_back(std::move(pass)); } - std::error_code runOnFile(SimpleFile &file) { + llvm::Error runOnFile(SimpleFile &file) { for (std::unique_ptr<Pass> &pass : _passes) - if (std::error_code EC = pass->perform(file)) + if (llvm::Error EC = pass->perform(file)) return EC; - return std::error_code(); + return llvm::Error(); } private: diff --git a/include/lld/Core/Reader.h b/include/lld/Core/Reader.h index 9324da475e3d..66df4380dc76 100644 --- a/include/lld/Core/Reader.h +++ b/include/lld/Core/Reader.h @@ -27,17 +27,14 @@ class IO; } namespace lld { -class ELFLinkingContext; class File; class LinkingContext; -class PECOFFLinkingContext; class MachOLinkingContext; /// \brief An abstract class for reading object files, library files, and /// executable files. /// -/// Each file format (e.g. ELF, mach-o, PECOFF, etc) have a concrete -/// subclass of Reader. +/// Each file format (e.g. mach-o, etc) has a concrete subclass of Reader. class Reader { public: virtual ~Reader() {} @@ -114,11 +111,7 @@ public: // as parameters to the addSupport*() method. void addSupportArchives(bool logLoading); void addSupportYamlFiles(); - void addSupportCOFFObjects(PECOFFLinkingContext &); - void addSupportCOFFImportLibraries(PECOFFLinkingContext &); void addSupportMachOObjects(MachOLinkingContext &); - void addSupportELFObjects(ELFLinkingContext &); - void addSupportELFDynamicSharedObjects(ELFLinkingContext &); /// To convert between kind values and names, the registry walks the list /// of registered kind tables. Each table is a zero terminated array of diff --git a/include/lld/Core/Reference.h b/include/lld/Core/Reference.h index 971721eb7d54..86de4f6a4236 100644 --- a/include/lld/Core/Reference.h +++ b/include/lld/Core/Reference.h @@ -25,15 +25,13 @@ class Atom; /// the Atom, then the function Atom will have a Reference of: offsetInAtom=40, /// kind=callsite, target=malloc, addend=0. /// -/// Besides supporting traditional "relocations", References are also used -/// grouping atoms (group comdat), forcing layout (one atom must follow -/// another), marking data-in-code (jump tables or ARM constants), etc. +/// Besides supporting traditional "relocations", references are also used +/// 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 <namespace, arch, value>. 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. +/// file formats and architectures. /// /// References and atoms form a directed graph. The dead-stripping pass /// traverses them starting from dead-strip root atoms to garbage collect @@ -47,16 +45,14 @@ public: enum class KindNamespace { all = 0, testing = 1, - ELF = 2, - COFF = 3, - mach_o = 4, + mach_o = 2, }; 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, AArch64, AMDGPU, ARM, Hexagon, Mips, x86, x86_64 }; + enum class KindArch { all, AArch64, ARM, x86, x86_64}; KindArch kindArch() const { return (KindArch)_kindArch; } void setKindArch(KindArch a) { _kindArch = (uint8_t)a; } @@ -76,8 +72,6 @@ public: // kindLayoutAfter is treated as a bidirected edge by the dead-stripping // pass. kindLayoutAfter = 1, - // kindGroupChild is treated as a bidirected edge too. - kindGroupChild, kindAssociate, }; diff --git a/include/lld/Core/Resolver.h b/include/lld/Core/Resolver.h index 05af7d9573ea..fb62a779c0a5 100644 --- a/include/lld/Core/Resolver.h +++ b/include/lld/Core/Resolver.h @@ -17,6 +17,7 @@ #include "lld/Core/SymbolTable.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseSet.h" +#include "llvm/Support/ErrorOr.h" #include <set> #include <unordered_map> #include <unordered_set> @@ -31,25 +32,23 @@ class LinkingContext; /// and producing a merged graph. class Resolver { public: - Resolver(LinkingContext &ctx) - : _ctx(ctx), _symbolTable(ctx), _result(new MergedFile()), - _fileIndex(0) {} + Resolver(LinkingContext &ctx) : _ctx(ctx), _result(new MergedFile()) {} // InputFiles::Handler methods - void doDefinedAtom(const DefinedAtom&); - bool doUndefinedAtom(const UndefinedAtom &); - void doSharedLibraryAtom(const SharedLibraryAtom &); - void doAbsoluteAtom(const AbsoluteAtom &); + void doDefinedAtom(OwningAtomPtr<DefinedAtom> atom); + bool doUndefinedAtom(OwningAtomPtr<UndefinedAtom> atom); + void doSharedLibraryAtom(OwningAtomPtr<SharedLibraryAtom> atom); + void doAbsoluteAtom(OwningAtomPtr<AbsoluteAtom> atom); // Handle files, this adds atoms from the current file thats // being processed by the resolver - bool handleFile(File &); + llvm::Expected<bool> handleFile(File &); // Handle an archive library file. - bool handleArchiveFile(File &); + llvm::Expected<bool> handleArchiveFile(File &); // Handle a shared library file. - void handleSharedLibrary(File &); + llvm::Error handleSharedLibrary(File &); /// @brief do work of merging and resolving and return list bool resolve(); @@ -57,37 +56,30 @@ public: std::unique_ptr<SimpleFile> resultFile() { return std::move(_result); } private: - typedef std::function<void(StringRef, bool)> UndefCallback; + typedef std::function<llvm::Expected<bool>(StringRef)> UndefCallback; bool undefinesAdded(int begin, int end); File *getFile(int &index); - /// \brief Add section group/.gnu.linkonce if it does not exist previously. - void maybeAddSectionGroupOrGnuLinkOnce(const DefinedAtom &atom); - /// \brief The main function that iterates over the files to resolve - void updatePreloadArchiveMap(); bool resolveUndefines(); void updateReferences(); void deadStripOptimize(); bool checkUndefines(); void removeCoalescedAwayAtoms(); - void checkDylibSymbolCollisions(); - void forEachUndefines(File &file, bool searchForOverrides, UndefCallback callback); + llvm::Expected<bool> forEachUndefines(File &file, UndefCallback callback); void markLive(const Atom *atom); - void addAtoms(const std::vector<const DefinedAtom *>&); - void maybePreloadArchiveMember(StringRef sym); class MergedFile : public SimpleFile { public: - MergedFile() : SimpleFile("<linker-internal>") {} - void addAtoms(std::vector<const Atom*>& atoms); + MergedFile() : SimpleFile("<linker-internal>", kindResolverMergedObject) {} + void addAtoms(llvm::MutableArrayRef<OwningAtomPtr<Atom>> atoms); }; LinkingContext &_ctx; SymbolTable _symbolTable; - std::vector<const Atom *> _atoms; + std::vector<OwningAtomPtr<Atom>> _atoms; std::set<const Atom *> _deadStripRoots; llvm::DenseSet<const Atom *> _liveAtoms; llvm::DenseSet<const Atom *> _deadAtoms; @@ -97,11 +89,6 @@ private: // --start-group and --end-group std::vector<File *> _files; std::map<File *, bool> _newUndefinesAdded; - size_t _fileIndex; - - // Preloading - llvm::StringMap<ArchiveLibraryFile *> _archiveMap; - llvm::DenseSet<ArchiveLibraryFile *> _archiveSeen; // List of undefined symbols. std::vector<StringRef> _undefines; diff --git a/include/lld/Core/STDExtras.h b/include/lld/Core/STDExtras.h deleted file mode 100644 index 4a6183891844..000000000000 --- a/include/lld/Core/STDExtras.h +++ /dev/null @@ -1,29 +0,0 @@ -//===- lld/Core/STDExtra.h - Helpers for the stdlib -----------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_CORE_STD_EXTRA_H -#define LLD_CORE_STD_EXTRA_H - -namespace lld { -/// \brief Deleter for smart pointers that only calls the destructor. Memory is -/// managed elsewhere. A common use of this is for things allocated with a -/// BumpPtrAllocator. -template <class T> -struct destruct_delete { - void operator ()(T *ptr) { - ptr->~T(); - } -}; - -template <class T> -using unique_bump_ptr = std::unique_ptr<T, destruct_delete<T>>; - -} // end namespace lld - -#endif diff --git a/include/lld/Core/SharedLibraryAtom.h b/include/lld/Core/SharedLibraryAtom.h index 1b0c37c41138..7fec7a3e3d29 100644 --- a/include/lld/Core/SharedLibraryAtom.h +++ b/include/lld/Core/SharedLibraryAtom.h @@ -25,9 +25,7 @@ public: }; /// Returns shared library name used to load it at runtime. - /// On linux that is the DT_NEEDED name. /// On Darwin it is the LC_DYLIB_LOAD dylib name. - /// On Windows it is the DLL name that to be referred from .idata section. virtual StringRef loadName() const = 0; /// Returns if shared library symbol can be missing at runtime and if @@ -46,6 +44,8 @@ public: protected: SharedLibraryAtom() : Atom(definitionSharedLibrary) {} + + ~SharedLibraryAtom() override = default; }; } // namespace lld diff --git a/include/lld/Core/SharedLibraryFile.h b/include/lld/Core/SharedLibraryFile.h index a2907287862d..53bf967b0236 100644 --- a/include/lld/Core/SharedLibraryFile.h +++ b/include/lld/Core/SharedLibraryFile.h @@ -27,29 +27,34 @@ public: /// Check if the shared library exports a symbol with the specified name. /// If so, return a SharedLibraryAtom which represents that exported /// symbol. Otherwise return nullptr. - virtual const SharedLibraryAtom *exports(StringRef name, - bool dataSymbolOnly) const = 0; + virtual OwningAtomPtr<SharedLibraryAtom> exports(StringRef name) const = 0; - // Returns DSO name. It's the soname (ELF), the install name (MachO) or - // the import name (Windows). + // Returns the install name. virtual StringRef getDSOName() const = 0; - const AtomVector<DefinedAtom> &defined() const override { + const AtomRange<DefinedAtom> defined() const override { return _definedAtoms; } - const AtomVector<UndefinedAtom> &undefined() const override { + const AtomRange<UndefinedAtom> undefined() const override { return _undefinedAtoms; } - const AtomVector<SharedLibraryAtom> &sharedLibrary() const override { + const AtomRange<SharedLibraryAtom> sharedLibrary() const override { return _sharedLibraryAtoms; } - const AtomVector<AbsoluteAtom> &absolute() const override { + const AtomRange<AbsoluteAtom> absolute() const override { return _absoluteAtoms; } + void clearAtoms() override { + _definedAtoms.clear(); + _undefinedAtoms.clear(); + _sharedLibraryAtoms.clear(); + _absoluteAtoms.clear(); + } + protected: /// only subclasses of SharedLibraryFile can be instantiated explicit SharedLibraryFile(StringRef path) : File(path, kindSharedLibrary) {} diff --git a/include/lld/Core/Simple.h b/include/lld/Core/Simple.h index 3c204f8ba284..f75b40327db4 100644 --- a/include/lld/Core/Simple.h +++ b/include/lld/Core/Simple.h @@ -15,36 +15,60 @@ #ifndef LLD_CORE_SIMPLE_H #define LLD_CORE_SIMPLE_H +#include "lld/Core/AbsoluteAtom.h" +#include "lld/Core/Atom.h" #include "lld/Core/DefinedAtom.h" #include "lld/Core/File.h" -#include "lld/Core/ArchiveLibraryFile.h" -#include "lld/Core/LinkingContext.h" #include "lld/Core/Reference.h" +#include "lld/Core/SharedLibraryAtom.h" #include "lld/Core/UndefinedAtom.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" #include "llvm/ADT/ilist.h" -#include "llvm/ADT/ilist_node.h" -#include <atomic> +#include "llvm/Support/Allocator.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/ErrorHandling.h" +#include <algorithm> +#include <cassert> +#include <cstdint> +#include <functional> namespace lld { class SimpleFile : public File { public: - SimpleFile(StringRef path) : File(path, kindObject) {} + SimpleFile(StringRef path, File::Kind kind) + : File(path, kind) {} + + ~SimpleFile() override { + _defined.clear(); + _undefined.clear(); + _shared.clear(); + _absolute.clear(); + } - void addAtom(const DefinedAtom &a) { _defined.push_back(&a); } - void addAtom(const UndefinedAtom &a) { _undefined.push_back(&a); } - void addAtom(const SharedLibraryAtom &a) { _shared.push_back(&a); } - void addAtom(const AbsoluteAtom &a) { _absolute.push_back(&a); } + void addAtom(DefinedAtom &a) { + _defined.push_back(OwningAtomPtr<DefinedAtom>(&a)); + } + void addAtom(UndefinedAtom &a) { + _undefined.push_back(OwningAtomPtr<UndefinedAtom>(&a)); + } + void addAtom(SharedLibraryAtom &a) { + _shared.push_back(OwningAtomPtr<SharedLibraryAtom>(&a)); + } + void addAtom(AbsoluteAtom &a) { + _absolute.push_back(OwningAtomPtr<AbsoluteAtom>(&a)); + } void addAtom(const Atom &atom) { if (auto *p = dyn_cast<DefinedAtom>(&atom)) { - _defined.push_back(p); + addAtom(const_cast<DefinedAtom &>(*p)); } else if (auto *p = dyn_cast<UndefinedAtom>(&atom)) { - _undefined.push_back(p); + addAtom(const_cast<UndefinedAtom &>(*p)); } else if (auto *p = dyn_cast<SharedLibraryAtom>(&atom)) { - _shared.push_back(p); + addAtom(const_cast<SharedLibraryAtom &>(*p)); } else if (auto *p = dyn_cast<AbsoluteAtom>(&atom)) { - _absolute.push_back(p); + addAtom(const_cast<AbsoluteAtom &>(*p)); } else { llvm_unreachable("atom has unknown definition kind"); } @@ -52,26 +76,33 @@ public: void removeDefinedAtomsIf(std::function<bool(const DefinedAtom *)> pred) { auto &atoms = _defined; - auto newEnd = std::remove_if(atoms.begin(), atoms.end(), pred); + auto newEnd = std::remove_if(atoms.begin(), atoms.end(), + [&pred](OwningAtomPtr<DefinedAtom> &p) { + return pred(p.get()); + }); atoms.erase(newEnd, atoms.end()); } - const AtomVector<DefinedAtom> &defined() const override { return _defined; } + const AtomRange<DefinedAtom> defined() const override { return _defined; } - const AtomVector<UndefinedAtom> &undefined() const override { + const AtomRange<UndefinedAtom> undefined() const override { return _undefined; } - const AtomVector<SharedLibraryAtom> &sharedLibrary() const override { + const AtomRange<SharedLibraryAtom> sharedLibrary() const override { return _shared; } - const AtomVector<AbsoluteAtom> &absolute() const override { + const AtomRange<AbsoluteAtom> absolute() const override { return _absolute; } - typedef range<std::vector<const DefinedAtom *>::iterator> DefinedAtomRange; - DefinedAtomRange definedAtoms() { return make_range(_defined); } + void clearAtoms() override { + _defined.clear(); + _undefined.clear(); + _shared.clear(); + _absolute.clear(); + } private: AtomVector<DefinedAtom> _defined; @@ -80,48 +111,6 @@ private: AtomVector<AbsoluteAtom> _absolute; }; -/// \brief Archive library file that may be used as a virtual container -/// for symbols that should be added dynamically in response to -/// call to find() method. -class SimpleArchiveLibraryFile : public ArchiveLibraryFile { -public: - SimpleArchiveLibraryFile(StringRef filename) - : ArchiveLibraryFile(filename) {} - - const AtomVector<DefinedAtom> &defined() const override { - return _definedAtoms; - } - - const AtomVector<UndefinedAtom> &undefined() const override { - return _undefinedAtoms; - } - - const AtomVector<SharedLibraryAtom> &sharedLibrary() const override { - return _sharedLibraryAtoms; - } - - const AtomVector<AbsoluteAtom> &absolute() const override { - return _absoluteAtoms; - } - - File *find(StringRef sym, bool dataSymbolOnly) override { - // For descendants: - // do some checks here and return dynamically generated files with atoms. - return nullptr; - } - - std::error_code - parseAllMembers(std::vector<std::unique_ptr<File>> &result) override { - return std::error_code(); - } - -private: - AtomVector<DefinedAtom> _definedAtoms; - AtomVector<UndefinedAtom> _undefinedAtoms; - AtomVector<SharedLibraryAtom> _sharedLibraryAtoms; - AtomVector<AbsoluteAtom> _absoluteAtoms; -}; - class SimpleReference : public Reference { public: SimpleReference(Reference::KindNamespace ns, Reference::KindArch arch, @@ -159,12 +148,13 @@ private: SimpleReference *_prev; }; -} +} // end namespace lld // ilist will lazily create a sentinal (so end() can return a node past the // end of the list). We need this trait so that the sentinal is allocated // via the BumpPtrAllocator. namespace llvm { + template<> struct ilist_sentinel_traits<lld::SimpleReference> { @@ -200,7 +190,8 @@ struct ilist_sentinel_traits<lld::SimpleReference> { private: mutable llvm::BumpPtrAllocator *_allocator; }; -} + +} // end namespace llvm namespace lld { @@ -211,6 +202,10 @@ public: _references.setAllocator(&f.allocator()); } + ~SimpleDefinedAtom() override { + _references.clearAndLeakNodesUnsafely(); + } + const File &file() const override { return _file; } StringRef name() const override { return StringRef(); } @@ -256,9 +251,10 @@ public: it = reinterpret_cast<const void*>(next); } - void addReference(Reference::KindNamespace ns, Reference::KindArch arch, + void addReference(Reference::KindNamespace ns, + Reference::KindArch arch, Reference::KindValue kindValue, uint64_t off, - const Atom *target, Reference::Addend a) { + const Atom *target, Reference::Addend a) override { assert(target && "trying to create reference to nothing"); auto node = new (_file.allocator()) SimpleReference(ns, arch, kindValue, off, target, a); @@ -290,6 +286,7 @@ public: _references.push_back(node); } } + void setOrdinal(uint64_t ord) { _ordinal = ord; } private: @@ -306,6 +303,8 @@ public: assert(!name.empty() && "UndefinedAtoms must have a name"); } + ~SimpleUndefinedAtom() override = default; + /// file - returns the File that produced/owns this Atom const File &file() const override { return _file; } @@ -320,23 +319,6 @@ private: StringRef _name; }; -class SimpleAbsoluteAtom : public AbsoluteAtom { -public: - SimpleAbsoluteAtom(const File &f, StringRef name, Scope s, uint64_t value) - : _file(f), _name(name), _scope(s), _value(value) {} - - const File &file() const override { return _file; } - StringRef name() const override { return _name; } - uint64_t value() const override { return _value; } - Scope scope() const override { return _scope; } - -private: - const File &_file; - StringRef _name; - Scope _scope; - uint64_t _value; -}; - } // end namespace lld -#endif +#endif // LLD_CORE_SIMPLE_H diff --git a/include/lld/Core/SymbolTable.h b/include/lld/Core/SymbolTable.h index 2e4459236d18..db610ad14066 100644 --- a/include/lld/Core/SymbolTable.h +++ b/include/lld/Core/SymbolTable.h @@ -34,8 +34,6 @@ class UndefinedAtom; /// if an atom has been coalesced away. class SymbolTable { public: - explicit SymbolTable(LinkingContext &); - /// @brief add atom to symbol table bool add(const DefinedAtom &); @@ -70,13 +68,6 @@ public: /// @brief if atom has been coalesced away, return true bool isCoalescedAway(const Atom *); - /// @brief Find a group atom. - const Atom *findGroup(StringRef name); - - /// @brief Add a group atom and returns true/false depending on whether the - /// previously existed. - bool addGroup(const DefinedAtom &da); - private: typedef llvm::DenseMap<const Atom *, const Atom *> AtomToAtom; @@ -105,10 +96,8 @@ private: bool addByName(const Atom &); bool addByContent(const DefinedAtom &); - LinkingContext &_ctx; AtomToAtom _replacedAtoms; NameToAtom _nameTable; - NameToAtom _groupTable; AtomContentSet _contentTable; }; diff --git a/include/lld/Core/UndefinedAtom.h b/include/lld/Core/UndefinedAtom.h index 7a835a4ebaa8..f45d6ecda6b0 100644 --- a/include/lld/Core/UndefinedAtom.h +++ b/include/lld/Core/UndefinedAtom.h @@ -57,16 +57,10 @@ public: static bool classof(const UndefinedAtom *) { return true; } - /// Returns an undefined atom if this undefined symbol has a synonym. This is - /// mainly used in COFF. In COFF, an unresolved external symbol can have up to - /// one optional name (sym2) in addition to its regular name (sym1). If a - /// definition of sym1 exists, sym1 is resolved normally. Otherwise, all - /// references to sym1 refer to sym2 instead. In that case sym2 must be - /// resolved, or link will fail. - virtual const UndefinedAtom *fallback() const { return nullptr; } - protected: UndefinedAtom() : Atom(definitionUndefined) {} + + ~UndefinedAtom() override = default; }; } // namespace lld diff --git a/include/lld/Core/Writer.h b/include/lld/Core/Writer.h index 8214ed6203f2..216f934916bc 100644 --- a/include/lld/Core/Writer.h +++ b/include/lld/Core/Writer.h @@ -11,25 +11,24 @@ #define LLD_CORE_WRITER_H #include "lld/Core/LLVM.h" +#include "llvm/Support/Error.h" #include <memory> #include <vector> namespace lld { -class ELFLinkingContext; class File; class LinkingContext; class MachOLinkingContext; -class PECOFFLinkingContext; /// \brief The Writer is an abstract class for writing object files, shared -/// library files, and executable files. Each file format (e.g. ELF, mach-o, -/// PECOFF, etc) have a concrete subclass of Writer. +/// library files, and executable files. Each file format (e.g. mach-o, etc) +/// has a concrete subclass of Writer. class Writer { public: virtual ~Writer(); /// \brief Write a file from the supplied File object - virtual std::error_code writeFile(const File &linkedFile, StringRef path) = 0; + virtual llvm::Error writeFile(const File &linkedFile, StringRef path) = 0; /// \brief 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 @@ -41,9 +40,7 @@ protected: Writer(); }; -std::unique_ptr<Writer> createWriterELF(const ELFLinkingContext &); std::unique_ptr<Writer> createWriterMachO(const MachOLinkingContext &); -std::unique_ptr<Writer> createWriterPECOFF(const PECOFFLinkingContext &); std::unique_ptr<Writer> createWriterYAML(const LinkingContext &); } // end namespace lld diff --git a/include/lld/Core/range.h b/include/lld/Core/range.h deleted file mode 100644 index 614c9672955c..000000000000 --- a/include/lld/Core/range.h +++ /dev/null @@ -1,738 +0,0 @@ -//===-- lld/Core/range.h - Iterator ranges ----------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// \brief Iterator range type based on c++1y range proposal. -/// -/// See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3350.html -/// -//===----------------------------------------------------------------------===// - -#ifndef LLD_CORE_RANGE_H -#define LLD_CORE_RANGE_H - -#include "llvm/Support/Compiler.h" -#include <array> -#include <cassert> -#include <iterator> -#include <string> -#include <type_traits> -#include <utility> -#include <vector> - -namespace lld { -// Nothing in this namespace is part of the exported interface. -namespace detail { -using std::begin; -using std::end; -/// Used as the result type of undefined functions. -struct undefined {}; - -template <typename R> class begin_result { - template <typename T> static auto check(T &&t) -> decltype(begin(t)); - static undefined check(...); -public: - typedef decltype(check(std::declval<R>())) type; -}; - -template <typename R> class end_result { - template <typename T> static auto check(T &&t) -> decltype(end(t)); - static undefined check(...); -public: - typedef decltype(check(std::declval<R>())) type; -}; - -// Things that begin and end work on, in compatible ways, are -// ranges. [stmt.ranged] -template <typename R> -struct is_range : std::is_same<typename detail::begin_result<R>::type, - typename detail::end_result<R>::type> {}; - -// This currently requires specialization and doesn't work for -// detecting \c range<>s or iterators. We should add -// \c contiguous_iterator_tag to fix that. -template <typename R> struct is_contiguous_range : std::false_type {}; -template <typename R> -struct is_contiguous_range<R &> : is_contiguous_range<R> {}; -template <typename R> -struct is_contiguous_range <R &&> : is_contiguous_range<R> {}; -template <typename R> -struct is_contiguous_range<const R> : is_contiguous_range<R> {}; - -template <typename T, size_t N> -struct is_contiguous_range<T[N]> : std::true_type {}; -template <typename T, size_t N> -struct is_contiguous_range<const T[N]> : std::true_type {}; -template <typename T, size_t N> -struct is_contiguous_range<std::array<T, N> > : std::true_type {}; -template <typename charT, typename traits, typename Allocator> -struct is_contiguous_range< - std::basic_string<charT, traits, Allocator> > : std::true_type {}; -template <typename T, typename Allocator> -struct is_contiguous_range<std::vector<T, Allocator> > : std::true_type {}; - -// Removes cv qualifiers from all levels of a multi-level pointer -// type, not just the type level. -template <typename T> struct remove_all_cv_ptr { - typedef T type; -}; -template <typename T> struct remove_all_cv_ptr<T *> { - typedef typename remove_all_cv_ptr<T>::type *type; -}; -template <typename T> struct remove_all_cv_ptr<const T> { - typedef typename remove_all_cv_ptr<T>::type type; -}; -template <typename T> struct remove_all_cv_ptr<volatile T> { - typedef typename remove_all_cv_ptr<T>::type type; -}; -template <typename T> struct remove_all_cv_ptr<const volatile T> { - typedef typename remove_all_cv_ptr<T>::type type; -}; - -template <typename From, typename To> -struct conversion_preserves_array_indexing : std::false_type {}; - -template <typename FromVal, typename ToVal> -struct conversion_preserves_array_indexing<FromVal *, - ToVal *> : std::integral_constant< - bool, std::is_convertible<FromVal *, ToVal *>::value && - std::is_same<typename remove_all_cv_ptr<FromVal>::type, - typename remove_all_cv_ptr<ToVal>::type>::value> {}; - -template <typename T> -LLVM_CONSTEXPR auto adl_begin(T &&t) -> decltype(begin(t)) { - return begin(std::forward<T>(t)); -} - -template <typename T> LLVM_CONSTEXPR auto adl_end(T &&t) -> decltype(end(t)) { - return end(std::forward<T>(t)); -} -} // end namespace detail - -/// A \c std::range<Iterator> represents a half-open iterator range -/// built from two iterators, \c 'begin', and \c 'end'. If \c end is -/// not reachable from \c begin, the behavior is undefined. -/// -/// The mutability of elements of the range is controlled by the -/// Iterator argument. Instantiate -/// <code>range<<var>Foo</var>::iterator></code> or -/// <code>range<<var>T</var>*></code>, or call -/// <code>make_range(<var>non_const_container</var>)</code>, and you -/// get a mutable range. Instantiate -/// <code>range<<var>Foo</var>::const_iterator></code> or -/// <code>range<const <var>T</var>*></code>, or call -/// <code>make_range(<var>const_container</var>)</code>, and you get a -/// constant range. -/// -/// \todo Inherit from std::pair<Iterator, Iterator>? -/// -/// \todo This interface contains some functions that could be -/// provided as free algorithms rather than member functions, and all -/// of the <code>pop_*()</code> functions could be replaced by \c -/// slice() at the cost of some extra iterator copies. This makes -/// them more awkward to use, but makes it easier for users to write -/// their own types that follow the same interface. On the other hand, -/// a \c range_facade could be provided to help users write new -/// ranges, and it could provide the members. Such functions are -/// marked with a note in their documentation. (Of course, all of -/// these member functions could be provided as free functions using -/// the iterator access methods, but one goal here is to allow people -/// to program without touching iterators at all.) -template <typename Iterator> class range { - Iterator begin_, end_; -public: - /// \name types - /// @{ - - /// The iterator category of \c Iterator. - /// \todo Consider defining range categories. If they don't add - /// anything over the corresponding iterator categories, then - /// they're probably not worth defining. - typedef typename std::iterator_traits< - Iterator>::iterator_category iterator_category; - /// The type of elements of the range. Not cv-qualified. - typedef typename std::iterator_traits<Iterator>::value_type value_type; - /// The type of the size of the range and offsets within the range. - typedef typename std::iterator_traits< - Iterator>::difference_type difference_type; - /// The return type of element access methods: \c front(), \c back(), etc. - typedef typename std::iterator_traits<Iterator>::reference reference; - typedef typename std::iterator_traits<Iterator>::pointer pointer; - /// @} - - /// \name constructors - /// @{ - - /// Creates a range of default-constructed (<em>not</em> - /// value-initialized) iterators. For most \c Iterator types, this - /// will be an invalid range. - range() : begin_(), end_() {} - - /// \pre \c end is reachable from \c begin. - /// \post <code>this->begin() == begin && this->end() == end</code> - LLVM_CONSTEXPR range(Iterator begin, Iterator end) - : begin_(begin), end_(end) {} - - /// \par Participates in overload resolution if: - /// - \c Iterator is not a pointer type, - /// - \c begin(r) and \c end(r) return the same type, and - /// - that type is convertible to \c Iterator. - /// - /// \todo std::begin and std::end are overloaded between T& and - /// const T&, which means that if a container has only a non-const - /// begin or end method, then it's ill-formed to pass an rvalue to - /// the free function. To avoid that problem, we don't use - /// std::forward<> here, so begin() and end() are always called with - /// an lvalue. Another option would be to insist that rvalue - /// arguments to range() must have const begin() and end() methods. - template <typename R> LLVM_CONSTEXPR range( - R &&r, - typename std::enable_if< - !std::is_pointer<Iterator>::value && - detail::is_range<R>::value && - std::is_convertible<typename detail::begin_result<R>::type, - Iterator>::value>::type* = 0) - : begin_(detail::adl_begin(r)), end_(detail::adl_end(r)) {} - - /// This constructor creates a \c range<T*> from any range with - /// contiguous iterators. Because dereferencing a past-the-end - /// iterator can be undefined behavior, empty ranges get initialized - /// with \c nullptr rather than \c &*begin(). - /// - /// \par Participates in overload resolution if: - /// - \c Iterator is a pointer type \c T*, - /// - \c begin(r) and \c end(r) return the same type, - /// - elements \c i of that type satisfy the invariant - /// <code>&*(i + N) == (&*i) + N</code>, and - /// - The result of <code>&*begin()</code> is convertible to \c T* - /// using only qualification conversions [conv.qual] (since - /// pointer conversions stop the pointer from pointing to an - /// array element). - /// - /// \todo The <code>&*(i + N) == (&*i) + N</code> invariant is - /// currently impossible to check for user-defined types. We need a - /// \c contiguous_iterator_tag to let users assert it. - template <typename R> LLVM_CONSTEXPR range( - R &&r, - typename std::enable_if< - std::is_pointer<Iterator>::value && - detail::is_contiguous_range<R>::value - // MSVC returns false for this in this context, but not if we lift it out of the - // constructor. -#ifndef _MSC_VER - && detail::conversion_preserves_array_indexing< - decltype(&*detail::adl_begin(r)), Iterator>::value -#endif - >::type* = 0) - : begin_((detail::adl_begin(r) == detail::adl_end(r) && - !std::is_pointer<decltype(detail::adl_begin(r))>::value) - // For non-pointers, &*begin(r) is only defined behavior - // if there's an element there. Otherwise, use nullptr - // since the user can't dereference it anyway. This _is_ - // detectable. - ? nullptr : &*detail::adl_begin(r)), - end_(begin_ + (detail::adl_end(r) - detail::adl_begin(r))) {} - - /// @} - - /// \name iterator access - /// @{ - LLVM_CONSTEXPR Iterator begin() const { return begin_; } - LLVM_CONSTEXPR Iterator end() const { return end_; } - /// @} - - /// \name element access - /// @{ - - /// \par Complexity: - /// O(1) - /// \pre \c !empty() - /// \returns a reference to the element at the front of the range. - LLVM_CONSTEXPR reference front() const { return *begin(); } - - /// \par Ill-formed unless: - /// \c iterator_category is convertible to \c - /// std::bidirectional_iterator_tag. - /// - /// \par Complexity: - /// O(2) (Involves copying and decrementing an iterator, so not - /// quite as cheap as \c front()) - /// - /// \pre \c !empty() - /// \returns a reference to the element at the front of the range. - LLVM_CONSTEXPR reference back() const { - static_assert( - std::is_convertible<iterator_category, - std::bidirectional_iterator_tag>::value, - "Can only retrieve the last element of a bidirectional range."); - using std::prev; - return *prev(end()); - } - - /// This method is drawn from scripting language indexing. It - /// indexes std::forward from the beginning of the range if the argument - /// is positive, or backwards from the end of the array if the - /// argument is negative. - /// - /// \par Ill-formed unless: - /// \c iterator_category is convertible to \c - /// std::random_access_iterator_tag. - /// - /// \par Complexity: - /// O(1) - /// - /// \pre <code>abs(index) < size() || index == -size()</code> - /// - /// \returns if <code>index >= 0</code>, a reference to the - /// <code>index</code>'th element in the range. Otherwise, a - /// reference to the <code>size()+index</code>'th element. - LLVM_CONSTEXPR reference operator[](difference_type index) const { - static_assert(std::is_convertible<iterator_category, - std::random_access_iterator_tag>::value, - "Can only index into a random-access range."); - // Less readable construction for constexpr support. - return index < 0 ? end()[index] - : begin()[index]; - } - /// @} - - /// \name size - /// @{ - - /// \par Complexity: - /// O(1) - /// \returns \c true if the range contains no elements. - LLVM_CONSTEXPR bool empty() const { return begin() == end(); } - - /// \par Ill-formed unless: - /// \c iterator_category is convertible to - /// \c std::forward_iterator_tag. - /// - /// \par Complexity: - /// O(1) if \c iterator_category is convertible to \c - /// std::random_access_iterator_tag. O(<code>size()</code>) - /// otherwise. - /// - /// \returns the number of times \c pop_front() can be called before - /// \c empty() becomes true. - LLVM_CONSTEXPR difference_type size() const { - static_assert(std::is_convertible<iterator_category, - std::forward_iterator_tag>::value, - "Calling size on an input range would destroy the range."); - return dispatch_size(iterator_category()); - } - /// @} - - /// \name traversal from the beginning of the range - /// @{ - - /// Advances the beginning of the range by one element. - /// \pre \c !empty() - void pop_front() { ++begin_; } - - /// Advances the beginning of the range by \c n elements. - /// - /// \par Complexity: - /// O(1) if \c iterator_category is convertible to \c - /// std::random_access_iterator_tag, O(<code>n</code>) otherwise. - /// - /// \pre <code>n >= 0</code>, and there must be at least \c n - /// elements in the range. - void pop_front(difference_type n) { advance(begin_, n); } - - /// Advances the beginning of the range by at most \c n elements, - /// stopping if the range becomes empty. A negative argument causes - /// no change. - /// - /// \par Complexity: - /// O(1) if \c iterator_category is convertible to \c - /// std::random_access_iterator_tag, O(<code>min(n, - /// <var>#-elements-in-range</var>)</code>) otherwise. - /// - /// \note Could be provided as a free function with little-to-no - /// loss in efficiency. - void pop_front_upto(difference_type n) { - advance_upto(begin_, std::max<difference_type>(0, n), end_, - iterator_category()); - } - - /// @} - - /// \name traversal from the end of the range - /// @{ - - /// Moves the end of the range earlier by one element. - /// - /// \par Ill-formed unless: - /// \c iterator_category is convertible to - /// \c std::bidirectional_iterator_tag. - /// - /// \par Complexity: - /// O(1) - /// - /// \pre \c !empty() - void pop_back() { - static_assert(std::is_convertible<iterator_category, - std::bidirectional_iterator_tag>::value, - "Can only access the end of a bidirectional range."); - --end_; - } - - /// Moves the end of the range earlier by \c n elements. - /// - /// \par Ill-formed unless: - /// \c iterator_category is convertible to - /// \c std::bidirectional_iterator_tag. - /// - /// \par Complexity: - /// O(1) if \c iterator_category is convertible to \c - /// std::random_access_iterator_tag, O(<code>n</code>) otherwise. - /// - /// \pre <code>n >= 0</code>, and there must be at least \c n - /// elements in the range. - void pop_back(difference_type n) { - static_assert(std::is_convertible<iterator_category, - std::bidirectional_iterator_tag>::value, - "Can only access the end of a bidirectional range."); - advance(end_, -n); - } - - /// Moves the end of the range earlier by <code>min(n, - /// size())</code> elements. A negative argument causes no change. - /// - /// \par Ill-formed unless: - /// \c iterator_category is convertible to - /// \c std::bidirectional_iterator_tag. - /// - /// \par Complexity: - /// O(1) if \c iterator_category is convertible to \c - /// std::random_access_iterator_tag, O(<code>min(n, - /// <var>#-elements-in-range</var>)</code>) otherwise. - /// - /// \note Could be provided as a free function with little-to-no - /// loss in efficiency. - void pop_back_upto(difference_type n) { - static_assert(std::is_convertible<iterator_category, - std::bidirectional_iterator_tag>::value, - "Can only access the end of a bidirectional range."); - advance_upto(end_, -std::max<difference_type>(0, n), begin_, - iterator_category()); - } - - /// @} - - /// \name creating derived ranges - /// @{ - - /// Divides the range into two pieces at \c index, where a positive - /// \c index represents an offset from the beginning of the range - /// and a negative \c index represents an offset from the end. - /// <code>range[index]</code> is the first element in the second - /// piece. If <code>index >= size()</code>, the second piece - /// will be empty. If <code>index < -size()</code>, the first - /// piece will be empty. - /// - /// \par Ill-formed unless: - /// \c iterator_category is convertible to - /// \c std::forward_iterator_tag. - /// - /// \par Complexity: - /// - If \c iterator_category is convertible to \c - /// std::random_access_iterator_tag: O(1) - /// - Otherwise, if \c iterator_category is convertible to \c - /// std::bidirectional_iterator_tag, \c abs(index) iterator increments - /// or decrements - /// - Otherwise, if <code>index >= 0</code>, \c index iterator - /// increments - /// - Otherwise, <code>size() + (size() + index)</code> - /// iterator increments. - /// - /// \returns a pair of adjacent ranges. - /// - /// \post - /// - <code>result.first.size() == min(index, this->size())</code> - /// - <code>result.first.end() == result.second.begin()</code> - /// - <code>result.first.size() + result.second.size()</code> <code>== - /// this->size()</code> - /// - /// \todo split() could take an arbitrary number of indices and - /// return an <code>N+1</code>-element \c tuple<>. This is tricky to - /// implement with negative indices in the optimal number of - /// increments or decrements for a bidirectional iterator, but it - /// should be possible. Do we want it? - std::pair<range, range> split(difference_type index) const { - static_assert( - std::is_convertible<iterator_category, - std::forward_iterator_tag>::value, - "Calling split on a non-std::forward range would return a useless " - "first result."); - if (index >= 0) { - range second = *this; - second.pop_front_upto(index); - return make_pair(range(begin(), second.begin()), second); - } else { - return dispatch_split_neg(index, iterator_category()); - } - } - - /// \returns A sub-range from \c start to \c stop (not including \c - /// stop, as usual). \c start and \c stop are interpreted as for - /// <code>operator[]</code>, with negative values offsetting from - /// the end of the range. Omitting the \c stop argument makes the - /// sub-range continue to the end of the original range. Positive - /// arguments saturate to the end of the range, and negative - /// arguments saturate to the beginning. If \c stop is before \c - /// start, returns an empty range beginning and ending at \c start. - /// - /// \par Ill-formed unless: - /// \c iterator_category is convertible to - /// \c std::forward_iterator_tag. - /// - /// \par Complexity: - /// - If \c iterator_category is convertible to \c - /// std::random_access_iterator_tag: O(1) - /// - Otherwise, if \c iterator_category is convertible to \c - /// std::bidirectional_iterator_tag, at most <code>min(abs(start), - /// size()) + min(abs(stop), size())</code> iterator - /// increments or decrements - /// - Otherwise, if <code>start >= 0 && stop >= 0</code>, - /// <code>max(start, stop)</code> iterator increments - /// - Otherwise, <code>size() + max(start', stop')</code> - /// iterator increments, where \c start' and \c stop' are the - /// offsets of the elements \c start and \c stop refer to. - /// - /// \note \c slice(start) should be implemented with a different - /// overload, rather than defaulting \c stop to - /// <code>numeric_limits<difference_type>::max()</code>, because - /// using a default would force non-random-access ranges to use an - /// O(<code>size()</code>) algorithm to compute the end rather - /// than the O(1) they're capable of. - range slice(difference_type start, difference_type stop) const { - static_assert( - std::is_convertible<iterator_category, - std::forward_iterator_tag>::value, - "Calling slice on a non-std::forward range would destroy the original " - "range."); - return dispatch_slice(start, stop, iterator_category()); - } - - range slice(difference_type start) const { - static_assert( - std::is_convertible<iterator_category, - std::forward_iterator_tag>::value, - "Calling slice on a non-std::forward range would destroy the original " - "range."); - return split(start).second; - } - - /// @} - -private: - // advance_upto: should be added to <algorithm>, but I'll use it as - // a helper function here. - // - // These return the number of increments that weren't applied - // because we ran into 'limit' (or 0 if we didn't run into limit). - static difference_type advance_upto(Iterator &it, difference_type n, - Iterator limit, std::input_iterator_tag) { - if (n < 0) - return 0; - while (it != limit && n > 0) { - ++it; - --n; - } - return n; - } - - static difference_type advance_upto(Iterator &it, difference_type n, - Iterator limit, - std::bidirectional_iterator_tag) { - if (n < 0) { - while (it != limit && n < 0) { - --it; - ++n; - } - } else { - while (it != limit && n > 0) { - ++it; - --n; - } - } - return n; - } - - static difference_type advance_upto(Iterator &it, difference_type n, - Iterator limit, - std::random_access_iterator_tag) { - difference_type distance = limit - it; - if (distance < 0) - assert(n <= 0); - else if (distance > 0) - assert(n >= 0); - - if (abs(distance) > abs(n)) { - it += n; - return 0; - } else { - it = limit; - return n - distance; - } - } - - // Dispatch functions. - difference_type dispatch_size(std::forward_iterator_tag) const { - return std::distance(begin(), end()); - } - - LLVM_CONSTEXPR difference_type dispatch_size( - std::random_access_iterator_tag) const { - return end() - begin(); - } - - std::pair<range, range> dispatch_split_neg(difference_type index, - std::forward_iterator_tag) const { - assert(index < 0); - difference_type size = this->size(); - return split(std::max<difference_type>(0, size + index)); - } - - std::pair<range, range> dispatch_split_neg( - difference_type index, std::bidirectional_iterator_tag) const { - assert(index < 0); - range first = *this; - first.pop_back_upto(-index); - return make_pair(first, range(first.end(), end())); - } - - range dispatch_slice(difference_type start, difference_type stop, - std::forward_iterator_tag) const { - if (start < 0 || stop < 0) { - difference_type size = this->size(); - if (start < 0) - start = std::max<difference_type>(0, size + start); - if (stop < 0) - stop = size + stop; // Possibly negative; will be fixed in 2 lines. - } - stop = std::max<difference_type>(start, stop); - - Iterator first = begin(); - advance_upto(first, start, end(), iterator_category()); - Iterator last = first; - advance_upto(last, stop - start, end(), iterator_category()); - return range(first, last); - } - - range dispatch_slice(const difference_type start, const difference_type stop, - std::bidirectional_iterator_tag) const { - Iterator first; - if (start < 0) { - first = end(); - advance_upto(first, start, begin(), iterator_category()); - } else { - first = begin(); - advance_upto(first, start, end(), iterator_category()); - } - Iterator last; - if (stop < 0) { - last = end(); - advance_upto(last, stop, first, iterator_category()); - } else { - if (start >= 0) { - last = first; - if (stop > start) - advance_upto(last, stop - start, end(), iterator_category()); - } else { - // Complicated: 'start' walked from the end of the sequence, - // but 'stop' needs to walk from the beginning. - Iterator dummy = begin(); - // Walk up to 'stop' increments from begin(), stopping when we - // get to 'first', and capturing the remaining number of - // increments. - difference_type increments_past_start = - advance_upto(dummy, stop, first, iterator_category()); - if (increments_past_start == 0) { - // If this is 0, then stop was before start. - last = first; - } else { - // Otherwise, count that many spaces beyond first. - last = first; - advance_upto(last, increments_past_start, end(), iterator_category()); - } - } - } - return range(first, last); - } - - range dispatch_slice(difference_type start, difference_type stop, - std::random_access_iterator_tag) const { - const difference_type size = this->size(); - if (start < 0) - start = size + start; - if (start < 0) - start = 0; - if (start > size) - start = size; - - if (stop < 0) - stop = size + stop; - if (stop < start) - stop = start; - if (stop > size) - stop = size; - - return range(begin() + start, begin() + stop); - } -}; - -/// \name deducing constructor wrappers -/// \relates std::range -/// \xmlonly <nonmember/> \endxmlonly -/// -/// These functions do the same thing as the constructor with the same -/// signature. They just allow users to avoid writing the iterator -/// type. -/// @{ - -/// \todo I'd like to define a \c make_range taking a single iterator -/// argument representing the beginning of a range that ends with a -/// default-constructed \c Iterator. This would help with using -/// iterators like \c istream_iterator. However, using just \c -/// make_range() could be confusing and lead to people writing -/// incorrect ranges of more common iterators. Is there a better name? -template <typename Iterator> -LLVM_CONSTEXPR range<Iterator> make_range(Iterator begin, Iterator end) { - return range<Iterator>(begin, end); -} - -/// \par Participates in overload resolution if: -/// \c begin(r) and \c end(r) return the same type. -template <typename Range> LLVM_CONSTEXPR auto make_range( - Range &&r, - typename std::enable_if<detail::is_range<Range>::value>::type* = 0) - -> range<decltype(detail::adl_begin(r))> { - return range<decltype(detail::adl_begin(r))>(r); -} - -/// \par Participates in overload resolution if: -/// - \c begin(r) and \c end(r) return the same type, -/// - that type satisfies the invariant that <code>&*(i + N) == -/// (&*i) + N</code>, and -/// - \c &*begin(r) has a pointer type. -template <typename Range> LLVM_CONSTEXPR auto make_ptr_range( - Range &&r, - typename std::enable_if< - detail::is_contiguous_range<Range>::value && - std::is_pointer<decltype(&*detail::adl_begin(r))>::value>::type* = 0) - -> range<decltype(&*detail::adl_begin(r))> { - return range<decltype(&*detail::adl_begin(r))>(r); -} -/// @} -} // end namespace lld - -#endif diff --git a/include/lld/Driver/Driver.h b/include/lld/Driver/Driver.h index 4bf0f43f8ce5..312f4f812b77 100644 --- a/include/lld/Driver/Driver.h +++ b/include/lld/Driver/Driver.h @@ -6,145 +6,27 @@ // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// -/// -/// \file -/// -/// Interface for Drivers which convert command line arguments into -/// LinkingContext objects, then perform the link. -/// -//===----------------------------------------------------------------------===// #ifndef LLD_DRIVER_DRIVER_H #define LLD_DRIVER_DRIVER_H -#include "lld/Core/LLVM.h" -#include "lld/Core/Node.h" -#include "llvm/ADT/Triple.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/Support/raw_ostream.h" -#include <memory> -#include <set> -#include <vector> namespace lld { -class LinkingContext; -class CoreLinkingContext; -class MachOLinkingContext; -class PECOFFLinkingContext; -class ELFLinkingContext; - -typedef std::vector<std::unique_ptr<File>> FileVector; - -FileVector makeErrorFile(StringRef path, std::error_code ec); -FileVector parseMemberFiles(std::unique_ptr<File> File); -FileVector loadFile(LinkingContext &ctx, StringRef path, bool wholeArchive); - -/// Base class for all Drivers. -class Driver { -protected: - - /// Performs link using specified options - static bool link(LinkingContext &context, - raw_ostream &diag = llvm::errs()); - - /// Parses the LLVM options from the context. - static void parseLLVMOptions(const LinkingContext &context); - -private: - Driver() = delete; -}; - -/// Driver for "universal" lld tool which can mimic any linker command line -/// parsing once it figures out which command line flavor to use. -class UniversalDriver : public Driver { -public: - /// Determine flavor and pass control to Driver for that flavor. - static bool link(llvm::MutableArrayRef<const char *> args, - raw_ostream &diag = llvm::errs()); - -private: - UniversalDriver() = delete; -}; - -/// Driver for gnu/binutil 'ld' command line options. -class GnuLdDriver : public Driver { -public: - /// Parses command line arguments same as gnu/binutils ld and performs link. - /// Returns true iff an error occurred. - static bool linkELF(llvm::ArrayRef<const char *> args, - raw_ostream &diag = llvm::errs()); - - /// Uses gnu/binutils style ld command line options to fill in options struct. - /// Returns true iff there was an error. - static bool parse(llvm::ArrayRef<const char *> args, - std::unique_ptr<ELFLinkingContext> &context, - raw_ostream &diag = llvm::errs()); - - /// Parses a given memory buffer as a linker script and evaluate that. - /// Public function for testing. - static std::error_code evalLinkerScript(ELFLinkingContext &ctx, - std::unique_ptr<MemoryBuffer> mb, - raw_ostream &diag, bool nostdlib); - - /// A factory method to create an instance of ELFLinkingContext. - static std::unique_ptr<ELFLinkingContext> - createELFLinkingContext(llvm::Triple triple); - -private: - static llvm::Triple getDefaultTarget(const char *progName); - static bool applyEmulation(llvm::Triple &triple, - llvm::opt::InputArgList &args, - raw_ostream &diag); - static void addPlatformSearchDirs(ELFLinkingContext &ctx, - llvm::Triple &triple, - llvm::Triple &baseTriple); - - GnuLdDriver() = delete; -}; - -/// Driver for darwin/ld64 'ld' command line options. -class DarwinLdDriver : public Driver { -public: - /// Parses command line arguments same as darwin's ld and performs link. - /// Returns true iff there was an error. - static bool linkMachO(llvm::ArrayRef<const char *> args, - raw_ostream &diag = llvm::errs()); - - /// Uses darwin style ld command line options to update LinkingContext object. - /// Returns true iff there was an error. - static bool parse(llvm::ArrayRef<const char *> args, - MachOLinkingContext &info, - raw_ostream &diag = llvm::errs()); - -private: - DarwinLdDriver() = delete; -}; - -/// Driver for Windows 'link.exe' command line options namespace coff { -void link(llvm::ArrayRef<const char *> args); +bool link(llvm::ArrayRef<const char *> Args); } -namespace elf2 { -void link(llvm::ArrayRef<const char *> args); +namespace elf { +bool link(llvm::ArrayRef<const char *> Args, + llvm::raw_ostream &Diag = llvm::errs()); } -/// Driver for lld unit tests -class CoreDriver : public Driver { -public: - /// Parses command line arguments same as lld-core and performs link. - /// Returns true iff there was an error. - static bool link(llvm::ArrayRef<const char *> args, - raw_ostream &diag = llvm::errs()); - - /// Uses lld-core command line options to fill in options struct. - /// Returns true iff there was an error. - static bool parse(llvm::ArrayRef<const char *> args, CoreLinkingContext &info, - raw_ostream &diag = llvm::errs()); - -private: - CoreDriver() = delete; -}; - -} // end namespace lld +namespace mach_o { +bool link(llvm::ArrayRef<const char *> Args, + llvm::raw_ostream &Diag = llvm::errs()); +} +} #endif diff --git a/include/lld/ReaderWriter/AtomLayout.h b/include/lld/ReaderWriter/AtomLayout.h deleted file mode 100644 index ad4cd0607b88..000000000000 --- a/include/lld/ReaderWriter/AtomLayout.h +++ /dev/null @@ -1,39 +0,0 @@ -//===- include/lld/ReaderWriter/AtomLayout.h ------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_READER_WRITER_ATOM_LAYOUT_H -#define LLD_READER_WRITER_ATOM_LAYOUT_H - -namespace lld { -class Atom; - -/// AtomLayouts are used by a writer to manage physical positions of atoms. -/// AtomLayout has two positions; one is file offset, and the other is the -/// address when loaded into memory. -/// -/// Construction of AtomLayouts is usually a multi-pass process. When an atom -/// is appended to a section, we don't know the starting address of the -/// section. Thus, we have no choice but to store the offset from the -/// beginning of the section as AtomLayout values. After all sections starting -/// address are fixed, AtomLayout is revisited to get the offsets updated by -/// adding the starting addresses of the section. -struct AtomLayout { - AtomLayout(const Atom *a, uint64_t fileOff, uint64_t virAddr) - : _atom(a), _fileOffset(fileOff), _virtualAddr(virAddr) {} - - AtomLayout() : _atom(nullptr), _fileOffset(0), _virtualAddr(0) {} - - const Atom *_atom; - uint64_t _fileOffset; - uint64_t _virtualAddr; -}; - -} - -#endif diff --git a/include/lld/ReaderWriter/CoreLinkingContext.h b/include/lld/ReaderWriter/CoreLinkingContext.h deleted file mode 100644 index d597ca46ddc7..000000000000 --- a/include/lld/ReaderWriter/CoreLinkingContext.h +++ /dev/null @@ -1,47 +0,0 @@ -//===- lld/ReaderWriter/CoreLinkingContext.h ------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_READER_WRITER_CORE_LINKER_CONTEXT_H -#define LLD_READER_WRITER_CORE_LINKER_CONTEXT_H - -#include "lld/Core/LinkingContext.h" -#include "lld/Core/Reader.h" -#include "lld/Core/Writer.h" -#include "llvm/Support/ErrorHandling.h" - -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, - }; - - bool validateImpl(raw_ostream &diagnostics) override; - void addPasses(PassManager &pm) override; - - void addPassNamed(StringRef name) { _passNames.push_back(name); } - -protected: - Writer &writer() const override; - -private: - std::unique_ptr<Writer> _writer; - std::vector<StringRef> _passNames; -}; - -} // end namespace lld - -#endif diff --git a/include/lld/ReaderWriter/ELFLinkingContext.h b/include/lld/ReaderWriter/ELFLinkingContext.h deleted file mode 100644 index d1a5b28bb61f..000000000000 --- a/include/lld/ReaderWriter/ELFLinkingContext.h +++ /dev/null @@ -1,422 +0,0 @@ -//===- lld/ReaderWriter/ELFLinkingContext.h -------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_READER_WRITER_ELF_LINKER_CONTEXT_H -#define LLD_READER_WRITER_ELF_LINKER_CONTEXT_H - -#include "lld/Core/LinkingContext.h" -#include "lld/Core/Pass.h" -#include "lld/Core/PassManager.h" -#include "lld/Core/STDExtras.h" -#include "lld/Core/range.h" -#include "lld/Core/Reader.h" -#include "lld/Core/Writer.h" -#include "lld/ReaderWriter/LinkerScript.h" -#include "llvm/ADT/StringSet.h" -#include "llvm/ADT/Triple.h" -#include "llvm/Object/ELF.h" -#include "llvm/Support/ELF.h" -#include <map> -#include <memory> -#include <set> - -namespace llvm { -class FileOutputBuffer; -} - -namespace lld { -struct AtomLayout; -class File; -class Reference; - -namespace elf { -using llvm::object::ELF32LE; -using llvm::object::ELF32BE; -using llvm::object::ELF64LE; -using llvm::object::ELF64BE; - -class ELFWriter; - -std::unique_ptr<ELFLinkingContext> createAArch64LinkingContext(llvm::Triple); -std::unique_ptr<ELFLinkingContext> createAMDGPULinkingContext(llvm::Triple); -std::unique_ptr<ELFLinkingContext> createARMLinkingContext(llvm::Triple); -std::unique_ptr<ELFLinkingContext> createExampleLinkingContext(llvm::Triple); -std::unique_ptr<ELFLinkingContext> createHexagonLinkingContext(llvm::Triple); -std::unique_ptr<ELFLinkingContext> createMipsLinkingContext(llvm::Triple); -std::unique_ptr<ELFLinkingContext> createX86LinkingContext(llvm::Triple); -std::unique_ptr<ELFLinkingContext> createX86_64LinkingContext(llvm::Triple); - -class TargetRelocationHandler { -public: - virtual ~TargetRelocationHandler() {} - - virtual std::error_code applyRelocation(ELFWriter &, llvm::FileOutputBuffer &, - const lld::AtomLayout &, - const Reference &) const = 0; -}; - -} // namespace elf - -/// \brief TargetHandler contains all the information responsible to handle a -/// a particular target on ELF. A target might wish to override implementation -/// of creating atoms and how the atoms are written to the output file. -class TargetHandler { -public: - virtual ~TargetHandler() {} - - /// Determines how relocations need to be applied. - virtual const elf::TargetRelocationHandler &getRelocationHandler() const = 0; - - /// Returns a reader for object files. - virtual std::unique_ptr<Reader> getObjReader() = 0; - - /// Returns a reader for .so files. - virtual std::unique_ptr<Reader> getDSOReader() = 0; - - /// Returns a writer to write an ELF file. - virtual std::unique_ptr<Writer> getWriter() = 0; -}; - -class ELFLinkingContext : public LinkingContext { -public: - /// \brief The type of ELF executable that the linker - /// creates. - enum class OutputMagic : uint8_t { - // The default mode, no specific magic set - DEFAULT, - // Disallow shared libraries and don't align sections - // PageAlign Data, Mark Text Segment/Data segment RW - NMAGIC, - // Disallow shared libraries and don't align sections, - // Mark Text Segment/Data segment RW - OMAGIC, - }; - - /// \brief ELF DT_FLAGS. - enum DTFlag : uint32_t { - DT_NOW = 1 << 1, - DT_ORIGIN = 1 << 2, - }; - - llvm::Triple getTriple() const { return _triple; } - - uint64_t getPageSize() const { return _maxPageSize; } - void setMaxPageSize(uint64_t v) { _maxPageSize = v; } - - OutputMagic getOutputMagic() const { return _outputMagic; } - uint16_t getOutputELFType() const { return _outputELFType; } - uint16_t getOutputMachine() const; - bool mergeCommonStrings() const { return _mergeCommonStrings; } - virtual int getMachineType() const = 0; - virtual uint64_t getBaseAddress() const { return _baseAddress; } - virtual void setBaseAddress(uint64_t address) { _baseAddress = address; } - - void notifySymbolTableCoalesce(const Atom *existingAtom, const Atom *newAtom, - bool &useNew) override; - - /// This controls if undefined atoms need to be created for undefines that are - /// present in a SharedLibrary. If this option is set, undefined atoms are - /// created for every undefined symbol that are present in the dynamic table - /// in the shared library - bool useShlibUndefines() const { return _useShlibUndefines; } - - /// \brief Returns true if a given relocation should be added to the - /// dynamic relocation table. - /// - /// This table is evaluated at loadtime by the dynamic loader and is - /// referenced by the DT_RELA{,ENT,SZ} entries in the dynamic table. - /// Relocations that return true will be added to the dynamic relocation - /// table. - virtual bool isDynamicRelocation(const Reference &) const { return false; } - - /// \brief Returns true if a given reference is a copy relocation. - /// - /// If this is a copy relocation, its target must be an ObjectAtom. We must - /// include in DT_NEEDED the name of the library where this object came from. - virtual bool isCopyRelocation(const Reference &) const { return false; } - - bool validateImpl(raw_ostream &diagnostics) override; - - /// \brief Returns true if the linker allows dynamic libraries to be - /// linked with. - /// - /// This is true when the output mode of the executable is set to be - /// having NMAGIC/OMAGIC - bool allowLinkWithDynamicLibraries() const { - if (_outputMagic == OutputMagic::NMAGIC || - _outputMagic == OutputMagic::OMAGIC || _noAllowDynamicLibraries) - return false; - return true; - } - - /// \brief Use Elf_Rela format to output relocation tables. - virtual bool isRelaOutputFormat() const { return true; } - - /// \brief Returns true if a given relocation should be added to PLT. - /// - /// This table holds all of the relocations used for delayed symbol binding. - /// It will be evaluated at load time if LD_BIND_NOW is set. It is referenced - /// by the DT_{JMPREL,PLTRELSZ} entries in the dynamic table. - /// Relocations that return true will be added to the dynamic plt relocation - /// table. - virtual bool isPLTRelocation(const Reference &) const { return false; } - - /// \brief The path to the dynamic interpreter - virtual StringRef getDefaultInterpreter() const { - return "/lib64/ld-linux-x86-64.so.2"; - } - - /// \brief The dynamic linker path set by the --dynamic-linker option - StringRef getInterpreter() const { - if (_dynamicLinkerPath.hasValue()) - return _dynamicLinkerPath.getValue(); - return getDefaultInterpreter(); - } - - /// \brief Returns true if the output have dynamic sections. - bool isDynamic() const; - - /// \brief Returns true if we are creating a shared library. - bool isDynamicLibrary() const { return _outputELFType == llvm::ELF::ET_DYN; } - - /// \brief Returns true if a given relocation is a relative relocation. - virtual bool isRelativeReloc(const Reference &r) const; - - TargetHandler &getTargetHandler() const { - assert(_targetHandler && "Got null TargetHandler!"); - return *_targetHandler; - } - - virtual void registerRelocationNames(Registry &) = 0; - - void addPasses(PassManager &pm) override; - - void setTriple(llvm::Triple trip) { _triple = trip; } - void setNoInhibitExec(bool v) { _noInhibitExec = v; } - void setExportDynamic(bool v) { _exportDynamic = v; } - void setIsStaticExecutable(bool v) { _isStaticExecutable = v; } - void setMergeCommonStrings(bool v) { _mergeCommonStrings = v; } - void setUseShlibUndefines(bool use) { _useShlibUndefines = use; } - void setOutputELFType(uint32_t type) { _outputELFType = type; } - - bool shouldExportDynamic() const { return _exportDynamic; } - - void createInternalFiles(std::vector<std::unique_ptr<File>> &) const override; - - void finalizeInputFiles() override; - - /// \brief Set the dynamic linker path - void setInterpreter(StringRef s) { _dynamicLinkerPath = s; } - - /// \brief Set NMAGIC output kind when the linker specifies --nmagic - /// or -n in the command line - /// Set OMAGIC output kind when the linker specifies --omagic - /// or -N in the command line - void setOutputMagic(OutputMagic magic) { _outputMagic = magic; } - - /// \brief Disallow dynamic libraries during linking - void setNoAllowDynamicLibraries() { _noAllowDynamicLibraries = true; } - - /// Searches directories for a match on the input File - ErrorOr<StringRef> searchLibrary(StringRef libName) const; - - /// \brief Searches directories for a match on the input file. - /// If \p fileName is an absolute path and \p isSysRooted is true, check - /// the file under sysroot directory. If \p fileName is a relative path - /// and is not in the current directory, search the file through library - /// search directories. - ErrorOr<StringRef> searchFile(StringRef fileName, bool isSysRooted) const; - - /// Get the entry symbol name - StringRef entrySymbolName() const override; - - /// \brief Set new initializer function - void setInitFunction(StringRef name) { _initFunction = name; } - - /// \brief Return an initializer function name. - /// Either default "_init" or configured by the -init command line option. - StringRef initFunction() const { return _initFunction; } - - /// \brief Set new finalizer function - void setFiniFunction(StringRef name) { _finiFunction = name; } - - /// \brief Return a finalizer function name. - /// Either default "_fini" or configured by the -fini command line option. - StringRef finiFunction() const { return _finiFunction; } - - /// Add an absolute symbol. Used for --defsym. - void addInitialAbsoluteSymbol(StringRef name, uint64_t addr) { - _absoluteSymbols[name] = addr; - } - - StringRef sharedObjectName() const { return _soname; } - void setSharedObjectName(StringRef soname) { _soname = soname; } - - StringRef getSysroot() const { return _sysrootPath; } - void setSysroot(StringRef path) { _sysrootPath = path; } - - void addRpath(StringRef path) { _rpathList.push_back(path); } - range<const StringRef *> getRpathList() const { return _rpathList; } - - void addRpathLink(StringRef path) { _rpathLinkList.push_back(path); } - range<const StringRef *> getRpathLinkList() const { return _rpathLinkList; } - - const std::map<std::string, uint64_t> &getAbsoluteSymbols() const { - return _absoluteSymbols; - } - - /// \brief Helper function to allocate strings. - StringRef allocateString(StringRef ref) const { - char *x = _allocator.Allocate<char>(ref.size() + 1); - memcpy(x, ref.data(), ref.size()); - x[ref.size()] = '\0'; - return x; - } - - // add search path to list. - void addSearchPath(StringRef ref) { _inputSearchPaths.push_back(ref); } - - // Retrieve search path list. - StringRefVector getSearchPaths() { return _inputSearchPaths; } - - // By default, the linker would merge sections that are read only with - // segments that have read and execute permissions. When the user specifies a - // flag --rosegment, a separate segment needs to be created. - bool mergeRODataToTextSegment() const { return _mergeRODataToTextSegment; } - - void setCreateSeparateROSegment() { _mergeRODataToTextSegment = false; } - - bool isDynamicallyExportedSymbol(StringRef name) const { - return _dynamicallyExportedSymbols.count(name) != 0; - } - - /// \brief Demangle symbols. - std::string demangle(StringRef symbolName) const override; - bool demangleSymbols() const { return _demangle; } - void setDemangleSymbols(bool d) { _demangle = d; } - - /// \brief Align segments. - bool alignSegments() const { return _alignSegments; } - void setAlignSegments(bool align) { _alignSegments = align; } - - /// \brief Enable new dtags. - /// If this flag is set lld emits DT_RUNPATH instead of - /// DT_RPATH. They are functionally equivalent except for - /// the following two differences: - /// - DT_RUNPATH is searched after LD_LIBRARY_PATH, while - /// DT_RPATH is searched before. - /// - DT_RUNPATH is used only to search for direct dependencies - /// of the object it's contained in, while DT_RPATH is used - /// for indirect dependencies as well. - bool getEnableNewDtags() const { return _enableNewDtags; } - void setEnableNewDtags(bool e) { _enableNewDtags = e; } - - /// \brief Discard local symbols. - bool discardLocals() const { return _discardLocals; } - void setDiscardLocals(bool d) { _discardLocals = d; } - - /// \brief Discard temprorary local symbols. - bool discardTempLocals() const { return _discardTempLocals; } - void setDiscardTempLocals(bool d) { _discardTempLocals = d; } - - /// \brief Strip symbols. - bool stripSymbols() const { return _stripSymbols; } - void setStripSymbols(bool strip) { _stripSymbols = strip; } - - /// \brief Collect statistics. - bool collectStats() const { return _collectStats; } - void setCollectStats(bool s) { _collectStats = s; } - - // --wrap option. - void addWrapForSymbol(StringRef sym) { _wrapCalls.insert(sym); } - - // \brief Set DT_FLAGS flag. - void setDTFlag(DTFlag f) { _dtFlags |= f; } - bool getDTFlag(DTFlag f) { return (_dtFlags & f); } - - const llvm::StringSet<> &wrapCalls() const { return _wrapCalls; } - - void setUndefinesResolver(std::unique_ptr<File> resolver); - - script::Sema &linkerScriptSema() { return _linkerScriptSema; } - const script::Sema &linkerScriptSema() const { return _linkerScriptSema; } - - /// Notify the ELFLinkingContext when the new ELF section is read. - void notifyInputSectionName(StringRef name); - /// Encountered C-ident input section names. - const llvm::StringSet<> &cidentSectionNames() const { - return _cidentSections; - } - - // Set R_ARM_TARGET1 relocation behaviour - bool armTarget1Rel() const { return _armTarget1Rel; } - void setArmTarget1Rel(bool value) { _armTarget1Rel = value; } - - // Set R_MIPS_EH relocation behaviour. - bool mipsPcRelEhRel() const { return _mipsPcRelEhRel; } - void setMipsPcRelEhRel(bool value) { _mipsPcRelEhRel = value; } - -protected: - ELFLinkingContext(llvm::Triple triple, std::unique_ptr<TargetHandler> handler) - : _triple(triple), _targetHandler(std::move(handler)) {} - - Writer &writer() const override; - - /// Method to create a internal file for an undefined symbol - std::unique_ptr<File> createUndefinedSymbolFile() const override; - - uint16_t _outputELFType = llvm::ELF::ET_EXEC; - llvm::Triple _triple; - std::unique_ptr<TargetHandler> _targetHandler; - uint64_t _baseAddress = 0; - bool _isStaticExecutable = false; - bool _noInhibitExec = false; - bool _exportDynamic = false; - bool _mergeCommonStrings = false; - bool _useShlibUndefines = true; - bool _dynamicLinkerArg = false; - bool _noAllowDynamicLibraries = false; - bool _mergeRODataToTextSegment = true; - bool _demangle = true; - bool _discardTempLocals = false; - bool _discardLocals = false; - bool _stripSymbols = false; - bool _alignSegments = true; - bool _enableNewDtags = false; - bool _collectStats = false; - bool _armTarget1Rel = false; - bool _mipsPcRelEhRel = false; - uint64_t _maxPageSize = 0x1000; - uint32_t _dtFlags = 0; - - OutputMagic _outputMagic = OutputMagic::DEFAULT; - StringRefVector _inputSearchPaths; - std::unique_ptr<Writer> _writer; - llvm::Optional<StringRef> _dynamicLinkerPath; - StringRef _initFunction = "_init"; - StringRef _finiFunction = "_fini"; - StringRef _sysrootPath = ""; - StringRef _soname; - StringRefVector _rpathList; - StringRefVector _rpathLinkList; - llvm::StringSet<> _wrapCalls; - std::map<std::string, uint64_t> _absoluteSymbols; - llvm::StringSet<> _dynamicallyExportedSymbols; - std::unique_ptr<File> _resolver; - std::mutex _cidentMutex; - llvm::StringSet<> _cidentSections; - - // The linker script semantic object, which owns all script ASTs, is stored - // in the current linking context via _linkerScriptSema. - script::Sema _linkerScriptSema; -}; - -} // end namespace lld - -#endif diff --git a/include/lld/ReaderWriter/LinkerScript.h b/include/lld/ReaderWriter/LinkerScript.h deleted file mode 100644 index 08ccb89ce8c1..000000000000 --- a/include/lld/ReaderWriter/LinkerScript.h +++ /dev/null @@ -1,1471 +0,0 @@ -//===- ReaderWriter/LinkerScript.h ----------------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// \brief Linker script parser. -/// -//===----------------------------------------------------------------------===// - -#ifndef LLD_READER_WRITER_LINKER_SCRIPT_H -#define LLD_READER_WRITER_LINKER_SCRIPT_H - -#include "lld/Core/Error.h" -#include "lld/Core/LLVM.h" -#include "lld/Core/range.h" -#include "llvm/ADT/DenseSet.h" -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/StringMap.h" -#include "llvm/ADT/StringSet.h" -#include "llvm/ADT/StringSwitch.h" -#include "llvm/Support/Allocator.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/SourceMgr.h" -#include "llvm/Support/raw_ostream.h" -#include <memory> -#include <system_error> -#include <unordered_map> -#include <vector> - -namespace lld { -namespace script { -class Token { -public: - enum Kind { - unknown, - eof, - exclaim, - exclaimequal, - amp, - ampequal, - l_paren, - r_paren, - star, - starequal, - plus, - plusequal, - comma, - minus, - minusequal, - slash, - slashequal, - number, - colon, - semicolon, - less, - lessequal, - lessless, - lesslessequal, - equal, - equalequal, - greater, - greaterequal, - greatergreater, - greatergreaterequal, - question, - identifier, - libname, - kw_align, - kw_align_with_input, - kw_as_needed, - kw_at, - kw_discard, - kw_entry, - kw_exclude_file, - kw_extern, - kw_filehdr, - kw_fill, - kw_flags, - kw_group, - kw_hidden, - kw_input, - kw_keep, - kw_length, - kw_memory, - kw_origin, - kw_phdrs, - kw_provide, - kw_provide_hidden, - kw_only_if_ro, - kw_only_if_rw, - kw_output, - kw_output_arch, - kw_output_format, - kw_overlay, - kw_search_dir, - kw_sections, - kw_sort_by_alignment, - kw_sort_by_init_priority, - kw_sort_by_name, - kw_sort_none, - kw_subalign, - l_brace, - pipe, - pipeequal, - r_brace, - tilde - }; - - Token() : _kind(unknown) {} - Token(StringRef range, Kind kind) : _range(range), _kind(kind) {} - - void dump(raw_ostream &os) const; - - StringRef _range; - Kind _kind; -}; - -class Lexer { -public: - explicit Lexer(std::unique_ptr<MemoryBuffer> mb) : _buffer(mb->getBuffer()) { - _sourceManager.AddNewSourceBuffer(std::move(mb), llvm::SMLoc()); - } - - void lex(Token &tok); - - const llvm::SourceMgr &getSourceMgr() const { return _sourceManager; } - -private: - bool canStartNumber(char c) const; - bool canContinueNumber(char c) const; - bool canStartName(char c) const; - bool canContinueName(char c) const; - void skipWhitespace(); - - Token _current; - /// \brief The current buffer state. - StringRef _buffer; - // Lexer owns the input files. - llvm::SourceMgr _sourceManager; -}; - -/// All linker scripts commands derive from this class. High-level, sections and -/// output section commands are all subclasses of this class. -/// Examples: -/// -/// OUTPUT_FORMAT("elf64-x86-64") /* A linker script command */ -/// OUTPUT_ARCH(i386:x86-64) /* Another command */ -/// ENTRY(_start) /* Another command */ -/// -/// SECTIONS /* Another command */ -/// { -/// .interp : { /* A sections-command */ -/// *(.interp) /* An output-section-command */ -/// } -/// } -/// -class Command { -public: - enum class Kind { - Entry, - Extern, - Fill, - Group, - Input, - InputSectionsCmd, - InputSectionName, - Memory, - Output, - OutputArch, - OutputFormat, - OutputSectionDescription, - Overlay, - PHDRS, - SearchDir, - Sections, - SortedGroup, - SymbolAssignment, - }; - - Kind getKind() const { return _kind; } - inline llvm::BumpPtrAllocator &getAllocator() const; - - virtual void dump(raw_ostream &os) const = 0; - - virtual ~Command() {} - -protected: - Command(class Parser &ctx, Kind k) : _ctx(ctx), _kind(k) {} - -private: - Parser &_ctx; - Kind _kind; -}; - -template <class T> -ArrayRef<T> save_array(llvm::BumpPtrAllocator &alloc, ArrayRef<T> array) { - size_t num = array.size(); - T *start = alloc.Allocate<T>(num); - std::uninitialized_copy(std::begin(array), std::end(array), start); - return llvm::makeArrayRef(start, num); -} - -class Output : public Command { -public: - Output(Parser &ctx, StringRef outputFileName) - : Command(ctx, Kind::Output), _outputFileName(outputFileName) {} - - static bool classof(const Command *c) { return c->getKind() == Kind::Output; } - - void dump(raw_ostream &os) const override { - os << "OUTPUT(" << _outputFileName << ")\n"; - } - - StringRef getOutputFileName() const { return _outputFileName; } - -private: - StringRef _outputFileName; -}; - -class OutputFormat : public Command { -public: - OutputFormat(Parser &ctx, const SmallVectorImpl<StringRef> &formats) - : Command(ctx, Kind::OutputFormat) { - _formats = save_array<StringRef>(getAllocator(), formats); - } - - static bool classof(const Command *c) { - return c->getKind() == Kind::OutputFormat; - } - - void dump(raw_ostream &os) const override { - os << "OUTPUT_FORMAT("; - bool first = true; - for (StringRef format : _formats) { - if (!first) - os << ","; - first = false; - os << "\"" << format << "\""; - } - os << ")\n"; - } - - llvm::ArrayRef<StringRef> getFormats() { return _formats; } - -private: - llvm::ArrayRef<StringRef> _formats; -}; - -class OutputArch : public Command { -public: - OutputArch(Parser &ctx, StringRef arch) - : Command(ctx, Kind::OutputArch), _arch(arch) {} - - static bool classof(const Command *c) { - return c->getKind() == Kind::OutputArch; - } - - void dump(raw_ostream &os) const override { - os << "OUTPUT_ARCH(" << getArch() << ")\n"; - } - - StringRef getArch() const { return _arch; } - -private: - StringRef _arch; -}; - -struct Path { - StringRef _path; - bool _asNeeded; - bool _isDashlPrefix; - - Path() : _asNeeded(false), _isDashlPrefix(false) {} - Path(StringRef path, bool asNeeded = false, bool isLib = false) - : _path(path), _asNeeded(asNeeded), _isDashlPrefix(isLib) {} -}; - -template<Command::Kind K> -class PathList : public Command { -public: - PathList(Parser &ctx, StringRef name, const SmallVectorImpl<Path> &paths) - : Command(ctx, K), _name(name) { - _paths = save_array<Path>(getAllocator(), paths); - } - - static bool classof(const Command *c) { return c->getKind() == K; } - - void dump(raw_ostream &os) const override { - os << _name << "("; - bool first = true; - for (const Path &path : getPaths()) { - if (!first) - os << " "; - first = false; - if (path._asNeeded) - os << "AS_NEEDED("; - if (path._isDashlPrefix) - os << "-l"; - os << path._path; - if (path._asNeeded) - os << ")"; - } - os << ")\n"; - } - - llvm::ArrayRef<Path> getPaths() const { return _paths; } - -private: - StringRef _name; - llvm::ArrayRef<Path> _paths; -}; - -class Group : public PathList<Command::Kind::Group> { -public: - template <class RangeT> - Group(Parser &ctx, RangeT range) - : PathList(ctx, "GROUP", std::move(range)) {} -}; - -class Input : public PathList<Command::Kind::Input> { -public: - template <class RangeT> - Input(Parser &ctx, RangeT range) - : PathList(ctx, "INPUT", std::move(range)) {} -}; - -class Entry : public Command { -public: - Entry(Parser &ctx, StringRef entryName) - : Command(ctx, Kind::Entry), _entryName(entryName) {} - - static bool classof(const Command *c) { return c->getKind() == Kind::Entry; } - - void dump(raw_ostream &os) const override { - os << "ENTRY(" << _entryName << ")\n"; - } - - StringRef getEntryName() const { return _entryName; } - -private: - StringRef _entryName; -}; - -class SearchDir : public Command { -public: - SearchDir(Parser &ctx, StringRef searchPath) - : Command(ctx, Kind::SearchDir), _searchPath(searchPath) {} - - static bool classof(const Command *c) { - return c->getKind() == Kind::SearchDir; - } - - void dump(raw_ostream &os) const override { - os << "SEARCH_DIR(\"" << _searchPath << "\")\n"; - } - - StringRef getSearchPath() const { return _searchPath; } - -private: - StringRef _searchPath; -}; - -/// Superclass for expression nodes. Linker scripts accept C-like expressions in -/// many places, such as when defining the value of a symbol or the address of -/// an output section. -/// Example: -/// -/// SECTIONS { -/// my_symbol = 1 + 1 * 2; -/// | | ^~~~> Constant : Expression -/// | | ^~~~> Constant : Expression -/// | | ^~~~> BinOp : Expression -/// ^~~~> Constant : Expression -/// ^~~~> BinOp : Expression (the top-level Expression node) -/// } -/// -class Expression { -public: - // The symbol table does not need to own its string keys and the use of StringMap - // here is an overkill. - typedef llvm::StringMap<int64_t, llvm::BumpPtrAllocator> SymbolTableTy; - - enum class Kind { Constant, Symbol, FunctionCall, Unary, BinOp, - TernaryConditional }; - Kind getKind() const { return _kind; } - inline llvm::BumpPtrAllocator &getAllocator() const; - virtual void dump(raw_ostream &os) const = 0; - virtual ErrorOr<int64_t> - evalExpr(const SymbolTableTy &symbolTable = SymbolTableTy()) const = 0; - virtual ~Expression() {} - -protected: - Expression(class Parser &ctx, Kind k) : _ctx(ctx), _kind(k) {} - -private: - Parser &_ctx; - Kind _kind; -}; - -/// A constant value is stored as unsigned because it represents absolute -/// values. We represent negative numbers by composing the unary '-' operator -/// with a constant. -class Constant : public Expression { -public: - Constant(Parser &ctx, uint64_t num) - : Expression(ctx, Kind::Constant), _num(num) {} - void dump(raw_ostream &os) const override; - - static bool classof(const Expression *c) { - return c->getKind() == Kind::Constant; - } - - ErrorOr<int64_t> evalExpr(const SymbolTableTy &symbolTable) const override; - -private: - uint64_t _num; -}; - -class Symbol : public Expression { -public: - Symbol(Parser &ctx, StringRef name) - : Expression(ctx, Kind::Symbol), _name(name) {} - void dump(raw_ostream &os) const override; - - static bool classof(const Expression *c) { - return c->getKind() == Kind::Symbol; - } - - ErrorOr<int64_t> evalExpr(const SymbolTableTy &symbolTable) const override; - -private: - StringRef _name; -}; - -class FunctionCall : public Expression { -public: - FunctionCall(Parser &ctx, StringRef name, - const SmallVectorImpl<const Expression *> &args) - : Expression(ctx, Kind::FunctionCall), _name(name) { - _args = save_array<const Expression *>(getAllocator(), args); - } - - void dump(raw_ostream &os) const override; - - static bool classof(const Expression *c) { - return c->getKind() == Kind::FunctionCall; - } - - ErrorOr<int64_t> evalExpr(const SymbolTableTy &symbolTable) const override; - -private: - StringRef _name; - llvm::ArrayRef<const Expression *> _args; -}; - -class Unary : public Expression { -public: - enum Operation { - Minus, - Not - }; - - Unary(Parser &ctx, Operation op, const Expression *child) - : Expression(ctx, Kind::Unary), _op(op), _child(child) {} - void dump(raw_ostream &os) const override; - - static bool classof(const Expression *c) { - return c->getKind() == Kind::Unary; - } - - ErrorOr<int64_t> evalExpr(const SymbolTableTy &symbolTable) const override; - -private: - Operation _op; - const Expression *_child; -}; - -class BinOp : public Expression { -public: - enum Operation { - And, - CompareDifferent, - CompareEqual, - CompareGreater, - CompareGreaterEqual, - CompareLess, - CompareLessEqual, - Div, - Mul, - Or, - Shl, - Shr, - Sub, - Sum - }; - - BinOp(Parser &ctx, const Expression *lhs, Operation op, const Expression *rhs) - : Expression(ctx, Kind::BinOp), _op(op), _lhs(lhs), _rhs(rhs) {} - - void dump(raw_ostream &os) const override; - - static bool classof(const Expression *c) { - return c->getKind() == Kind::BinOp; - } - - ErrorOr<int64_t> evalExpr(const SymbolTableTy &symbolTable) const override; - -private: - Operation _op; - const Expression *_lhs; - const Expression *_rhs; -}; - -/// Operands of the ternary operator can be any expression, similar to the other -/// operations, including another ternary operator. To disambiguate the parse -/// tree, note that ternary conditionals have precedence 13 and, different from -/// other operators, associates right-to-left. For example: -/// -/// i = i > 3 ? i < 5 ? 1 : 2 : 0; -/// -/// will have the following parse tree: -/// -/// i = ((i > 3) ? ((i < 5) ? 1 : 2) : 0); -/// -/// The '>' binds tigher because it has precedence 6. When faced with two "?" -/// ternary operators back-to-back, the parser prioritized the rightmost one. -/// -class TernaryConditional : public Expression { -public: - TernaryConditional(Parser &ctx, const Expression *conditional, - const Expression *trueExpr, const Expression *falseExpr) - : Expression(ctx, Kind::TernaryConditional), _conditional(conditional), - _trueExpr(trueExpr), _falseExpr(falseExpr) {} - - void dump(raw_ostream &os) const override; - - static bool classof(const Expression *c) { - return c->getKind() == Kind::TernaryConditional; - } - - ErrorOr<int64_t> evalExpr(const SymbolTableTy &symbolTable) const override; - -private: - const Expression *_conditional; - const Expression *_trueExpr; - const Expression *_falseExpr; -}; - -/// Symbol assignments of the form "symbolname = <expression>" may occur either -/// as sections-commands or as output-section-commands. -/// Example: -/// -/// SECTIONS { -/// mysymbol = . /* SymbolAssignment as a sections-command */ -/// .data : { -/// othersymbol = . /* SymbolAssignment as an output-section-command */ -/// } -///} -/// -class SymbolAssignment : public Command { -public: - enum AssignmentKind { Simple, Sum, Sub, Mul, Div, Shl, Shr, And, Or }; - enum AssignmentVisibility { Default, Hidden, Provide, ProvideHidden }; - - SymbolAssignment(Parser &ctx, StringRef name, const Expression *expr, - AssignmentKind kind, AssignmentVisibility visibility) - : Command(ctx, Kind::SymbolAssignment), _expression(expr), _symbol(name), - _assignmentKind(Simple), _assignmentVisibility(visibility) {} - - static bool classof(const Command *c) { - return c->getKind() == Kind::SymbolAssignment; - } - - void dump(raw_ostream &os) const override; - const Expression *expr() const { return _expression; } - StringRef symbol() const { return _symbol; } - AssignmentKind assignmentKind() const { return _assignmentKind; } - AssignmentVisibility assignmentVisibility() const { - return _assignmentVisibility; - } - -private: - const Expression *_expression; - StringRef _symbol; - AssignmentKind _assignmentKind; - AssignmentVisibility _assignmentVisibility; -}; - -/// Encodes how to sort file names or section names that are expanded from -/// wildcard operators. This typically occurs in constructs such as -/// SECTIONS { .data : SORT_BY_NAME(*)(*) }}, where the order of the expanded -/// names is important to determine which sections go first. -enum class WildcardSortMode { - NA, - ByAlignment, - ByAlignmentAndName, - ByInitPriority, - ByName, - ByNameAndAlignment, - None -}; - -/// Represents either a single input section name or a group of sorted input -/// section names. They specify which sections to map to a given output section. -/// Example: -/// -/// SECTIONS { -/// .x: { *(.text) } -/// /* ^~~~^ InputSectionName : InputSection */ -/// .y: { *(SORT(.text*)) } -/// /* ^~~~~~~~~~~^ InputSectionSortedGroup : InputSection */ -/// } -class InputSection : public Command { -public: - static bool classof(const Command *c) { - return c->getKind() == Kind::InputSectionName || - c->getKind() == Kind::SortedGroup; - } - -protected: - InputSection(Parser &ctx, Kind k) : Command(ctx, k) {} -}; - -class InputSectionName : public InputSection { -public: - InputSectionName(Parser &ctx, StringRef name, bool excludeFile) - : InputSection(ctx, Kind::InputSectionName), _name(name), - _excludeFile(excludeFile) {} - - void dump(raw_ostream &os) const override; - - static bool classof(const Command *c) { - return c->getKind() == Kind::InputSectionName; - } - bool hasExcludeFile() const { return _excludeFile; } - StringRef name() const { return _name; } - -private: - StringRef _name; - bool _excludeFile; -}; - -class InputSectionSortedGroup : public InputSection { -public: - typedef llvm::ArrayRef<const InputSection *>::const_iterator const_iterator; - - InputSectionSortedGroup(Parser &ctx, WildcardSortMode sort, - const SmallVectorImpl<const InputSection *> §ions) - : InputSection(ctx, Kind::SortedGroup), _sortMode(sort) { - _sections = save_array<const InputSection *>(getAllocator(), sections); - } - - void dump(raw_ostream &os) const override; - WildcardSortMode sortMode() const { return _sortMode; } - - static bool classof(const Command *c) { - return c->getKind() == Kind::SortedGroup; - } - - const_iterator begin() const { return _sections.begin(); } - const_iterator end() const { return _sections.end(); } - -private: - WildcardSortMode _sortMode; - llvm::ArrayRef<const InputSection *> _sections; -}; - -/// An output-section-command that maps a series of sections inside a given -/// file-archive pair to an output section. -/// Example: -/// -/// SECTIONS { -/// .x: { *(.text) } -/// /* ^~~~~~~^ InputSectionsCmd */ -/// .y: { w:z(SORT(.text*)) } -/// /* ^~~~~~~~~~~~~~~~^ InputSectionsCmd */ -/// } -class InputSectionsCmd : public Command { -public: - typedef llvm::ArrayRef<const InputSection *>::const_iterator const_iterator; - typedef std::vector<const InputSection *> VectorTy; - - InputSectionsCmd(Parser &ctx, StringRef memberName, StringRef archiveName, - bool keep, WildcardSortMode fileSortMode, - WildcardSortMode archiveSortMode, - const SmallVectorImpl<const InputSection *> §ions) - : Command(ctx, Kind::InputSectionsCmd), _memberName(memberName), - _archiveName(archiveName), _keep(keep), _fileSortMode(fileSortMode), - _archiveSortMode(archiveSortMode) { - _sections = save_array<const InputSection *>(getAllocator(), sections); - } - - void dump(raw_ostream &os) const override; - - static bool classof(const Command *c) { - return c->getKind() == Kind::InputSectionsCmd; - } - - StringRef memberName() const { return _memberName; } - StringRef archiveName() const { return _archiveName; } - const_iterator begin() const { return _sections.begin(); } - const_iterator end() const { return _sections.end(); } - WildcardSortMode archiveSortMode() const { return _archiveSortMode; } - WildcardSortMode fileSortMode() const { return _fileSortMode; } - -private: - StringRef _memberName; - StringRef _archiveName; - bool _keep; - WildcardSortMode _fileSortMode; - WildcardSortMode _archiveSortMode; - llvm::ArrayRef<const InputSection *> _sections; -}; - -class FillCmd : public Command { -public: - FillCmd(Parser &ctx, ArrayRef<uint8_t> bytes) : Command(ctx, Kind::Fill) { - _bytes = save_array<uint8_t>(getAllocator(), bytes); - } - - void dump(raw_ostream &os) const override; - - static bool classof(const Command *c) { - return c->getKind() == Kind::Fill; - } - - ArrayRef<uint8_t> bytes() { return _bytes; } - -private: - ArrayRef<uint8_t> _bytes; -}; - -/// A sections-command to specify which input sections and symbols compose a -/// given output section. -/// Example: -/// -/// SECTIONS { -/// .x: { *(.text) ; symbol = .; } -/// /*^~~~~~~~~~~~~~~~~~~~~~~~~~~~~^ OutputSectionDescription */ -/// .y: { w:z(SORT(.text*)) } -/// /*^~~~~~~~~~~~~~~~~~~~~~~~^ OutputSectionDescription */ -/// .a 0x10000 : ONLY_IF_RW { *(.data*) ; *:libc.a(SORT(*)); } -/// /*^~~~~~~~~~~~~ OutputSectionDescription ~~~~~~~~~~~~~~~~~^ */ -/// } -class OutputSectionDescription : public Command { -public: - enum Constraint { C_None, C_OnlyIfRO, C_OnlyIfRW }; - - typedef llvm::ArrayRef<const Command *>::const_iterator const_iterator; - - OutputSectionDescription( - Parser &ctx, StringRef sectionName, const Expression *address, - const Expression *align, const Expression *subAlign, const Expression *at, - const Expression *fillExpr, StringRef fillStream, bool alignWithInput, - bool discard, Constraint constraint, - const SmallVectorImpl<const Command *> &outputSectionCommands, - ArrayRef<StringRef> phdrs) - : Command(ctx, Kind::OutputSectionDescription), _sectionName(sectionName), - _address(address), _align(align), _subAlign(subAlign), _at(at), - _fillExpr(fillExpr), _fillStream(fillStream), - _alignWithInput(alignWithInput), _discard(discard), - _constraint(constraint) { - _outputSectionCommands = - save_array<const Command *>(getAllocator(), outputSectionCommands); - _phdrs = save_array<StringRef>(getAllocator(), phdrs); - } - - static bool classof(const Command *c) { - return c->getKind() == Kind::OutputSectionDescription; - } - - void dump(raw_ostream &os) const override; - - const_iterator begin() const { return _outputSectionCommands.begin(); } - const_iterator end() const { return _outputSectionCommands.end(); } - StringRef name() const { return _sectionName; } - bool isDiscarded() const { return _discard; } - ArrayRef<StringRef> PHDRs() const { return _phdrs; } - -private: - StringRef _sectionName; - const Expression *_address; - const Expression *_align; - const Expression *_subAlign; - const Expression *_at; - const Expression *_fillExpr; - StringRef _fillStream; - bool _alignWithInput; - bool _discard; - Constraint _constraint; - llvm::ArrayRef<const Command *> _outputSectionCommands; - ArrayRef<StringRef> _phdrs; -}; - -/// Represents an Overlay structure as documented in -/// https://sourceware.org/binutils/docs/ld/Overlay-Description.html#Overlay-Description -class Overlay : public Command { -public: - Overlay(Parser &ctx) : Command(ctx, Kind::Overlay) {} - - static bool classof(const Command *c) { - return c->getKind() == Kind::Overlay; - } - - void dump(raw_ostream &os) const override { os << "Overlay description\n"; } -}; - -class PHDR { -public: - PHDR(StringRef name, uint64_t type, bool includeFileHdr, bool includePHDRs, - const Expression *at, uint64_t flags) - : _name(name), _type(type), _includeFileHdr(includeFileHdr), - _includePHDRs(includePHDRs), _at(at), _flags(flags) {} - - StringRef name() const { return _name; } - uint64_t type() const { return _type; } - bool hasFileHdr() const { return _includeFileHdr; } - bool hasPHDRs() const { return _includePHDRs; } - uint64_t flags() const { return _flags; } - bool isNone() const; - - void dump(raw_ostream &os) const; - -private: - StringRef _name; - uint64_t _type; - bool _includeFileHdr; - bool _includePHDRs; - const Expression *_at; - uint64_t _flags; -}; - -class PHDRS : public Command { -public: - typedef ArrayRef<const PHDR *>::const_iterator const_iterator; - - PHDRS(Parser &ctx, const SmallVectorImpl<const PHDR *> &phdrs) - : Command(ctx, Kind::PHDRS) { - _phdrs = save_array<const PHDR *>(getAllocator(), phdrs); - } - - static bool classof(const Command *c) { - return c->getKind() == Kind::PHDRS; - } - - void dump(raw_ostream &os) const override; - const_iterator begin() const { return _phdrs.begin(); } - const_iterator end() const { return _phdrs.end(); } - -private: - ArrayRef<const PHDR *> _phdrs; -}; - -/// Represents all the contents of the SECTIONS {} construct. -class Sections : public Command { -public: - typedef llvm::ArrayRef<const Command *>::const_iterator const_iterator; - - Sections(Parser &ctx, - const SmallVectorImpl<const Command *> §ionsCommands) - : Command(ctx, Kind::Sections) { - _sectionsCommands = - save_array<const Command *>(getAllocator(), sectionsCommands); - } - - static bool classof(const Command *c) { - return c->getKind() == Kind::Sections; - } - - void dump(raw_ostream &os) const override; - const_iterator begin() const { return _sectionsCommands.begin(); } - const_iterator end() const { return _sectionsCommands.end(); } - -private: - llvm::ArrayRef<const Command *> _sectionsCommands; -}; - -/// Represents a single memory block definition in a MEMORY {} command. -class MemoryBlock { -public: - MemoryBlock(StringRef name, StringRef attr, - const Expression *origin, const Expression *length) - : _name(name), _attr(attr), _origin(origin), _length(length) {} - - void dump(raw_ostream &os) const; - -private: - StringRef _name; - StringRef _attr; - const Expression *_origin; - const Expression *_length; -}; - -/// Represents all the contents of the MEMORY {} command. -class Memory : public Command { -public: - Memory(Parser &ctx, - const SmallVectorImpl<const MemoryBlock *> &blocks) - : Command(ctx, Kind::Memory) { - _blocks = save_array<const MemoryBlock *>(getAllocator(), blocks); - } - - static bool classof(const Command *c) { - return c->getKind() == Kind::Memory; - } - - void dump(raw_ostream &os) const override; - -private: - llvm::ArrayRef<const MemoryBlock *> _blocks; -}; - -/// Represents an extern command. -class Extern : public Command { -public: - typedef llvm::ArrayRef<StringRef>::const_iterator const_iterator; - - Extern(Parser &ctx, - const SmallVectorImpl<StringRef> &symbols) - : Command(ctx, Kind::Extern) { - _symbols = save_array<StringRef>(getAllocator(), symbols); - } - - static bool classof(const Command *c) { - return c->getKind() == Kind::Extern; - } - - void dump(raw_ostream &os) const override; - const_iterator begin() const { return _symbols.begin(); } - const_iterator end() const { return _symbols.end(); } - -private: - llvm::ArrayRef<StringRef> _symbols; -}; - -/// Stores the parse tree of a linker script. -class LinkerScript { -public: - void dump(raw_ostream &os) const { - for (const Command *c : _commands) { - c->dump(os); - if (isa<SymbolAssignment>(c)) - os << "\n"; - } - } - - std::vector<const Command *> _commands; -}; - -/// Recognizes syntactic constructs of a linker script using a predictive -/// parser/recursive descent implementation. -/// -/// Based on the linker script documentation available at -/// https://sourceware.org/binutils/docs/ld/Scripts.html -class Parser { -public: - explicit Parser(std::unique_ptr<MemoryBuffer> mb) - : _lex(std::move(mb)), _peekAvailable(false) {} - - /// Let's not allow copying of Parser class because it would be expensive - /// to update all the AST pointers to a new buffer. - Parser(const Parser &instance) = delete; - - /// Lex and parse the current memory buffer to create a linker script AST. - std::error_code parse(); - - /// Returns a reference to the top level node of the linker script AST. - LinkerScript *get() { return &_script; } - - /// Returns a reference to the underlying allocator. - llvm::BumpPtrAllocator &getAllocator() { return _alloc; } - -private: - /// Advances to the next token, either asking the Lexer to lex the next token - /// or obtaining it from the look ahead buffer. - void consumeToken() { - // First check if the look ahead buffer cached the next token - if (_peekAvailable) { - _tok = _bufferedToken; - _peekAvailable = false; - return; - } - _lex.lex(_tok); - } - - /// Returns the token that succeeds the current one without consuming the - /// current token. This operation will lex an additional token and store it in - /// a private buffer. - const Token &peek() { - if (_peekAvailable) - return _bufferedToken; - - _lex.lex(_bufferedToken); - _peekAvailable = true; - return _bufferedToken; - } - - void error(const Token &tok, Twine msg) { - _lex.getSourceMgr().PrintMessage( - llvm::SMLoc::getFromPointer(tok._range.data()), - llvm::SourceMgr::DK_Error, msg); - } - - bool expectAndConsume(Token::Kind kind, Twine msg) { - if (_tok._kind != kind) { - error(_tok, msg); - return false; - } - consumeToken(); - return true; - } - - bool isNextToken(Token::Kind kind) { return (_tok._kind == kind); } - - // Recursive descent parsing member functions - // All of these functions consumes tokens and return an AST object, - // represented by the Command superclass. However, note that not all AST - // objects derive from Command. For nodes of C-like expressions, used in - // linker scripts, the superclass is Expression. For nodes that represent - // input sections that map to an output section, the superclass is - // InputSection. - // - // Example mapping common constructs to AST nodes: - // - // SECTIONS { /* Parsed to Sections class */ - // my_symbol = 1 + 1; /* Parsed to SymbolAssignment class */ - // /* ^~~> Parsed to Expression class */ - // .data : { *(.data) } /* Parsed to OutputSectionDescription class */ - // /* ^~~> Parsed to InputSectionName class */ - // /* ^~~~~> Parsed to InputSectionsCmd class */ - // } - - // ==== Expression parsing member functions ==== - - /// Parse "identifier(param [, param]...)" - /// - /// Example: - /// - /// SECTIONS { - /// my_symbol = 0x1000 | ALIGN(other_symbol); - /// /* ^~~~> parseFunctionCall() - /// } - const Expression *parseFunctionCall(); - - /// Ensures that the current token is an expression operand. If it is not, - /// issues an error to the user and returns false. - bool expectExprOperand(); - - /// Parse operands of an expression, such as function calls, identifiers, - /// literal numbers or unary operators. - /// - /// Example: - /// - /// SECTIONS { - /// my_symbol = 0x1000 | ALIGN(other_symbol); - /// ^~~~> parseExprTerminal() - /// } - const Expression *parseExprOperand(); - - // As a reference to the precedence of C operators, consult - // http://en.cppreference.com/w/c/language/operator_precedence - - /// Parse either a single expression operand and returns or parse an entire - /// expression if its top-level node has a lower or equal precedence than the - /// indicated. - const Expression *parseExpression(unsigned precedence = 13); - - /// Parse an operator and its rhs operand, assuming that the lhs was already - /// consumed. Keep parsing subsequent operator-operand pairs that do not - /// exceed highestPrecedence. - /// * lhs points to the left-hand-side operand of this operator - /// * maxPrecedence has the maximum operator precedence level that this parse - /// function is allowed to consume. - const Expression *parseOperatorOperandLoop(const Expression *lhs, - unsigned maxPrecedence); - - /// Parse ternary conditionals such as "(condition)? true: false;". This - /// operator has precedence level 13 and associates right-to-left. - const Expression *parseTernaryCondOp(const Expression *lhs); - - // ==== High-level commands parsing ==== - - /// Parse the OUTPUT linker script command. - /// Example: - /// OUTPUT(/path/to/file) - /// ^~~~> parseOutput() - /// - Output *parseOutput(); - - /// Parse the OUTPUT_FORMAT linker script command. - /// Example: - /// - /// OUTPUT_FORMAT(elf64-x86-64,elf64-x86-64,elf64-x86-64) - /// ^~~~> parseOutputFormat() - /// - OutputFormat *parseOutputFormat(); - - /// Parse the OUTPUT_ARCH linker script command. - /// Example: - /// - /// OUTPUT_ARCH(i386:x86-64) - /// ^~~~> parseOutputArch() - /// - OutputArch *parseOutputArch(); - - /// Parse the INPUT or GROUP linker script command. - /// Example: - /// - /// GROUP ( /lib/x86_64-linux-gnu/libc.so.6 - /// /usr/lib/x86_64-linux-gnu/libc_nonshared.a - /// AS_NEEDED ( /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 ) - /// -lm -l:libgcc.a ) - /// - template<class T> T *parsePathList(); - bool parseAsNeeded(SmallVectorImpl<Path> &paths); - - /// Parse the ENTRY linker script command. - /// Example: - /// - /// ENTRY(init) - /// ^~~~> parseEntry() - /// - Entry *parseEntry(); - - /// Parse the SEARCH_DIR linker script command. - /// Example: - /// - /// SEARCH_DIR("/usr/x86_64-linux-gnu/lib64"); - /// ^~~~> parseSearchDir() - /// - SearchDir *parseSearchDir(); - - /// Parse "symbol = expression" commands that live inside the - /// SECTIONS directive. - /// Example: - /// - /// SECTIONS { - /// my_symbol = 1 + 1; - /// ^~~~> parseExpression() - /// ^~~~ parseSymbolAssignment() - /// } - /// - const SymbolAssignment *parseSymbolAssignment(); - - /// Parse "EXCLUDE_FILE" used inside the listing of input section names. - /// Example: - /// - /// SECTIONS { - /// .data : { *(EXCLUDE_FILE (*crtend.o *otherfile.o) .ctors) } - /// ^~~~> parseExcludeFile() - /// } - /// - ErrorOr<InputSectionsCmd::VectorTy> parseExcludeFile(); - - /// Helper to parse SORT_BY_NAME(, SORT_BY_ALIGNMENT( and SORT_NONE(, - /// possibly nested. Returns the number of Token::r_paren tokens that need - /// to be consumed, while sortMode is updated with the parsed sort - /// criteria. - /// Example: - /// - /// SORT_BY_NAME(SORT_BY_ALIGNMENT(*)) - /// ^~~~ parseSortDirectives() ~~^ - /// Returns 2, finishes with sortMode = WildcardSortMode::ByNameAndAlignment - /// - int parseSortDirectives(WildcardSortMode &sortMode); - - /// Parse a group of input section names that are sorted via SORT* directives. - /// Example: - /// SORT_BY_NAME(SORT_BY_ALIGNMENT(*data *bss)) - const InputSection *parseSortedInputSections(); - - /// Parse input section description statements. - /// Example: - /// - /// SECTIONS { - /// .mysection : crt.o(.data* .bss SORT_BY_NAME(name*)) - /// ^~~~ parseInputSectionsCmd() - /// } - const InputSectionsCmd *parseInputSectionsCmd(); - - const FillCmd *parseFillCmd(); - - /// Parse output section description statements. - /// Example: - /// - /// SECTIONS { - /// .data : { crt.o(.data* .bss SORT_BY_NAME(name*)) } - /// ^~~~ parseOutputSectionDescription() - /// } - const OutputSectionDescription *parseOutputSectionDescription(); - - /// Stub for parsing overlay commands. Currently unimplemented. - const Overlay *parseOverlay(); - - const PHDR *parsePHDR(); - - PHDRS *parsePHDRS(); - - /// Parse the SECTIONS linker script command. - /// Example: - /// - /// SECTIONS { - /// ^~~~ parseSections() - /// . = 0x100000; - /// .data : { *(.data) } - /// } - /// - Sections *parseSections(); - - /// Parse the MEMORY linker script command. - /// Example: - /// - /// MEMORY { - /// ^~~~ parseMemory() - /// ram (rwx) : ORIGIN = 0x20000000, LENGTH = 96K - /// rom (rx) : ORIGIN = 0x0, LENGTH = 256K - /// } - /// - Memory *parseMemory(); - - /// Parse the EXTERN linker script command. - /// Example: - /// - /// EXTERN(symbol symbol ...) - /// ^~~~> parseExtern() - /// - Extern *parseExtern(); - -private: - // Owns the entire linker script AST nodes - llvm::BumpPtrAllocator _alloc; - - // The top-level/entry-point linker script AST node - LinkerScript _script; - - Lexer _lex; - - // Current token being analyzed - Token _tok; - - // Annotate whether we buffered the next token to allow peeking - bool _peekAvailable; - Token _bufferedToken; -}; - -/// script::Sema traverses all parsed linker script structures and populate -/// internal data structures to be able to answer the following questions: -/// -/// * According to the linker script, which input section goes first in the -/// output file layout, input section A or input section B? -/// -/// * What is the name of the output section that input section A should be -/// mapped to? -/// -/// * Which linker script expressions should be calculated before emitting -/// a given section? -/// -/// * How to evaluate a given linker script expression? -/// -class Sema { -public: - /// From the linker script point of view, this class represents the minimum - /// set of information to uniquely identify an input section. - struct SectionKey { - StringRef archivePath; - StringRef memberPath; - StringRef sectionName; - }; - - Sema(); - - /// We can parse several linker scripts via command line whose ASTs are stored - /// here via addLinkerScript(). - void addLinkerScript(std::unique_ptr<Parser> script) { - _scripts.push_back(std::move(script)); - } - - const std::vector<std::unique_ptr<Parser>> &getLinkerScripts() { - return _scripts; - } - - /// Prepare our data structures according to the linker scripts currently in - /// our control (control given via addLinkerScript()). Called once all linker - /// scripts have been parsed. - std::error_code perform(); - - /// Answer if we have layout commands (section mapping rules). If we don't, - /// the output file writer can assume there is no linker script special rule - /// to handle. - bool hasLayoutCommands() const { return _layoutCommands.size() > 0; } - - /// Return true if this section has a mapping rule in the linker script - bool hasMapping(const SectionKey &key) const { - return getLayoutOrder(key, true) >= 0; - } - - /// Order function - used to sort input sections in the output file according - /// to linker script custom mappings. Return true if lhs should appear before - /// rhs. - bool less(const SectionKey &lhs, const SectionKey &rhs) const; - - /// Retrieve the name of the output section that this input section is mapped - /// to, according to custom linker script mappings. - StringRef getOutputSection(const SectionKey &key) const; - - /// Retrieve all the linker script expressions that need to be evaluated - /// before the given section is emitted. This is *not* const because the - /// first section to retrieve a given set of expression is the only one to - /// receive it. This set is marked as "delivered" and no other sections can - /// retrieve this set again. If we don't do this, multiple sections may map - /// to the same set of expressions because of wildcards rules. - std::vector<const SymbolAssignment *> getExprs(const SectionKey &key); - - /// Evaluate a single linker script expression according to our current - /// context (symbol table). This function is *not* constant because it can - /// update our symbol table with new symbols calculated in this expression. - std::error_code evalExpr(const SymbolAssignment *assgn, uint64_t &curPos); - - /// Retrieve the set of symbols defined in linker script expressions. - const llvm::StringSet<> &getScriptDefinedSymbols() const; - - /// Queries the linker script symbol table for the value of a given symbol. - /// This function must be called after linker script expressions evaluation - /// has been performed (by calling evalExpr() for all expressions). - uint64_t getLinkerScriptExprValue(StringRef name) const; - - /// Check if there are custom headers available. - bool hasPHDRs() const; - - /// Retrieve all the headers the given output section is assigned to. - std::vector<const PHDR *> getPHDRsForOutputSection(StringRef name) const; - - /// Retrieve program header if available. - const PHDR *getProgramPHDR() const; - - void dump() const; - -private: - /// A custom hash operator to teach the STL how to handle our custom keys. - /// This will be used in our hash table mapping Sections to a Layout Order - /// number (caching results). - struct SectionKeyHash { - int64_t operator()(const SectionKey &k) const { - return llvm::hash_combine(k.archivePath, k.memberPath, k.sectionName); - } - }; - - /// Teach the STL when two section keys are the same. This will be used in - /// our hash table mapping Sections to a Layout Order number (caching results) - struct SectionKeyEq { - bool operator()(const SectionKey &lhs, const SectionKey &rhs) const { - return ((lhs.archivePath == rhs.archivePath) && - (lhs.memberPath == rhs.memberPath) && - (lhs.sectionName == rhs.sectionName)); - } - }; - - /// Given an order id, check if it matches the tuple - /// <archivePath, memberPath, sectionName> and returns the - /// internal id that matched, or -1 if no matches. - int matchSectionName(int id, const SectionKey &key) const; - - /// Returns a number that will determine the order of this input section - /// in the final layout. If coarse is true, we simply return the layour order - /// of the higher-level node InputSectionsCmd, used to order input sections. - /// If coarse is false, we return the layout index down to the internal - /// InputSectionsCmd arrangement, used to get the set of preceding linker - ///expressions. - int getLayoutOrder(const SectionKey &key, bool coarse) const; - - /// Compare two sections that have the same mapping rule (i.e., are matched - /// by the same InputSectionsCmd). - /// Determine if lhs < rhs by analyzing the InputSectionsCmd structure. - bool localCompare(int order, const SectionKey &lhs, - const SectionKey &rhs) const; - - /// Convert the PHDRS command into map of names to headers. - /// Determine program header during processing. - std::error_code collectPHDRs(const PHDRS *ph, - llvm::StringMap<const PHDR *> &phdrs); - - /// Build map that matches output section names to segments they should be - /// put into. - std::error_code buildSectionToPHDR(llvm::StringMap<const PHDR *> &phdrs); - - /// Our goal with all linearizeAST overloaded functions is to - /// traverse the linker script AST while putting nodes in a vector and - /// thus enforcing order among nodes (which comes first). - /// - /// The order among nodes is determined by their indexes in this vector - /// (_layoutCommands). This index allows us to solve the problem of - /// establishing the order among two different input sections: we match each - /// input sections with their respective layout command and use the indexes - /// of these commands to order these sections. - /// - /// Example: - /// - /// Given the linker script: - /// SECTIONS { - /// .text : { *(.text) } - /// .data : { *(.data) } - /// } - /// - /// The _layoutCommands vector should contain: - /// id 0 : <OutputSectionDescription> (_sectionName = ".text") - /// id 1 : <InputSectionsCmd> (_memberName = "*") - /// id 2 : <InputSectionName> (_name = ".text) - /// id 3 : <OutputSectionDescription> (_sectionName = ".data") - /// id 4 : <InputSectionsCmd> (_memberName = "*") - /// id 5 : <InputSectionName> (_name = ".data") - /// - /// If we need to sort the following input sections: - /// - /// input section A: .text from libc.a (member errno.o) - /// input section B: .data from libc.a (member write.o) - /// - /// Then we match input section A with the InputSectionsCmd of id 1, and - /// input section B with the InputSectionsCmd of id 4. Since 1 < 4, we - /// put A before B. - /// - /// The second problem handled by the linearization of the AST is the task - /// of finding all preceding expressions that need to be calculated before - /// emitting a given section. This task is easier to deal with when all nodes - /// are in a vector because otherwise we would need to traverse multiple - /// levels of the AST to find the set of expressions that preceed a layout - /// command. - /// - /// The linker script commands that are linearized ("layout commands") are: - /// - /// * OutputSectionDescription, containing an output section name - /// * InputSectionsCmd, containing an input file name - /// * InputSectionName, containing a single input section name - /// * InputSectionSortedName, a group of input section names - /// * SymbolAssignment, containing an expression that may - /// change the address where the linker is outputting data - /// - void linearizeAST(const Sections *sections); - void linearizeAST(const InputSectionsCmd *inputSections); - void linearizeAST(const InputSection *inputSection); - - std::vector<std::unique_ptr<Parser>> _scripts; - std::vector<const Command *> _layoutCommands; - std::unordered_multimap<std::string, int> _memberToLayoutOrder; - std::vector<std::pair<StringRef, int>> _memberNameWildcards; - mutable std::unordered_map<SectionKey, int, SectionKeyHash, SectionKeyEq> - _cacheSectionOrder, _cacheExpressionOrder; - llvm::DenseSet<int> _deliveredExprs; - mutable llvm::StringSet<> _definedSymbols; - - llvm::StringMap<llvm::SmallVector<const PHDR *, 2>> _sectionToPHDR; - const PHDR *_programPHDR; - - Expression::SymbolTableTy _symbolTable; -}; - -llvm::BumpPtrAllocator &Command::getAllocator() const { - return _ctx.getAllocator(); -} -llvm::BumpPtrAllocator &Expression::getAllocator() const { - return _ctx.getAllocator(); -} -} // end namespace script -} // end namespace lld - -#endif diff --git a/include/lld/ReaderWriter/MachOLinkingContext.h b/include/lld/ReaderWriter/MachOLinkingContext.h index dc44d3f303f8..7b673f0dad3e 100644 --- a/include/lld/ReaderWriter/MachOLinkingContext.h +++ b/include/lld/ReaderWriter/MachOLinkingContext.h @@ -13,6 +13,7 @@ #include "lld/Core/LinkingContext.h" #include "lld/Core/Reader.h" #include "lld/Core/Writer.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringSet.h" #include "llvm/Support/ErrorHandling.h" @@ -71,10 +72,21 @@ public: dynamicLookup }; + enum ObjCConstraint { + objc_unknown = 0, + objc_supports_gc = 2, + objc_gc_only = 4, + // Image optimized by dyld = 8 + // GC compaction = 16 + objc_retainReleaseForSimulator = 32, + objc_retainRelease + }; + /// Initializes the context to sane default values given the specified output /// file type, arch, os, and minimum os version. This should be called before /// other setXXX() methods. - void configure(HeaderFileType type, Arch arch, OS os, uint32_t minOSVersion); + void configure(HeaderFileType type, Arch arch, OS os, uint32_t minOSVersion, + bool exportDynamicSymbols); void addPasses(PassManager &pm) override; bool validateImpl(raw_ostream &diagnostics) override; @@ -82,6 +94,18 @@ public: void createImplicitFiles(std::vector<std::unique_ptr<File>> &) override; + /// Creates a new file which is owned by the context. Returns a pointer to + /// the new file. + template <class T, class... Args> + typename std::enable_if<!std::is_array<T>::value, T *>::type + make_file(Args &&... args) const { + auto file = std::unique_ptr<T>(new T(std::forward<Args>(args)...)); + auto *filePtr = file.get(); + auto *ctx = const_cast<MachOLinkingContext *>(this); + ctx->getNodes().push_back(llvm::make_unique<FileNode>(std::move(file))); + return filePtr; + } + uint32_t getCPUType() const; uint32_t getCPUSubType() const; @@ -118,6 +142,8 @@ public: void setKeepPrivateExterns(bool v) { _keepPrivateExterns = v; } bool demangleSymbols() const { return _demangle; } void setDemangleSymbols(bool d) { _demangle = d; } + bool mergeObjCCategories() const { return _mergeObjCCategories; } + void setMergeObjCCategories(bool v) { _mergeObjCCategories = v; } /// Create file at specified path which will contain a binary encoding /// of all input and output file paths. std::error_code createDependencyFile(StringRef path); @@ -136,6 +162,26 @@ public: const StringRefVector &sysLibRoots() const { return _syslibRoots; } bool PIE() const { return _pie; } void setPIE(bool pie) { _pie = pie; } + bool generateVersionLoadCommand() const { + return _generateVersionLoadCommand; + } + void setGenerateVersionLoadCommand(bool v) { + _generateVersionLoadCommand = v; + } + + bool generateFunctionStartsLoadCommand() const { + return _generateFunctionStartsLoadCommand; + } + void setGenerateFunctionStartsLoadCommand(bool v) { + _generateFunctionStartsLoadCommand = v; + } + + bool generateDataInCodeLoadCommand() const { + return _generateDataInCodeLoadCommand; + } + void setGenerateDataInCodeLoadCommand(bool v) { + _generateDataInCodeLoadCommand = v; + } uint64_t stackSize() const { return _stackSize; } void setStackSize(uint64_t stackSize) { _stackSize = stackSize; } @@ -143,6 +189,18 @@ public: uint64_t baseAddress() const { return _baseAddress; } void setBaseAddress(uint64_t baseAddress) { _baseAddress = baseAddress; } + ObjCConstraint objcConstraint() const { return _objcConstraint; } + + uint32_t osMinVersion() const { return _osMinVersion; } + + uint32_t sdkVersion() const { return _sdkVersion; } + void setSdkVersion(uint64_t v) { _sdkVersion = v; } + + uint64_t sourceVersion() const { return _sourceVersion; } + void setSourceVersion(uint64_t v) { _sourceVersion = v; } + + uint32_t swiftVersion() const { return _swiftVersion; } + /// \brief Checks whether a given path on the filesystem exists. /// /// When running in -test_file_usage mode, this method consults an @@ -167,12 +225,12 @@ public: /// The -lFoo option is documented to search for libFoo.dylib and libFoo.a in /// that order, unless Foo ends in ".o", in which case only the exact file /// matches (e.g. -lfoo.o would only find foo.o). - ErrorOr<StringRef> searchDirForLibrary(StringRef path, - StringRef libName) const; + llvm::Optional<StringRef> searchDirForLibrary(StringRef path, + StringRef libName) const; /// \brief Iterates through all search path entries looking for libName (as /// specified by -lFoo). - ErrorOr<StringRef> searchLibrary(StringRef libName) const; + llvm::Optional<StringRef> searchLibrary(StringRef libName) const; /// Add a framework search path. Internally, this method may be prepended /// the path with syslibroot. @@ -180,7 +238,7 @@ public: /// \brief Iterates through all framework directories looking for /// Foo.framework/Foo (when fwName = "Foo"). - ErrorOr<StringRef> findPathForFramework(StringRef fwName) const; + llvm::Optional<StringRef> findPathForFramework(StringRef fwName) const; /// \brief The dylib's binary compatibility version, in the raw uint32 format. /// @@ -297,6 +355,9 @@ public: /// Pass to add shims switching between thumb and arm mode. bool needsShimPass() const; + /// Pass to add objc image info and optimized objc data. + bool needsObjCPass() const; + /// Magic symbol name stubs will need to help lazy bind. StringRef binderSymbolName() const; @@ -340,8 +401,14 @@ public: /// bits are xxxx.yy.zz. Largest number is 65535.255.255 static bool parsePackedVersion(StringRef str, uint32_t &result); + /// Construct 64-bit value from string "A.B.C.D.E" where + /// bits are aaaa.bb.cc.dd.ee. Largest number is 16777215.1023.1023.1023.1023 + static bool parsePackedVersion(StringRef str, uint64_t &result); + void finalizeInputFiles() override; + llvm::Error handleLoadedFile(File &file) override; + bool customAtomOrderer(const DefinedAtom *left, const DefinedAtom *right, bool &leftBeforeRight) const; @@ -383,28 +450,36 @@ private: StringRefVector _searchDirs; StringRefVector _syslibRoots; StringRefVector _frameworkDirs; - HeaderFileType _outputMachOType; // e.g MH_EXECUTE - bool _outputMachOTypeStatic; // Disambiguate static vs dynamic prog - bool _doNothing; // for -help and -v which just print info - bool _pie; - Arch _arch; - OS _os; - uint32_t _osMinVersion; - uint64_t _pageZeroSize; - uint64_t _pageSize; - uint64_t _baseAddress; - uint64_t _stackSize; - uint32_t _compatibilityVersion; - uint32_t _currentVersion; + HeaderFileType _outputMachOType = llvm::MachO::MH_EXECUTE; + bool _outputMachOTypeStatic = false; // Disambiguate static vs dynamic prog + bool _doNothing = false; // for -help and -v which just print info + bool _pie = false; + Arch _arch = arch_unknown; + OS _os = OS::macOSX; + uint32_t _osMinVersion = 0; + uint32_t _sdkVersion = 0; + uint64_t _sourceVersion = 0; + uint64_t _pageZeroSize = 0; + uint64_t _pageSize = 4096; + uint64_t _baseAddress = 0; + uint64_t _stackSize = 0; + uint32_t _compatibilityVersion = 0; + uint32_t _currentVersion = 0; + ObjCConstraint _objcConstraint = objc_unknown; + uint32_t _swiftVersion = 0; StringRef _installName; StringRefVector _rpaths; - bool _flatNamespace; - UndefinedMode _undefinedMode; - bool _deadStrippableDylib; - bool _printAtoms; - bool _testingFileUsage; - bool _keepPrivateExterns; - bool _demangle; + bool _flatNamespace = false; + UndefinedMode _undefinedMode = UndefinedMode::error; + bool _deadStrippableDylib = false; + bool _printAtoms = false; + bool _testingFileUsage = false; + bool _keepPrivateExterns = false; + bool _demangle = false; + bool _mergeObjCCategories = true; + bool _generateVersionLoadCommand = false; + bool _generateFunctionStartsLoadCommand = false; + bool _generateDataInCodeLoadCommand = false; StringRef _bundleLoader; mutable std::unique_ptr<mach_o::ArchHandler> _archHandler; mutable std::unique_ptr<Writer> _writer; @@ -414,13 +489,13 @@ private: mutable std::set<mach_o::MachODylibFile*> _upwardDylibs; mutable std::vector<std::unique_ptr<File>> _indirectDylibs; mutable std::mutex _dylibsMutex; - ExportMode _exportMode; + ExportMode _exportMode = ExportMode::globals; llvm::StringSet<> _exportedSymbols; - DebugInfoMode _debugInfoMode; + DebugInfoMode _debugInfoMode = DebugInfoMode::addDebugMap; std::unique_ptr<llvm::raw_fd_ostream> _dependencyInfo; llvm::StringMap<std::vector<OrderFileNode>> _orderFiles; - unsigned _orderFileEntries; - File *_flatNamespaceFile; + unsigned _orderFileEntries = 0; + File *_flatNamespaceFile = nullptr; mach_o::SectCreateFile *_sectCreateFile = nullptr; }; |