From 1a6615dc883555027a1b4aa4f03822eb4e1b8515 Mon Sep 17 00:00:00 2001 From: Nick Kledzik Date: Thu, 8 Mar 2012 00:18:30 +0000 Subject: [PATCH] Sources now require C++11 to build. Add first linker pass (StubsPass) which looks for calls to shared library symbols and replaces them with calls to a StubAtom. On ELF system, a "stub" is a PLT entry. Added a simple test case. Pass a Platform object to YAML reader and writer for converting fixup kinds between names and values. Change output of Resolver to be a File object instead of a vector of Atoms. Thus, passes operate on a File instead of just Atoms. Rework how to walk through a File's Atoms. Now iterator based instead of a method that visits each atom. llvm-svn: 152269 --- lld/CMakeLists.txt | 16 ++ lld/include/lld/Core/Atom.h | 2 +- lld/include/lld/Core/DefinedAtom.h | 55 ++++- lld/include/lld/Core/File.h | 193 +++++++++++++++-- lld/include/lld/Core/InputFiles.h | 15 +- lld/include/lld/Core/Pass.h | 65 ++++++ lld/include/lld/Core/Resolver.h | 69 ++++-- lld/include/lld/Core/YamlReader.h | 12 +- lld/include/lld/Core/YamlWriter.h | 7 +- lld/include/lld/Platform/Platform.h | 23 ++ lld/lib/CMakeLists.txt | 1 + lld/lib/Core/File.cpp | 4 +- lld/lib/Core/NativeReader.cpp | 235 +++++++++++---------- lld/lib/Core/NativeWriter.cpp | 67 +++--- lld/lib/Core/Resolver.cpp | 63 ++++-- lld/lib/Core/YamlKeyValues.cpp | 1 + lld/lib/Core/YamlReader.cpp | 141 ++++++------- lld/lib/Core/YamlWriter.cpp | 296 ++++++++++++++------------ lld/lib/Passes/CMakeLists.txt | 3 + lld/lib/Passes/StubsPass.cpp | 79 +++++++ lld/test/pass-stubs-basic.objtxt | 50 +++++ lld/tools/lld-core/CMakeLists.txt | 1 + lld/tools/lld-core/lld-core.cpp | 311 +++++++++++++++++++++------- 23 files changed, 1217 insertions(+), 492 deletions(-) create mode 100644 lld/include/lld/Core/Pass.h create mode 100644 lld/lib/Passes/CMakeLists.txt create mode 100644 lld/lib/Passes/StubsPass.cpp create mode 100644 lld/test/pass-stubs-basic.objtxt diff --git a/lld/CMakeLists.txt b/lld/CMakeLists.txt index 4fe1e0117d76..c6409249fc56 100644 --- a/lld/CMakeLists.txt +++ b/lld/CMakeLists.txt @@ -1,6 +1,8 @@ # If we are not building as a part of LLVM, build lld as a standalone project, # using LLVM as an external library. + + if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) project(lld) cmake_minimum_required(VERSION 2.8) @@ -58,6 +60,20 @@ if (CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR) "`CMakeFiles'. Please delete them.") endif() +# +# lld now requires C++11 to build +# +# set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") +include(CheckCXXCompilerFlag) +check_cxx_compiler_flag("-std=c++11" SUPPORTS_CXX11_FLAG) +if( SUPPORTS_CXX11_FLAG ) + message(STATUS "Building with -std=c++11") + set(CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}") +else( SUPPORTS_CXX11_FLAG ) + message(WARNING "-std=c++11 not supported.") +endif() + + macro(add_lld_library name) llvm_process_sources(srcs ${ARGN}) if (MSVC_IDE OR XCODE) diff --git a/lld/include/lld/Core/Atom.h b/lld/include/lld/Core/Atom.h index 64d6f86ebd02..f4b8904ec84e 100644 --- a/lld/include/lld/Core/Atom.h +++ b/lld/include/lld/Core/Atom.h @@ -24,7 +24,7 @@ class UndefinedAtom; class SharedLibraryAtom; class AbsoluteAtom; - /// +/// /// 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 /// and each Reference is an edge. An Atom can be a DefinedAtom which has diff --git a/lld/include/lld/Core/DefinedAtom.h b/lld/include/lld/Core/DefinedAtom.h index e7dfe3abe3af..2230af3a712e 100644 --- a/lld/include/lld/Core/DefinedAtom.h +++ b/lld/include/lld/Core/DefinedAtom.h @@ -195,13 +195,6 @@ public: uint16_t modulus; }; - /// for use iterating over this Atom's References - class ReferenceHandler { - public: - virtual ~ReferenceHandler() {} - virtual void doReference(const Reference &) = 0; - }; - /// ordinal - returns a value for the order of this Atom within its file. /// This is used by the linker to order the layout of Atoms so that /// the resulting image is stable and reproducible. @@ -266,10 +259,43 @@ public: /// rawContent - returns a reference to the raw (unrelocated) bytes of /// this Atom's content. virtual llvm::ArrayRef rawContent() const = 0; - - /// iterator over this Atom's References - virtual void forEachReference(ReferenceHandler&) const = 0; + /// This class abstracts iterating over the sequence of References + /// in an Atom. Concrete instances of DefinedAtom must implement + /// the derefIterator() and incrementIterator methods. + class reference_iterator { + public: + reference_iterator(const DefinedAtom& a, const void* it) + : _atom(a), _it(it) { } + + const Reference* operator*() const { + return _atom.derefIterator(_it); + } + + const Reference* operator->() const { + return _atom.derefIterator(_it); + } + + bool operator!=(const reference_iterator& other) const { + return (this->_it != other._it); + } + + reference_iterator& operator++() { + _atom.incrementIterator(_it); + return *this; + } + private: + const DefinedAtom& _atom; + const void* _it; + }; + + /// Returns an iterator to the beginning of this Atom's References + virtual reference_iterator referencesBegin() const = 0; + + /// Returns an iterator to the end of this Atom's References + virtual reference_iterator referencesEnd() const = 0; + + protected: /// DefinedAtom is an abstract base class. /// Only subclasses can access constructor. @@ -280,6 +306,15 @@ protected: /// delete on an Atom. In fact, some File objects may bulk allocate /// an array of Atoms, so they cannot be individually deleted by anyone. virtual ~DefinedAtom() {} + + /// Returns a pointer to the Reference object that the abstract + /// iterator "points" to. + virtual const Reference* derefIterator(const void* iter) const = 0; + + /// Adjusts the abstract iterator to "point" to the next Reference object + /// for this Atom. + virtual void incrementIterator(const void*& iter) const = 0; + }; } // namespace lld diff --git a/lld/include/lld/Core/File.h b/lld/include/lld/Core/File.h index f524ae31c61c..741244692b15 100644 --- a/lld/include/lld/Core/File.h +++ b/lld/include/lld/Core/File.h @@ -1,4 +1,4 @@ -//===- Core/File.h - A Contaier of Atoms ----------------------------------===// +//===- Core/File.h - A Container of Atoms ---------------------------------===// // // The LLVM Linker // @@ -10,6 +10,8 @@ #ifndef LLD_CORE_FILE_H_ #define LLD_CORE_FILE_H_ +#include + #include "llvm/ADT/StringRef.h" #include "lld/Core/DefinedAtom.h" @@ -19,31 +21,190 @@ namespace lld { + +/// +/// Every Atom is owned by some File. A common scenario is for a single +/// object file (.o) to be parsed by some reader and produce a single +/// File object that represents the content of that object file. +/// +/// The File class has *begin() and *end() methods for use iterating through +/// the Atoms in a File object. +/// +/// The Atom objects in a File are owned by the File object. The Atom objects +/// are destroyed when the File object is destroyed. +/// class File { public: - File(llvm::StringRef p) : _path(p) {} virtual ~File(); - class AtomHandler { - public: - virtual ~AtomHandler() {} - virtual void doDefinedAtom(const class DefinedAtom &) = 0; - virtual void doUndefinedAtom(const class UndefinedAtom &) = 0; - virtual void doSharedLibraryAtom(const class SharedLibraryAtom &) = 0; - virtual void doAbsoluteAtom(const class AbsoluteAtom &) = 0; - virtual void doFile(const class File &) = 0; - }; - + /// For error messages and debugging, this returns the path to the file + /// which was used to create this object (e.g. "/tmp/foo.o"). llvm::StringRef path() const { return _path; } - virtual bool forEachAtom(AtomHandler &) const = 0; - virtual bool justInTimeforEachAtom( llvm::StringRef name - , AtomHandler &) const = 0; + /// Returns the path of the source file used to create the object + /// file which this (File) object represents. This information is usually + /// parsed out of the DWARF debug information. If the source file cannot + /// be ascertained, this method returns the empty string. + virtual llvm::StringRef translationUnitSource() const; - virtual bool translationUnitSource(llvm::StringRef &path) const; +protected: + template class atom_iterator; // forward reference +public: + + /// For use interating over DefinedAtoms in this File. + typedef atom_iterator defined_iterator; + /// For use interating over UndefinedAtoms in this File. + typedef atom_iterator undefined_iterator; + + /// For use interating over SharedLibraryAtoms in this File. + typedef atom_iterator shared_library_iterator; + + /// For use interating over AbsoluteAtoms in this File. + typedef atom_iterator absolute_iterator; + + /// Returns an iterator to the beginning of this File's DefinedAtoms + defined_iterator definedAtomsBegin() const { + return defined().begin(); + } + + /// Returns an iterator to the end of this File's DefinedAtoms + defined_iterator definedAtomsEnd() const { + return defined().end(); + } + + /// Returns an iterator to the beginning of this File's DefinedAtoms + undefined_iterator undefinedAtomsBegin() const { + return undefined().begin(); + } + + /// Returns an iterator to the end of this File's UndefinedAtoms + undefined_iterator undefinedAtomsEnd() const { + return undefined().end(); + } + + /// Returns an iterator to the beginning of this File's SharedLibraryAtoms + shared_library_iterator sharedLibraryAtomsBegin() const { + return sharedLibrary().begin(); + } + + /// Returns an iterator to the end of this File's SharedLibraryAtoms + shared_library_iterator sharedLibraryAtomsEnd() const { + return sharedLibrary().end(); + } + + /// Returns an iterator to the beginning of this File's AbsoluteAtoms + absolute_iterator absoluteAtomsBegin() const { + return absolute().begin(); + } + + /// Returns an iterator to the end of this File's AbsoluteAtoms + absolute_iterator absoluteAtomsEnd() const { + return absolute().end(); + } + + /// Note: this method is not const. All File objects instantiated by reading + /// an object file from disk are "const File*" objects and cannot be + /// modified. This method can only be used with temporay File objects + /// such as is seen by each Pass object when it runs. + /// This method is *not* safe to call while iterating through this File's + /// Atoms. A Pass should queue up any Atoms it want to add and then + /// call this method when no longer iterating over the File's Atoms. + virtual void addAtom(const Atom&) = 0; + + + +protected: + /// only subclasses of File can be instantiated + File(llvm::StringRef p) : _path(p) {} + + + /// Different object file readers may instantiate and manage atoms with + /// different data structures. This class is a collection abstraction. + /// Each concrete File instance must implement these atom_collection + /// methods to enable clients to interate the File's atoms. + template + class atom_collection { + public: + virtual atom_iterator begin() const = 0; + virtual atom_iterator end() const = 0; + virtual const T* deref(const void* it) const = 0; + virtual void next(const void*& it) const = 0; + }; + + + /// The class is the iterator type used to iterate through a File's Atoms. + /// This iterator delegates the work to the associated atom_collection object. + /// There are four kinds of Atoms, so this iterator is templated on + /// the four base Atom kinds. + template + class atom_iterator { + public: + atom_iterator(const atom_collection& c, const void* it) + : _collection(c), _it(it) { } + + const T* operator*() const { + return _collection.deref(_it); + } + + const T* operator->() const { + return _collection.deref(_it); + } + + bool operator!=(const atom_iterator& other) const { + return (this->_it != other._it); + } + + atom_iterator& operator++() { + _collection.next(_it); + return *this; + } + private: + const atom_collection& _collection; + const void* _it; + }; + + /// Must be implemented to return the atom_collection object for + /// all DefinedAtoms in this File. + virtual const atom_collection& defined() const = 0; + + /// Must be implemented to return the atom_collection object for + /// all UndefinedAtomw in this File. + virtual const atom_collection& undefined() const = 0; + + /// Must be implemented to return the atom_collection object for + /// all SharedLibraryAtoms in this File. + virtual const atom_collection& sharedLibrary() const = 0; + + /// Must be implemented to return the atom_collection object for + /// all AbsoluteAtoms in this File. + virtual const atom_collection& absolute() const = 0; + + /// This is a convenience class for File subclasses which manage their + /// atoms as a simple std::vector<>. + template + class atom_collection_vector : public atom_collection { + public: + virtual atom_iterator begin() const { + return atom_iterator(*this, reinterpret_cast(&_atoms[0])); + } + virtual atom_iterator end() const{ + return atom_iterator(*this, reinterpret_cast + (&_atoms[_atoms.size()])); + } + virtual const T* deref(const void* it) const { + return *reinterpret_cast(it); + } + virtual void next(const void*& it) const { + const T * const * p = reinterpret_cast(it); + ++p; + it = reinterpret_cast(p); + } + std::vector _atoms; + }; + private: llvm::StringRef _path; diff --git a/lld/include/lld/Core/InputFiles.h b/lld/include/lld/Core/InputFiles.h index 533d07eb9ad9..0042ceca457b 100644 --- a/lld/include/lld/Core/InputFiles.h +++ b/lld/include/lld/Core/InputFiles.h @@ -24,15 +24,26 @@ namespace lld { /// The searchLibraries() method is used to lazily search libraries. class InputFiles { public: + class Handler { + public: + virtual ~Handler() {} + virtual void doFile(const class File &) = 0; + virtual void doDefinedAtom(const class DefinedAtom &) = 0; + virtual void doUndefinedAtom(const class UndefinedAtom &) = 0; + virtual void doSharedLibraryAtom(const class SharedLibraryAtom &) = 0; + virtual void doAbsoluteAtom(const class AbsoluteAtom &) = 0; + }; + + /// @brief iterates all atoms in initial files - virtual void forEachInitialAtom(File::AtomHandler &) const = 0; + virtual void forEachInitialAtom(Handler &) const = 0; /// @brief searches libraries for name virtual bool searchLibraries( llvm::StringRef name , bool searchDylibs , bool searchArchives , bool dataSymbolOnly - , File::AtomHandler &) const = 0; + , Handler &) const = 0; }; } // namespace lld diff --git a/lld/include/lld/Core/Pass.h b/lld/include/lld/Core/Pass.h new file mode 100644 index 000000000000..ebbcfcdc36e4 --- /dev/null +++ b/lld/include/lld/Core/Pass.h @@ -0,0 +1,65 @@ +//===------ Core/Pass.h - Base class for linker passes --------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_CORE_PASS_H_ +#define LLD_CORE_PASS_H_ + +#include + +#include "lld/Core/Atom.h" +#include "lld/Platform/Platform.h" + +namespace lld { + + +/// +/// Once the core linking is done (which resolves references, coalesces atoms +/// and produces a complete Atom graph), the linker runs a series of passes +/// on the Atom graph. The graph is modeled as a File, which means the pass +/// has access to all the atoms and to File level attributes. Each pass does +/// a particular transformation to the Atom graph or to the File attributes. +/// +/// This is the abstract base class for all passes. A Pass does its +/// actual work in it perform() method. It can iterator over Atoms in the +/// graph using the *begin()/*end() atom iterator of the File. It can add +/// new Atoms to the graph using the File's addAtom() method. +/// +/// +class Pass { +public: + /// Do the actual work of the Pass. + virtual void perform() = 0; + +protected: + // Only subclassess can be instantiated. + Pass(File& f, Platform& p) : _file(f), _platform(p) {} + + + File& _file; + Platform& _platform; +}; + + +/// +/// Pass for adding stubs (PLT entries) for calls to functions +/// outside the linkage unit. +/// +class StubsPass : public Pass { +public: + StubsPass(File& f, Platform& p) : Pass(f, p) {} + + /// Scans all Atoms looking for call-site uses of SharedLibraryAtoms + /// and transfroms the call-site to call a stub instead. + virtual void perform(); +}; + + +} // namespace lld + +#endif // LLD_CORE_PASS_H_ diff --git a/lld/include/lld/Core/Resolver.h b/lld/include/lld/Core/Resolver.h index 9786a7448ba5..22d667b1ee53 100644 --- a/lld/include/lld/Core/Resolver.h +++ b/lld/include/lld/Core/Resolver.h @@ -11,6 +11,7 @@ #define LLD_CORE_RESOLVER_H_ #include "lld/Core/File.h" +#include "lld/Core/InputFiles.h" #include "lld/Core/SymbolTable.h" #include "llvm/ADT/DenseSet.h" @@ -30,7 +31,7 @@ class SymbolTable; /// /// All platform specific resolving is done by delegating to the /// Platform object specified. -class Resolver : public File::AtomHandler { +class Resolver : public InputFiles::Handler { public: Resolver(Platform &plat, const InputFiles &inputs) : _platform(plat) @@ -40,7 +41,7 @@ public: , _addToFinalSection(false) , _completedInitialObjectFiles(false) {} - // AtomHandler methods + // InputFiles::Handler methods virtual void doDefinedAtom(const class DefinedAtom&); virtual void doUndefinedAtom(const class UndefinedAtom&); virtual void doSharedLibraryAtom(const class SharedLibraryAtom &); @@ -48,7 +49,11 @@ public: virtual void doFile(const File&); /// @brief do work of merging and resolving and return list - std::vector &resolve(); + void resolve(); + + File& resultFile() { + return _result; + } private: struct WhyLiveBackChain { @@ -73,31 +78,49 @@ private: void addAtoms(const std::vector&); - // helper to update targets for use with forEachReference() - class MarkLiveReferences : public DefinedAtom::ReferenceHandler { + class MergedFile : public File { public: - MarkLiveReferences(Resolver& resolver, WhyLiveBackChain* chain) - : _resolver(resolver), _chain(chain) { } + MergedFile() : File("") { } - virtual void doReference(const Reference& ref) { - _resolver.markLive(*ref.target(), _chain); - } + + + virtual const atom_collection& defined() const { + return _definedAtoms; + } + virtual const atom_collection& undefined() const { + return _undefinedAtoms; + } + virtual const atom_collection& sharedLibrary() const { + return _sharedLibraryAtoms; + } + virtual const atom_collection& absolute() const { + return _absoluteAtoms; + } + + void addAtoms(std::vector& atoms); + + virtual void addAtom(const Atom& atom); private: - Resolver& _resolver; - WhyLiveBackChain* _chain; + atom_collection_vector _definedAtoms; + atom_collection_vector _undefinedAtoms; + atom_collection_vector _sharedLibraryAtoms; + atom_collection_vector _absoluteAtoms; }; - - Platform &_platform; - const InputFiles &_inputFiles; - SymbolTable _symbolTable; - std::vector _atoms; - std::set _deadStripRoots; - std::vector _atomsWithUnresolvedReferences; - llvm::DenseSet _liveAtoms; - bool _haveLLVMObjs; - bool _addToFinalSection; - bool _completedInitialObjectFiles; + + + + Platform& _platform; + const InputFiles& _inputFiles; + SymbolTable _symbolTable; + std::vector _atoms; + std::set _deadStripRoots; + std::vector _atomsWithUnresolvedReferences; + llvm::DenseSet _liveAtoms; + MergedFile _result; + bool _haveLLVMObjs; + bool _addToFinalSection; + bool _completedInitialObjectFiles; }; } // namespace lld diff --git a/lld/include/lld/Core/YamlReader.h b/lld/include/lld/Core/YamlReader.h index a63af02e0cc7..3ec7ff47bad7 100644 --- a/lld/include/lld/Core/YamlReader.h +++ b/lld/include/lld/Core/YamlReader.h @@ -10,8 +10,6 @@ #ifndef LLD_CORE_YAML_READER_H_ #define LLD_CORE_YAML_READER_H_ -#include "lld/Core/File.h" - #include "llvm/Support/system_error.h" #include @@ -19,19 +17,25 @@ namespace llvm { class MemoryBuffer; } namespace lld { + +class Platform; +class File; + namespace yaml { /// parseObjectTextFileOrSTDIN - Open the specified YAML file (use stdin if /// the path is "-") and parse into lld::File object(s) and append each to /// the specified vector. llvm::error_code parseObjectTextFileOrSTDIN(llvm::StringRef path - , std::vector&); + , Platform& + , std::vector&); /// parseObjectText - Parse the specified YAML formatted MemoryBuffer /// into lld::File object(s) and append each to the specified vector. llvm::error_code parseObjectText(llvm::MemoryBuffer *mb - , std::vector&); + , Platform& + , std::vector&); } // namespace yaml } // namespace lld diff --git a/lld/include/lld/Core/YamlWriter.h b/lld/include/lld/Core/YamlWriter.h index b4c024731336..e950cb4117c1 100644 --- a/lld/include/lld/Core/YamlWriter.h +++ b/lld/include/lld/Core/YamlWriter.h @@ -10,15 +10,18 @@ #ifndef LLD_CORE_YAML_WRITER_H_ #define LLD_CORE_YAML_WRITER_H_ -#include "lld/Core/File.h" #include "llvm/Support/raw_ostream.h" namespace lld { + +class Platform; +class File; + namespace yaml { /// writeObjectText - writes the lld::File object as in YAML /// format to the specified stream. - void writeObjectText(const lld::File &, llvm::raw_ostream &); + void writeObjectText(const lld::File &, Platform &, llvm::raw_ostream &); } // namespace yaml } // namespace lld diff --git a/lld/include/lld/Platform/Platform.h b/lld/include/lld/Platform/Platform.h index 48d443779527..3486716f87db 100644 --- a/lld/include/lld/Platform/Platform.h +++ b/lld/include/lld/Platform/Platform.h @@ -12,10 +12,13 @@ #include +#include "lld/Core/Reference.h" + namespace lld { class Atom; class DefinedAtom; + /// The Platform class encapsulated plaform specific linking knowledge. /// /// Much of what it does is driving by platform specific linker options. @@ -98,6 +101,26 @@ public: /// @brief last chance for platform to tweak atoms virtual void postResolveTweaks(std::vector& all) = 0; + + /// If the output being generated uses needs stubs for external calls + virtual bool outputUsesStubs() = 0; + + /// Converts a reference kind string to a in-memory numeric value. + /// For use with parsing YAML encoded object files. + virtual Reference::Kind kindFromString(llvm::StringRef) = 0; + + /// Converts an in-memory reference kind value to a string. + /// For use with writing YAML encoded object files. + virtual llvm::StringRef kindToString(Reference::Kind) = 0; + + /// If Reference is a branch instruction that might need to be changed + /// to target a stub (PLT entry). + virtual bool isBranch(const Reference*) = 0; + + /// Create a platform specific atom which contains a stub/PLT entry + /// targeting the specified shared library atom. + virtual const Atom* makeStub(const SharedLibraryAtom&, File&) = 0; + }; } // namespace lld diff --git a/lld/lib/CMakeLists.txt b/lld/lib/CMakeLists.txt index 194a13a1af84..21fda8b74890 100644 --- a/lld/lib/CMakeLists.txt +++ b/lld/lib/CMakeLists.txt @@ -1 +1,2 @@ add_subdirectory(Core) +add_subdirectory(Passes) diff --git a/lld/lib/Core/File.cpp b/lld/lib/Core/File.cpp index 09c3f8aba7b3..995993ec493e 100644 --- a/lld/lib/Core/File.cpp +++ b/lld/lib/Core/File.cpp @@ -13,8 +13,8 @@ namespace lld { File::~File() {} -bool File::translationUnitSource(llvm::StringRef &path) const { - return false; +llvm::StringRef File::translationUnitSource() const { + return llvm::StringRef(); } diff --git a/lld/lib/Core/NativeReader.cpp b/lld/lib/Core/NativeReader.cpp index e85d2ff825bf..0eb95b948d75 100644 --- a/lld/lib/Core/NativeReader.cpp +++ b/lld/lib/Core/NativeReader.cpp @@ -92,9 +92,15 @@ public: } virtual llvm::ArrayRef rawContent() const; - - virtual void forEachReference(ReferenceHandler&) const; - + + virtual reference_iterator referencesBegin() const; + + virtual reference_iterator referencesEnd() const; + + virtual const Reference* derefIterator(const void*) const; + + virtual void incrementIterator(const void*& it) const; + private: const NativeAtomAttributesV1& attributes() const; @@ -299,53 +305,29 @@ public: // the _definedAtoms array which was allocated to contain an array // of Atom objects. The atoms have empty destructors, so it is ok // to just delete the memory. - delete _definedAtoms.arrayStart; - delete _undefinedAtoms.arrayStart; - delete _sharedLibraryAtoms.arrayStart; - delete _absoluteAtoms.arrayStart; + delete _definedAtoms._arrayStart; + delete _undefinedAtoms._arrayStart; + delete _sharedLibraryAtoms._arrayStart; + delete _absoluteAtoms._arrayStart; delete _references.arrayStart; delete _targetsTable; } - // visits each atom in the file - virtual bool forEachAtom(AtomHandler& handler) const { - bool didSomething = false; - for(const uint8_t* p=_definedAtoms.arrayStart; p != _definedAtoms.arrayEnd; - p += _definedAtoms.elementSize) { - const DefinedAtom* atom = reinterpret_cast(p); - handler.doDefinedAtom(*atom); - didSomething = true; - } - for(const uint8_t* p=_undefinedAtoms.arrayStart; - p != _undefinedAtoms.arrayEnd; - p += _undefinedAtoms.elementSize) { - const UndefinedAtom* atom = reinterpret_cast(p); - handler.doUndefinedAtom(*atom); - didSomething = true; - } - for(const uint8_t* p=_sharedLibraryAtoms.arrayStart; - p != _sharedLibraryAtoms.arrayEnd; - p += _sharedLibraryAtoms.elementSize) { - const SharedLibraryAtom* atom - = reinterpret_cast(p); - handler.doSharedLibraryAtom(*atom); - didSomething = true; - } - for(const uint8_t* p=_absoluteAtoms.arrayStart; - p != _absoluteAtoms.arrayEnd; - p += _absoluteAtoms.elementSize) { - const AbsoluteAtom* atom - = reinterpret_cast(p); - handler.doAbsoluteAtom(*atom); - didSomething = true; - } - return didSomething; + virtual const atom_collection& defined() const { + return _definedAtoms; } - - // not used - virtual bool justInTimeforEachAtom(llvm::StringRef name, - AtomHandler &) const { - return false; + virtual const atom_collection& undefined() const { + return _undefinedAtoms; + } + virtual const atom_collection& sharedLibrary() const { + return _sharedLibraryAtoms; + } + virtual const atom_collection& absolute() const { + return _absoluteAtoms; + } + + virtual void addAtom(const Atom&) { + assert(0 && "cannot add atoms to native .o files"); } private: @@ -378,10 +360,10 @@ private: new (atomAllocSpace) NativeDefinedAtomV1(*this, ivarData); ++ivarData; } - this->_definedAtoms.arrayStart = atomsStart; - this->_definedAtoms.arrayEnd = atomsEnd; - this->_definedAtoms.elementSize = atomSize; - this->_definedAtoms.elementCount = chunk->elementCount; + this->_definedAtoms._arrayStart = atomsStart; + this->_definedAtoms._arrayEnd = atomsEnd; + this->_definedAtoms._elementSize = atomSize; + this->_definedAtoms._elementCount = chunk->elementCount; return make_error_code(native_reader_error::success); } @@ -416,10 +398,10 @@ private: new (atomAllocSpace) NativeUndefinedAtomV1(*this, ivarData); ++ivarData; } - this->_undefinedAtoms.arrayStart = atomsStart; - this->_undefinedAtoms.arrayEnd = atomsEnd; - this->_undefinedAtoms.elementSize = atomSize; - this->_undefinedAtoms.elementCount = chunk->elementCount; + this->_undefinedAtoms._arrayStart = atomsStart; + this->_undefinedAtoms._arrayEnd = atomsEnd; + this->_undefinedAtoms._elementSize = atomSize; + this->_undefinedAtoms._elementCount = chunk->elementCount; return make_error_code(native_reader_error::success); } @@ -447,10 +429,10 @@ private: new (atomAllocSpace) NativeSharedLibraryAtomV1(*this, ivarData); ++ivarData; } - this->_sharedLibraryAtoms.arrayStart = atomsStart; - this->_sharedLibraryAtoms.arrayEnd = atomsEnd; - this->_sharedLibraryAtoms.elementSize = atomSize; - this->_sharedLibraryAtoms.elementCount = chunk->elementCount; + this->_sharedLibraryAtoms._arrayStart = atomsStart; + this->_sharedLibraryAtoms._arrayEnd = atomsEnd; + this->_sharedLibraryAtoms._elementSize = atomSize; + this->_sharedLibraryAtoms._elementCount = chunk->elementCount; return make_error_code(native_reader_error::success); } @@ -478,10 +460,10 @@ private: new (atomAllocSpace) NativeAbsoluteAtomV1(*this, ivarData); ++ivarData; } - this->_absoluteAtoms.arrayStart = atomsStart; - this->_absoluteAtoms.arrayEnd = atomsEnd; - this->_absoluteAtoms.elementSize = atomSize; - this->_absoluteAtoms.elementCount = chunk->elementCount; + this->_absoluteAtoms._arrayStart = atomsStart; + this->_absoluteAtoms._arrayEnd = atomsEnd; + this->_absoluteAtoms._elementSize = atomSize; + this->_absoluteAtoms._elementCount = chunk->elementCount; return make_error_code(native_reader_error::success); } @@ -529,33 +511,33 @@ private: this->_targetsTable = new const Atom*[chunk->elementCount]; for (uint32_t i=0; i < chunk->elementCount; ++i) { const uint32_t index = targetIndexes[i]; - if ( index < _definedAtoms.elementCount ) { - const uint8_t* p = _definedAtoms.arrayStart - + index * _definedAtoms.elementSize; + if ( index < _definedAtoms._elementCount ) { + const uint8_t* p = _definedAtoms._arrayStart + + index * _definedAtoms._elementSize; this->_targetsTable[i] = reinterpret_cast(p); continue; } - const uint32_t undefIndex = index - _definedAtoms.elementCount; - if ( undefIndex < _undefinedAtoms.elementCount ) { - const uint8_t* p = _undefinedAtoms.arrayStart - + undefIndex * _undefinedAtoms.elementSize; + const uint32_t undefIndex = index - _definedAtoms._elementCount; + if ( undefIndex < _undefinedAtoms._elementCount ) { + const uint8_t* p = _undefinedAtoms._arrayStart + + undefIndex * _undefinedAtoms._elementSize; this->_targetsTable[i] = reinterpret_cast(p); continue; } - const uint32_t slIndex = index - _definedAtoms.elementCount - - _undefinedAtoms.elementCount; - if ( slIndex < _sharedLibraryAtoms.elementCount ) { - const uint8_t* p = _sharedLibraryAtoms.arrayStart - + slIndex * _sharedLibraryAtoms.elementSize; + const uint32_t slIndex = index - _definedAtoms._elementCount + - _undefinedAtoms._elementCount; + if ( slIndex < _sharedLibraryAtoms._elementCount ) { + const uint8_t* p = _sharedLibraryAtoms._arrayStart + + slIndex * _sharedLibraryAtoms._elementSize; this->_targetsTable[i] = reinterpret_cast(p); continue; } - const uint32_t abIndex = index - _definedAtoms.elementCount - - _undefinedAtoms.elementCount - - _sharedLibraryAtoms.elementCount; - if ( abIndex < _absoluteAtoms.elementCount ) { - const uint8_t* p = _absoluteAtoms.arrayStart - + slIndex * _absoluteAtoms.elementSize; + const uint32_t abIndex = index - _definedAtoms._elementCount + - _undefinedAtoms._elementCount + - _sharedLibraryAtoms._elementCount; + if ( abIndex < _absoluteAtoms._elementCount ) { + const uint8_t* p = _absoluteAtoms._arrayStart + + slIndex * _absoluteAtoms._elementSize; this->_targetsTable[i] = reinterpret_cast(p); continue; } @@ -612,21 +594,13 @@ private: assert((result+size) <= _contentEnd); return result; } - - void forEachReference(DefinedAtom::ReferenceHandler& handler, - uint32_t start, uint32_t count) const { - assert(start < _references.elementCount); - assert(start+count <= _references.elementCount); - const uint8_t* arrStart = _references.arrayStart - + start * _references.elementSize; - const uint8_t* arrEnd = arrStart + count * _references.elementSize; - for(const uint8_t* p=arrStart; p != arrEnd; p += _references.elementSize) { - const NativeReferenceV1* ref - = reinterpret_cast(p); - handler.doReference(*ref); - } - } + const Reference* referenceByIndex(uintptr_t index) const { + assert(index < _references.elementCount); + const uint8_t* p = _references.arrayStart + index * _references.elementSize; + return reinterpret_cast(p); + } + const Atom* target(uint32_t index) const { assert(index < _targetsTableCount); return _targetsTable[index]; @@ -656,21 +630,52 @@ private: (_buffer->getBufferStart()); } + template + class AtomArray : public File::atom_collection { + public: + AtomArray() : _arrayStart(NULL), _arrayEnd(NULL), + _elementSize(0), _elementCount(0) { } + + virtual atom_iterator begin() const { + return atom_iterator(*this, reinterpret_cast(_arrayStart)); + } + virtual atom_iterator end() const{ + return atom_iterator(*this, reinterpret_cast(_arrayEnd)); + } + virtual const T* deref(const void* it) const { + return reinterpret_cast(it); + } + virtual void next(const void*& it) const { + const uint8_t* p = reinterpret_cast(it); + p += _elementSize; + it = reinterpret_cast(p); + } + const uint8_t* _arrayStart; + const uint8_t* _arrayEnd; + uint32_t _elementSize; + uint32_t _elementCount; + }; + struct IvarArray { - IvarArray() : arrayStart(NULL), arrayEnd(NULL), - elementSize(0), elementCount(0) { } + IvarArray() : + arrayStart(NULL), + arrayEnd(NULL), + elementSize(0), + elementCount(0) { } + const uint8_t* arrayStart; const uint8_t* arrayEnd; uint32_t elementSize; uint32_t elementCount; - }; + }; + llvm::OwningPtr _buffer; const NativeFileHeader* _header; - IvarArray _definedAtoms; - IvarArray _undefinedAtoms; - IvarArray _sharedLibraryAtoms; - IvarArray _absoluteAtoms; + AtomArray _definedAtoms; + AtomArray _undefinedAtoms; + AtomArray _sharedLibraryAtoms; + AtomArray _absoluteAtoms; const uint8_t* _attributes; uint32_t _attributesMaxOffset; IvarArray _references; @@ -684,14 +689,14 @@ private: const uint8_t* _contentEnd; }; - + inline const class File& NativeDefinedAtomV1::file() const { return *_file; } inline uint64_t NativeDefinedAtomV1:: ordinal() const { const uint8_t* p = reinterpret_cast(_ivarData); - return p - _file->_definedAtoms.arrayStart; + return p - _file->_definedAtoms._arrayStart; } inline llvm::StringRef NativeDefinedAtomV1::name() const { @@ -715,11 +720,27 @@ inline llvm::StringRef NativeDefinedAtomV1::customSectionName() const { return _file->string(offset); } -inline void NativeDefinedAtomV1::forEachReference(ReferenceHandler& hnd) const { - if ( _ivarData->referencesCount == 0 ) - return; - _file->forEachReference(hnd, _ivarData->referencesStartIndex, - _ivarData->referencesCount); +DefinedAtom::reference_iterator NativeDefinedAtomV1::referencesBegin() const { + uintptr_t index = _ivarData->referencesStartIndex; + const void* it = reinterpret_cast(index); + return reference_iterator(*this, it); +} + +DefinedAtom::reference_iterator NativeDefinedAtomV1::referencesEnd() const { + uintptr_t index = _ivarData->referencesStartIndex+_ivarData->referencesCount; + const void* it = reinterpret_cast(index); + return reference_iterator(*this, it); +} + +const Reference* NativeDefinedAtomV1::derefIterator(const void* it) const { + uintptr_t index = reinterpret_cast(it); + return _file->referenceByIndex(index); +} + +void NativeDefinedAtomV1::incrementIterator(const void*& it) const { + uintptr_t index = reinterpret_cast(it); + ++index; + it = reinterpret_cast(index); } inline const class File& NativeUndefinedAtomV1::file() const { diff --git a/lld/lib/Core/NativeWriter.cpp b/lld/lib/Core/NativeWriter.cpp index a95a51498080..5feb314639c9 100644 --- a/lld/lib/Core/NativeWriter.cpp +++ b/lld/lib/Core/NativeWriter.cpp @@ -8,7 +8,6 @@ //===----------------------------------------------------------------------===// #include -#include #include "llvm/ADT/StringRef.h" #include "llvm/ADT/ArrayRef.h" @@ -26,15 +25,36 @@ namespace lld { /// /// Class for writing native object files. /// -class NativeWriter : public File::AtomHandler, - public DefinedAtom::ReferenceHandler { +class NativeWriter { public: /// construct writer for an lld::File object NativeWriter(const lld::File& file) : _file(file) { // reserve first byte for unnamed atoms _stringPool.push_back('\0'); // visit all atoms - _file.forEachAtom(*this); + for(File::defined_iterator it=file.definedAtomsBegin(), + end=file.definedAtomsEnd(); + it != end; ++it) { + this->addIVarsForDefinedAtom(**it); + } + for(File::undefined_iterator it=file.undefinedAtomsBegin(), + end=file.undefinedAtomsEnd(); + it != end; ++it) { + this->addIVarsForUndefinedAtom(**it); + } + for(File::shared_library_iterator it=file.sharedLibraryAtomsBegin(), + end=file.sharedLibraryAtomsEnd(); + it != end; ++it) { + this->addIVarsForSharedLibraryAtom(**it); + } + for(File::absolute_iterator it=file.absoluteAtomsBegin(), + end=file.absoluteAtomsEnd(); + it != end; ++it) { + this->addIVarsForAbsoluteAtom(**it); + } + + + // construct file header based on atom information accumulated makeHeader(); } @@ -105,8 +125,7 @@ public: private: - // visitor routine called by forEachAtom() - virtual void doDefinedAtom(const DefinedAtom& atom) { + void addIVarsForDefinedAtom(const DefinedAtom& atom) { _definedAtomIndex[&atom] = _definedAtomIvars.size(); NativeDefinedAtomIvarsV1 ivar; unsigned refsCount; @@ -119,8 +138,7 @@ private: _definedAtomIvars.push_back(ivar); } - // visitor routine called by forEachAtom() - virtual void doUndefinedAtom(const UndefinedAtom& atom) { + void addIVarsForUndefinedAtom(const UndefinedAtom& atom) { _undefinedAtomIndex[&atom] = _undefinedAtomIvars.size(); NativeUndefinedAtomIvarsV1 ivar; ivar.nameOffset = getNameOffset(atom); @@ -128,8 +146,7 @@ private: _undefinedAtomIvars.push_back(ivar); } - // visitor routine called by forEachAtom() - virtual void doSharedLibraryAtom(const SharedLibraryAtom& atom) { + void addIVarsForSharedLibraryAtom(const SharedLibraryAtom& atom) { _sharedLibraryAtomIndex[&atom] = _sharedLibraryAtomIvars.size(); NativeSharedLibraryAtomIvarsV1 ivar; ivar.nameOffset = getNameOffset(atom); @@ -138,8 +155,7 @@ private: _sharedLibraryAtomIvars.push_back(ivar); } - // visitor routine called by forEachAtom() - virtual void doAbsoluteAtom(const AbsoluteAtom& atom) { + void addIVarsForAbsoluteAtom(const AbsoluteAtom& atom) { _absoluteAtomIndex[&atom] = _absoluteAtomIvars.size(); NativeAbsoluteAtomIvarsV1 ivar; ivar.nameOffset = getNameOffset(atom); @@ -148,10 +164,6 @@ private: _absoluteAtomIvars.push_back(ivar); } - // visitor routine called by forEachAtom() - virtual void doFile(const File &) { - } - // fill out native file header and chunk directory void makeHeader() { const bool hasDefines = !_definedAtomIvars.empty(); @@ -304,6 +316,7 @@ private: return chunks[i]; } assert(0 && "findChunk() signature not found"); + static NativeChunk x; return x; // suppress warning } // append atom name to string pool and return offset @@ -403,23 +416,23 @@ private: count = 0; size_t startRefSize = _references.size(); uint32_t result = startRefSize; - atom.forEachReference(*this); + for (auto it=atom.referencesBegin(), end=atom.referencesEnd(); + it != end; ++it) { + const Reference* ref = *it; + NativeReferenceIvarsV1 nref; + nref.offsetInAtom = ref->offsetInAtom(); + nref.kind = ref->kind(); + nref.targetIndex = this->getTargetIndex(ref->target()); + nref.addendIndex = this->getAddendIndex(ref->addend()); + _references.push_back(nref); + } count = _references.size() - startRefSize; if ( count == 0 ) return 0; else return result; } - - void doReference(const Reference& ref) { - NativeReferenceIvarsV1 nref; - nref.offsetInAtom = ref.offsetInAtom(); - nref.kind = ref.kind(); - nref.targetIndex = this->getTargetIndex(ref.target()); - nref.addendIndex = this->getAddendIndex(ref.addend()); - _references.push_back(nref); - } - + uint32_t getTargetIndex(const Atom* target) { TargetToIndex::const_iterator pos = _targetsTableIndex.find(target); if ( pos != _targetsTableIndex.end() ) { diff --git a/lld/lib/Core/Resolver.cpp b/lld/lib/Core/Resolver.cpp index 92c15f0af506..62361e002eb2 100644 --- a/lld/lib/Core/Resolver.cpp +++ b/lld/lib/Core/Resolver.cpp @@ -217,29 +217,18 @@ void Resolver::resolveUndefines() { } } -// helper to update targets for use with forEachReference() -class ReferenceUpdater : public DefinedAtom::ReferenceHandler { -public: - ReferenceUpdater(SymbolTable& sym) : _symbolTable(sym) { } - - virtual void doReference(const Reference& ref) { - const Atom* newTarget = _symbolTable.replacement(ref.target()); - (const_cast(&ref))->setTarget(newTarget); - } - -private: - SymbolTable& _symbolTable; -}; - // switch all references to undefined or coalesced away atoms // to the new defined atom void Resolver::updateReferences() { - ReferenceUpdater updater(_symbolTable); - for (std::vector::iterator it = _atoms.begin(); - it != _atoms.end(); ++it) { - if ( const DefinedAtom* defAtom = (*it)->definedAtom() ) { - defAtom->forEachReference(updater); + for (auto ait = _atoms.begin(); ait != _atoms.end(); ++ait) { + if ( const DefinedAtom* defAtom = (*ait)->definedAtom() ) { + for (auto rit=defAtom->referencesBegin(), end=defAtom->referencesEnd(); + rit != end; ++rit) { + const Reference* ref = *rit; + const Atom* newTarget = _symbolTable.replacement(ref->target()); + (const_cast(ref))->setTarget(newTarget); + } } } } @@ -272,8 +261,11 @@ void Resolver::markLive(const Atom &atom, WhyLiveBackChain *previous) { thisChain.previous = previous; thisChain.referer = &atom; if ( const DefinedAtom* defAtom = atom.definedAtom() ) { - MarkLiveReferences markRefs(*this, &thisChain); - defAtom->forEachReference(markRefs); + for (auto rit=defAtom->referencesBegin(), end=defAtom->referencesEnd(); + rit != end; ++rit) { + const Reference* ref = *rit; + this->markLive(*ref->target(), &thisChain); + } } } @@ -382,7 +374,7 @@ void Resolver::linkTimeOptimize() { // FIX ME } -std::vector &Resolver::resolve() { +void Resolver::resolve() { this->initializeState(); this->addInitialUndefines(); this->buildInitialAtomList(); @@ -394,7 +386,32 @@ std::vector &Resolver::resolve() { this->checkDylibSymbolCollisions(); this->linkTimeOptimize(); this->tweakAtoms(); - return _atoms; + this->_result.addAtoms(_atoms); } +void Resolver::MergedFile::addAtom(const Atom& atom) { + if ( const DefinedAtom* defAtom = atom.definedAtom() ) { + _definedAtoms._atoms.push_back(defAtom); + } + else if ( const UndefinedAtom* undefAtom = atom.undefinedAtom() ) { + _undefinedAtoms._atoms.push_back(undefAtom); + } + else if ( const SharedLibraryAtom* slAtom = atom.sharedLibraryAtom() ) { + _sharedLibraryAtoms._atoms.push_back(slAtom); + } + else if ( const AbsoluteAtom* abAtom = atom.absoluteAtom() ) { + _absoluteAtoms._atoms.push_back(abAtom); + } + else { + assert(0 && "atom has unknown definition kind"); + } +} + +void Resolver::MergedFile::addAtoms(std::vector& all) { + for(std::vector::iterator it=all.begin(); it != all.end(); ++it) { + this->addAtom(**it); + } +} + + } // namespace lld diff --git a/lld/lib/Core/YamlKeyValues.cpp b/lld/lib/Core/YamlKeyValues.cpp index 6e49580ce693..7ee46cc07fd1 100644 --- a/lld/lib/Core/YamlKeyValues.cpp +++ b/lld/lib/Core/YamlKeyValues.cpp @@ -137,6 +137,7 @@ struct ContentTypeMapping { static const ContentTypeMapping typeMappings[] = { { "unknown", DefinedAtom::typeUnknown }, { "code", DefinedAtom::typeCode }, + { "stub", DefinedAtom::typeStub }, { "resolver", DefinedAtom::typeResolver }, { "constant", DefinedAtom::typeConstant }, { "c-string", DefinedAtom::typeCString }, diff --git a/lld/lib/Core/YamlReader.cpp b/lld/lib/Core/YamlReader.cpp index 97642abeadfb..31f999e3d241 100644 --- a/lld/lib/Core/YamlReader.cpp +++ b/lld/lib/Core/YamlReader.cpp @@ -20,6 +20,8 @@ #include "lld/Core/File.h" #include "lld/Core/Reference.h" +#include "lld/Platform/Platform.h" + #include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/ArrayRef.h" @@ -297,10 +299,23 @@ public: : File("path") , _lastRefIndex(0) {} - virtual bool forEachAtom(File::AtomHandler &) const; - virtual bool justInTimeforEachAtom(llvm::StringRef name, - File::AtomHandler &) const; + virtual const atom_collection& defined() const { + return _definedAtoms; + } + virtual const atom_collection& undefined() const { + return _undefinedAtoms; + } + virtual const atom_collection& sharedLibrary() const { + return _sharedLibraryAtoms; + } + virtual const atom_collection& absolute() const { + return _absoluteAtoms; + } + virtual void addAtom(const Atom&) { + assert(0 && "cannot add atoms to YAML files"); + } + void bindTargetReferences(); void addDefinedAtom(YAMLDefinedAtom* atom, const char* refName); void addUndefinedAtom(UndefinedAtom* atom); @@ -314,13 +329,13 @@ public: Atom* atom; }; - std::vector _definedAtoms; - std::vector _undefinedAtoms; - std::vector _sharedLibraryAtoms; - std::vector _absoluteAtoms; - std::vector _references; - std::vector _nameToAtomMapping; - unsigned int _lastRefIndex; + atom_collection_vector _definedAtoms; + atom_collection_vector _undefinedAtoms; + atom_collection_vector _sharedLibraryAtoms; + atom_collection_vector _absoluteAtoms; + std::vector _references; + std::vector _nameToAtomMapping; + unsigned int _lastRefIndex; }; @@ -434,14 +449,35 @@ public: return _ord; } - - virtual void forEachReference(ReferenceHandler& handler) const { - for (uint32_t i=_refStartIndex; i < _refEndIndex; ++i) { - handler.doReference(_file._references[i]); - } + DefinedAtom::reference_iterator referencesBegin() const { + uintptr_t index = _refStartIndex; + const void* it = reinterpret_cast(index); + return reference_iterator(*this, it); } - void bindTargetReferences() { + DefinedAtom::reference_iterator referencesEnd() const { + uintptr_t index = _refEndIndex; + const void* it = reinterpret_cast(index); + return reference_iterator(*this, it); + } + + const Reference* derefIterator(const void* it) const { + uintptr_t index = reinterpret_cast(it); + assert(index >= _refStartIndex); + assert(index < _refEndIndex); + assert(index < _file._references.size()); + return &_file._references[index]; + } + + void incrementIterator(const void*& it) const { + uintptr_t index = reinterpret_cast(it); + ++index; + it = reinterpret_cast(index); + } + + + + void bindTargetReferences() const { for (unsigned int i=_refStartIndex; i < _refEndIndex; ++i) { const char* targetName = _file._references[i]._targetName; Atom* targetAtom = _file.findAtom(targetName); @@ -559,40 +595,9 @@ private: - -bool YAMLFile::forEachAtom(File::AtomHandler &handler) const { - handler.doFile(*this); - for (std::vector::const_iterator it = _definedAtoms.begin(); - it != _definedAtoms.end(); ++it) { - handler.doDefinedAtom(**it); - } - for (std::vector::const_iterator it = _undefinedAtoms.begin(); - it != _undefinedAtoms.end(); ++it) { - handler.doUndefinedAtom(**it); - } - for (std::vector::const_iterator - it = _sharedLibraryAtoms.begin(); - it != _sharedLibraryAtoms.end(); ++it) { - handler.doSharedLibraryAtom(**it); - } - for (std::vector::const_iterator - it = _absoluteAtoms.begin(); - it != _absoluteAtoms.end(); ++it) { - handler.doAbsoluteAtom(**it); - } - - return true; -} - -bool YAMLFile::justInTimeforEachAtom(llvm::StringRef name, - File::AtomHandler &handler) const { - return false; -} - void YAMLFile::bindTargetReferences() { - for (std::vector::const_iterator - it = _definedAtoms.begin(); it != _definedAtoms.end(); ++it) { - YAMLDefinedAtom* atom = *it; + for (defined_iterator it = definedAtomsBegin(); it != definedAtomsEnd(); ++it) { + const YAMLDefinedAtom* atom = reinterpret_cast(*it); atom->bindTargetReferences(); } } @@ -607,31 +612,31 @@ Atom* YAMLFile::findAtom(const char* name) { } void YAMLFile::addDefinedAtom(YAMLDefinedAtom* atom, const char* refName) { - _definedAtoms.push_back(atom); + _definedAtoms._atoms.push_back(atom); assert(refName != NULL); _nameToAtomMapping.push_back(NameAtomPair(refName, atom)); } void YAMLFile::addUndefinedAtom(UndefinedAtom* atom) { - _undefinedAtoms.push_back(atom); + _undefinedAtoms._atoms.push_back(atom); _nameToAtomMapping.push_back(NameAtomPair(atom->name().data(), atom)); } void YAMLFile::addSharedLibraryAtom(SharedLibraryAtom* atom) { - _sharedLibraryAtoms.push_back(atom); + _sharedLibraryAtoms._atoms.push_back(atom); _nameToAtomMapping.push_back(NameAtomPair(atom->name().data(), atom)); } void YAMLFile::addAbsoluteAtom(AbsoluteAtom* atom) { - _absoluteAtoms.push_back(atom); + _absoluteAtoms._atoms.push_back(atom); _nameToAtomMapping.push_back(NameAtomPair(atom->name().data(), atom)); } class YAMLAtomState { public: - YAMLAtomState(); - + YAMLAtomState(Platform& platform); + void setName(const char *n); void setRefName(const char *n); void setAlign2(const char *n); @@ -642,6 +647,7 @@ public: void makeAtom(YAMLFile&); + Platform& _platform; const char * _name; const char * _refName; const char * _sectionName; @@ -666,8 +672,9 @@ public: }; -YAMLAtomState::YAMLAtomState() - : _name(NULL) +YAMLAtomState::YAMLAtomState(Platform& platform) + : _platform(platform) + , _name(NULL) , _refName(NULL) , _sectionName(NULL) , _loadName(NULL) @@ -764,15 +771,7 @@ void YAMLAtomState::setAlign2(const char *s) { void YAMLAtomState::setFixupKind(const char *s) { - if (strcmp(s, "pcrel32") == 0) - _ref._kind = 1; - else if (strcmp(s, "call32") == 0) - _ref._kind = 2; - else { - int k; - llvm::StringRef(s).getAsInteger(10, k); - _ref._kind = k; - } + _ref._kind = _platform.kindFromString(llvm::StringRef(s)); } void YAMLAtomState::setFixupTarget(const char *s) { @@ -800,12 +799,13 @@ void YAMLAtomState::addFixup(YAMLFile *f) { /// parseObjectText - Parse the specified YAML formatted MemoryBuffer /// into lld::File object(s) and append each to the specified vector. llvm::error_code parseObjectText( llvm::MemoryBuffer *mb - , std::vector &result) { + , Platform& platform + , std::vector &result) { std::vector entries; YAML::parse(mb, entries); YAMLFile *file = NULL; - YAMLAtomState atomState; + YAMLAtomState atomState(platform); bool inAtoms = false; bool inFixups = false; int depthForAtoms = -1; @@ -985,13 +985,14 @@ llvm::error_code parseObjectText( llvm::MemoryBuffer *mb // Fill in vector from path to input text file. // llvm::error_code parseObjectTextFileOrSTDIN(llvm::StringRef path - , std::vector& result) { + , Platform& platform + , std::vector& result) { llvm::OwningPtr mb; llvm::error_code ec = llvm::MemoryBuffer::getFileOrSTDIN(path, mb); if ( ec ) return ec; - return parseObjectText(mb.get(), result); + return parseObjectText(mb.get(), platform, result); } diff --git a/lld/lib/Core/YamlWriter.cpp b/lld/lib/Core/YamlWriter.cpp index c3a7f235454d..f8440667c9d9 100644 --- a/lld/lib/Core/YamlWriter.cpp +++ b/lld/lib/Core/YamlWriter.cpp @@ -14,6 +14,8 @@ #include "lld/Core/File.h" #include "lld/Core/Reference.h" +#include "lld/Platform/Platform.h" + #include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/StringExtras.h" @@ -41,44 +43,50 @@ namespace { /// In that case referencing the function by name is ambiguous, so a unique /// ref-name is added. /// -class RefNameBuilder : public File::AtomHandler, - public DefinedAtom::ReferenceHandler { +class RefNameBuilder { public: - RefNameBuilder() { } - - virtual void doReference(const Reference& ref) { - // create refname for any unnamed reference target - if ( ref.target()->name().empty() ) { - char* buffer; - asprintf(&buffer, "L%03d", _unnamedCounter++); - _refNames[ref.target()] = buffer; + RefNameBuilder(const File& file) + : _collisionCount(0), _unnamedCounter(0) { + // visit all atoms + for(File::defined_iterator it=file.definedAtomsBegin(), + end=file.definedAtomsEnd(); + it != end; ++it) { + const DefinedAtom* atom = *it; + // Build map of atoms names to detect duplicates + if ( ! atom->name().empty() ) + buildDuplicateNameMap(*atom); + + // Find references to unnamed atoms and create ref-names for them. + for (auto rit=atom->referencesBegin(), rend=atom->referencesEnd(); + rit != rend; ++rit) { + const Reference* ref = *rit; + // create refname for any unnamed reference target + if ( ref->target()->name().empty() ) { + char* buffer; + asprintf(&buffer, "L%03d", _unnamedCounter++); + _refNames[ref->target()] = buffer; + } + } + } + for(File::undefined_iterator it=file.undefinedAtomsBegin(), + end=file.undefinedAtomsEnd(); + it != end; ++it) { + buildDuplicateNameMap(**it); + } + for(File::shared_library_iterator it=file.sharedLibraryAtomsBegin(), + end=file.sharedLibraryAtomsEnd(); + it != end; ++it) { + buildDuplicateNameMap(**it); + } + for(File::absolute_iterator it=file.absoluteAtomsBegin(), + end=file.absoluteAtomsEnd(); + it != end; ++it) { + buildDuplicateNameMap(**it); } - } - virtual void doFile(const File &) { } - virtual void doDefinedAtom(const DefinedAtom& atom) { - // Build map of atoms names to detect duplicates - if ( ! atom.name().empty() ) - buildDuplicateNameMap(atom); - - // Find references to unnamed atoms and create ref-names for them. - _unnamedCounter = 0; - atom.forEachReference(*this); } - - virtual void doUndefinedAtom(const UndefinedAtom& atom) { - buildDuplicateNameMap(atom); - } - - virtual void doSharedLibraryAtom(const SharedLibraryAtom& atom) { - buildDuplicateNameMap(atom); - } - - virtual void doAbsoluteAtom(const AbsoluteAtom& atom) { - buildDuplicateNameMap(atom); - } - + void buildDuplicateNameMap(const Atom& atom) { assert(!atom.name().empty()); NameToAtom::iterator pos = _nameMap.find(atom.name()); @@ -131,27 +139,55 @@ private: /// /// Helper class for writeObjectText() to write out atoms in yaml format. /// -class AtomWriter : public File::AtomHandler, - public DefinedAtom::ReferenceHandler { +class AtomWriter { public: - AtomWriter(RefNameBuilder& rnb, llvm::raw_ostream &out) - : _out(out), _rnb(rnb), _firstAtom(true) { } + AtomWriter(const File& file, Platform& platform, RefNameBuilder& rnb) + : _file(file), _platform(platform), _rnb(rnb), _firstAtom(true) { } + + + void write(llvm::raw_ostream& out) { + // write header + out << "---\n"; + + // visit all atoms + for(File::defined_iterator it=_file.definedAtomsBegin(), + end=_file.definedAtomsEnd(); + it != end; ++it) { + writeDefinedAtom(**it, out); + } + for(File::undefined_iterator it=_file.undefinedAtomsBegin(), + end=_file.undefinedAtomsEnd(); + it != end; ++it) { + writeUndefinedAtom(**it, out); + } + for(File::shared_library_iterator it=_file.sharedLibraryAtomsBegin(), + end=_file.sharedLibraryAtomsEnd(); + it != end; ++it) { + writeSharedLibraryAtom(**it, out); + } + for(File::absolute_iterator it=_file.absoluteAtomsBegin(), + end=_file.absoluteAtomsEnd(); + it != end; ++it) { + writeAbsoluteAtom(**it, out); + } + + out << "...\n"; + } - virtual void doFile(const class File &) { _firstAtom = true; } - virtual void doDefinedAtom(const class DefinedAtom &atom) { + void writeDefinedAtom(const DefinedAtom &atom, llvm::raw_ostream& out) { if ( _firstAtom ) { - _out << "atoms:\n"; + out << "atoms:\n"; _firstAtom = false; } else { // add blank line between atoms for readability - _out << "\n"; + out << "\n"; } bool hasDash = false; if ( !atom.name().empty() ) { - _out << " - " + out << " - " << KeyValues::nameKeyword << ":" << spacePadding(KeyValues::nameKeyword) @@ -161,7 +197,7 @@ public: } if ( _rnb.hasRefName(&atom) ) { - _out << (hasDash ? " " : " - ") + out << (hasDash ? " " : " - ") << KeyValues::refNameKeyword << ":" << spacePadding(KeyValues::refNameKeyword) @@ -171,7 +207,7 @@ public: } if ( atom.definition() != KeyValues::definitionDefault ) { - _out << (hasDash ? " " : " - ") + out << (hasDash ? " " : " - ") << KeyValues::definitionKeyword << ":" << spacePadding(KeyValues::definitionKeyword) @@ -181,7 +217,7 @@ public: } if ( atom.scope() != KeyValues::scopeDefault ) { - _out << (hasDash ? " " : " - ") + out << (hasDash ? " " : " - ") << KeyValues::scopeKeyword << ":" << spacePadding(KeyValues::scopeKeyword) @@ -191,7 +227,7 @@ public: } if ( atom.interposable() != KeyValues::interposableDefault ) { - _out << " " + out << " " << KeyValues::interposableKeyword << ":" << spacePadding(KeyValues::interposableKeyword) @@ -200,7 +236,7 @@ public: } if ( atom.merge() != KeyValues::mergeDefault ) { - _out << " " + out << " " << KeyValues::mergeKeyword << ":" << spacePadding(KeyValues::mergeKeyword) @@ -209,7 +245,7 @@ public: } if ( atom.contentType() != KeyValues::contentTypeDefault ) { - _out << " " + out << " " << KeyValues::contentTypeKeyword << ":" << spacePadding(KeyValues::contentTypeKeyword) @@ -218,7 +254,7 @@ public: } if ( atom.deadStrip() != KeyValues::deadStripKindDefault ) { - _out << " " + out << " " << KeyValues::deadStripKindKeyword << ":" << spacePadding(KeyValues::deadStripKindKeyword) @@ -227,14 +263,14 @@ public: } if ( atom.sectionChoice() != KeyValues::sectionChoiceDefault ) { - _out << " " + out << " " << KeyValues::sectionChoiceKeyword << ":" << spacePadding(KeyValues::sectionChoiceKeyword) << KeyValues::sectionChoice(atom.sectionChoice()) << "\n"; assert( ! atom.customSectionName().empty() ); - _out << " " + out << " " << KeyValues::sectionNameKeyword << ":" << spacePadding(KeyValues::sectionNameKeyword) @@ -243,7 +279,7 @@ public: } if ( atom.isThumb() != KeyValues::isThumbDefault ) { - _out << " " + out << " " << KeyValues::isThumbKeyword << ":" << spacePadding(KeyValues::isThumbKeyword) @@ -252,7 +288,7 @@ public: } if ( atom.isAlias() != KeyValues::isAliasDefault ) { - _out << " " + out << " " << KeyValues::isAliasKeyword << ":" << spacePadding(KeyValues::isAliasKeyword) @@ -262,7 +298,7 @@ public: if ( (atom.contentType() != DefinedAtom::typeZeroFill) && (atom.size() != 0) ) { - _out << " " + out << " " << KeyValues::contentKeyword << ":" << spacePadding(KeyValues::contentKeyword) @@ -271,77 +307,77 @@ public: bool needComma = false; for (unsigned int i=0; i < arr.size(); ++i) { if ( needComma ) - _out << ", "; - _out << hexdigit(arr[i] >> 4); - _out << hexdigit(arr[i] & 0x0F); + out << ", "; + out << hexdigit(arr[i] >> 4); + out << hexdigit(arr[i] & 0x0F); needComma = true; } - _out << " ]\n"; + out << " ]\n"; } - _wroteFirstFixup = false; - atom.forEachReference(*this); + bool wroteFirstFixup = false; + for (auto it=atom.referencesBegin(), end=atom.referencesEnd(); + it != end; ++it) { + const Reference* ref = *it; + if ( !wroteFirstFixup ) { + out << " fixups:\n"; + wroteFirstFixup = true; + } + out << " - " + << KeyValues::fixupsOffsetKeyword + << ":" + << spacePadding(KeyValues::fixupsOffsetKeyword) + << ref->offsetInAtom() + << "\n"; + out << " " + << KeyValues::fixupsKindKeyword + << ":" + << spacePadding(KeyValues::fixupsKindKeyword) + << _platform.kindToString(ref->kind()) + << "\n"; + const Atom* target = ref->target(); + if ( target != NULL ) { + llvm::StringRef refName = target->name(); + if ( _rnb.hasRefName(target) ) + refName = _rnb.refName(target); + assert(!refName.empty()); + out << " " + << KeyValues::fixupsTargetKeyword + << ":" + << spacePadding(KeyValues::fixupsTargetKeyword) + << refName + << "\n"; + } + if ( ref->addend() != 0 ) { + out << " " + << KeyValues::fixupsAddendKeyword + << ":" + << spacePadding(KeyValues::fixupsAddendKeyword) + << ref->addend() + << "\n"; + } + } } - virtual void doReference(const Reference& ref) { - if ( !_wroteFirstFixup ) { - _out << " fixups:\n"; - _wroteFirstFixup = true; - } - _out << " - " - << KeyValues::fixupsOffsetKeyword - << ":" - << spacePadding(KeyValues::fixupsOffsetKeyword) - << ref.offsetInAtom() - << "\n"; - _out << " " - << KeyValues::fixupsKindKeyword - << ":" - << spacePadding(KeyValues::fixupsKindKeyword) - << ref.kind() - << "\n"; - const Atom* target = ref.target(); - if ( target != NULL ) { - llvm::StringRef refName = target->name(); - if ( _rnb.hasRefName(target) ) - refName = _rnb.refName(target); - assert(!refName.empty()); - _out << " " - << KeyValues::fixupsTargetKeyword - << ":" - << spacePadding(KeyValues::fixupsTargetKeyword) - << refName - << "\n"; - } - if ( ref.addend() != 0 ) { - _out << " " - << KeyValues::fixupsAddendKeyword - << ":" - << spacePadding(KeyValues::fixupsAddendKeyword) - << ref.addend() - << "\n"; - } - } - - virtual void doUndefinedAtom(const class UndefinedAtom &atom) { + void writeUndefinedAtom(const UndefinedAtom &atom, llvm::raw_ostream& out) { if ( _firstAtom ) { - _out << "atoms:\n"; + out << "atoms:\n"; _firstAtom = false; } else { // add blank line between atoms for readability - _out << "\n"; + out << "\n"; } - _out << " - " + out << " - " << KeyValues::nameKeyword << ":" << spacePadding(KeyValues::nameKeyword) << atom.name() << "\n"; - _out << " " + out << " " << KeyValues::definitionKeyword << ":" << spacePadding(KeyValues::definitionKeyword) @@ -349,7 +385,7 @@ public: << "\n"; if ( atom.canBeNull() != KeyValues::canBeNullDefault ) { - _out << " " + out << " " << KeyValues::canBeNullKeyword << ":" << spacePadding(KeyValues::canBeNullKeyword) @@ -358,24 +394,24 @@ public: } } - virtual void doSharedLibraryAtom(const SharedLibraryAtom& atom) { + void writeSharedLibraryAtom(const SharedLibraryAtom& atom, llvm::raw_ostream& out) { if ( _firstAtom ) { - _out << "atoms:\n"; + out << "atoms:\n"; _firstAtom = false; } else { // add blank line between atoms for readability - _out << "\n"; + out << "\n"; } - _out << " - " + out << " - " << KeyValues::nameKeyword << ":" << spacePadding(KeyValues::nameKeyword) << atom.name() << "\n"; - _out << " " + out << " " << KeyValues::definitionKeyword << ":" << spacePadding(KeyValues::definitionKeyword) @@ -383,7 +419,7 @@ public: << "\n"; if ( !atom.loadName().empty() ) { - _out << " " + out << " " << KeyValues::loadNameKeyword << ":" << spacePadding(KeyValues::loadNameKeyword) @@ -392,7 +428,7 @@ public: } if ( atom.canBeNullAtRuntime() ) { - _out << " " + out << " " << KeyValues::canBeNullKeyword << ":" << spacePadding(KeyValues::canBeNullKeyword) @@ -401,37 +437,37 @@ public: } } - virtual void doAbsoluteAtom(const AbsoluteAtom& atom) { + void writeAbsoluteAtom(const AbsoluteAtom& atom, llvm::raw_ostream& out) { if ( _firstAtom ) { - _out << "atoms:\n"; + out << "atoms:\n"; _firstAtom = false; } else { // add blank line between atoms for readability - _out << "\n"; + out << "\n"; } - _out << " - " + out << " - " << KeyValues::nameKeyword << ":" << spacePadding(KeyValues::nameKeyword) << atom.name() << "\n"; - _out << " " + out << " " << KeyValues::definitionKeyword << ":" << spacePadding(KeyValues::definitionKeyword) << KeyValues::definition(atom.definition()) << "\n"; - _out << " " + out << " " << KeyValues::valueKeyword << ":" << spacePadding(KeyValues::valueKeyword) << "0x"; - _out.write_hex(atom.value()); - _out << "\n"; + out.write_hex(atom.value()); + out << "\n"; } @@ -450,10 +486,10 @@ private: return 'A' + nibble - 0x0A; } - llvm::raw_ostream& _out; - RefNameBuilder _rnb; + const File& _file; + Platform& _platform; + RefNameBuilder& _rnb; bool _firstAtom; - bool _wroteFirstFixup; }; } // anonymous namespace @@ -464,16 +500,14 @@ private: /// writeObjectText - writes the lld::File object as in YAML /// format to the specified stream. /// -void writeObjectText(const File &file, llvm::raw_ostream &out) { +void writeObjectText(const File& file, Platform& platform, + llvm::raw_ostream &out) { // Figure what ref-name labels are needed - RefNameBuilder rnb; - file.forEachAtom(rnb); + RefNameBuilder rnb(file); // Write out all atoms - AtomWriter h(rnb, out); - out << "---\n"; - file.forEachAtom(h); - out << "...\n"; + AtomWriter writer(file, platform, rnb); + writer.write(out); } } // namespace yaml diff --git a/lld/lib/Passes/CMakeLists.txt b/lld/lib/Passes/CMakeLists.txt new file mode 100644 index 000000000000..a90164c04497 --- /dev/null +++ b/lld/lib/Passes/CMakeLists.txt @@ -0,0 +1,3 @@ +add_lld_library(lldPasses + StubsPass.cpp + ) diff --git a/lld/lib/Passes/StubsPass.cpp b/lld/lib/Passes/StubsPass.cpp new file mode 100644 index 000000000000..4c0aec4eba3d --- /dev/null +++ b/lld/lib/Passes/StubsPass.cpp @@ -0,0 +1,79 @@ +//===- Passes/StubsPass.cpp - Adds stubs ----------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// +// This linker pass is +// +// +// +// + + +#include "llvm/ADT/DenseMap.h" + +#include "lld/Core/Pass.h" +#include "lld/Core/File.h" +#include "lld/Core/Reference.h" +#include "lld/Platform/Platform.h" + + +namespace lld { + +void StubsPass::perform() { + // Skip this pass if output format does not need stubs. + if ( !_platform.outputUsesStubs() ) + return; + + // Use map so all call sites to same shlib symbol use same stub + llvm::DenseMap shlibToStub; + + // Scan all references in all atoms. + for(auto ait=_file.definedAtomsBegin(), aend=_file.definedAtomsEnd(); + ait != aend; ++ait) { + const DefinedAtom* atom = *ait; + for (auto rit=atom->referencesBegin(), rend=atom->referencesEnd(); + rit != rend; ++rit) { + const Reference* ref = *rit; + const Atom* target = ref->target(); + assert(target != NULL); + // If the target of this reference is in a shared library + if ( const SharedLibraryAtom* shlbTarget = target->sharedLibraryAtom() ) { + // and this is a call to that shared library symbol. + if ( _platform.isBranch(ref) ) { + const Atom* stub; + // Replace the target with a reference to a stub + auto pos = shlibToStub.find(shlbTarget); + if ( pos == shlibToStub.end() ) { + // This is no existing stub. Create a new one. + stub = _platform.makeStub(*shlbTarget, _file); + shlibToStub[shlbTarget] = stub; + } + else { + // Reuse and existing stub + stub = pos->second; + } + assert(stub != NULL); + // Switch call site in atom to refrence stub instead of shlib atom. + (const_cast(ref))->setTarget(stub); + } + } + } + } + + // add all created stubs to file + for (auto it=shlibToStub.begin(), end=shlibToStub.end(); it != end; ++it) { + _file.addAtom(*it->second); + } + + +} + + + +} diff --git a/lld/test/pass-stubs-basic.objtxt b/lld/test/pass-stubs-basic.objtxt new file mode 100644 index 000000000000..bb88e418d5c7 --- /dev/null +++ b/lld/test/pass-stubs-basic.objtxt @@ -0,0 +1,50 @@ +# RUN: lld-core %s -stubs_pass | FileCheck %s + +# +# Test that stubs pass adds stubs and rebinds call sites to the stub +# + +--- +atoms: + - name: foo + type: code + content: [ E8, 00, 00, 00, 00, E8, 00, 00, 00, + 00, 48 ,8B, 05, 00, 00, 00, 00 ] + fixups: + - offset: 1 + kind: call32 + target: malloc + - offset: 6 + kind: call32 + target: free + - offset: 13 + kind: gotLoad32 + target: malloc + + - name: malloc + definition: shared-library + load-name: libc.so + + - name: free + definition: shared-library + load-name: libc.so + +... + +# CHECK: name: foo +# CHECK: fixups: +# CHECK: kind: call32 +# CHECK: target: L +# CHECK: kind: call32 +# CHECK: target: L +# CHECK: kind: gotLoad32 +# CHECK: target: malloc +# CHECK: name: L +# CHECK: type: stub +# CHECK: name: L +# CHECK: type: stub +# CHECK: name: malloc +# CHECK: definition: shared-library +# CHECK: name: free +# CHECK: definition: shared-library +# CHECK: ... diff --git a/lld/tools/lld-core/CMakeLists.txt b/lld/tools/lld-core/CMakeLists.txt index 0f326dc9e5ad..d962760f9115 100644 --- a/lld/tools/lld-core/CMakeLists.txt +++ b/lld/tools/lld-core/CMakeLists.txt @@ -1,5 +1,6 @@ set(LLVM_USED_LIBS lldCore + lldPasses ) set(LLVM_LINK_COMPONENTS diff --git a/lld/tools/lld-core/lld-core.cpp b/lld/tools/lld-core/lld-core.cpp index 33e021d996c6..d71a0f906d6b 100644 --- a/lld/tools/lld-core/lld-core.cpp +++ b/lld/tools/lld-core/lld-core.cpp @@ -11,6 +11,7 @@ #include "lld/Core/Atom.h" #include "lld/Core/DefinedAtom.h" #include "lld/Core/UndefinedAtom.h" +#include "lld/Core/Pass.h" #include "lld/Core/Resolver.h" #include "lld/Core/YamlReader.h" #include "lld/Core/YamlWriter.h" @@ -22,6 +23,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/Twine.h" +#include "llvm/Support/CommandLine.h" #include "llvm/Support/DataTypes.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/MemoryBuffer.h" @@ -49,15 +51,110 @@ static bool error(llvm::error_code ec) { } namespace { -class LdCore : public InputFiles, public Platform { -public: - LdCore(std::vector &f) : _files(f) { } - // InputFiles interface - virtual void forEachInitialAtom(File::AtomHandler &) const; - virtual bool searchLibraries(llvm::StringRef name, bool searchDylibs, - bool searchArchives, bool dataSymbolOnly, - File::AtomHandler &) const; + +// +// Simple atoms created by the stubs pass. +// +class TestingStubAtom : public DefinedAtom { +public: + TestingStubAtom(const File& f, const SharedLibraryAtom& shlib) : + _file(f), _shlib(shlib) { + static uint32_t lastOrdinal = 0; + _ordinal = lastOrdinal++; + } + + virtual const File& file() const { + return _file; + } + + virtual llvm::StringRef name() const { + return llvm::StringRef(); + } + + virtual uint64_t ordinal() const { + return _ordinal; + } + + virtual uint64_t size() const { + return 0; + } + + virtual Scope scope() const { + return DefinedAtom::scopeLinkageUnit; + } + + virtual Interposable interposable() const { + return DefinedAtom::interposeNo; + } + + virtual Merge merge() const { + return DefinedAtom::mergeNo; + } + + virtual ContentType contentType() const { + return DefinedAtom::typeStub; + } + + virtual Alignment alignment() const { + return Alignment(0,0); + } + + virtual SectionChoice sectionChoice() const { + return DefinedAtom::sectionBasedOnContent; + } + + virtual llvm::StringRef customSectionName() const { + return llvm::StringRef(); + } + virtual DeadStripKind deadStrip() const { + return DefinedAtom::deadStripNormal; + } + + virtual ContentPermissions permissions() const { + return DefinedAtom::permR_X; + } + + virtual bool isThumb() const { + return false; + } + + virtual bool isAlias() const { + return false; + } + + virtual llvm::ArrayRef rawContent() const { + return llvm::ArrayRef(); + } + + virtual reference_iterator referencesBegin() const { + return reference_iterator(*this, NULL); + } + + virtual reference_iterator referencesEnd() const { + return reference_iterator(*this, NULL); + } + + virtual const Reference* derefIterator(const void* iter) const { + return NULL; + } + + virtual void incrementIterator(const void*& iter) const { + + } + +private: + const File& _file; + const SharedLibraryAtom& _shlib; + uint32_t _ordinal; +}; + + +// +// A simple platform for testing. +// +class TestingPlatform : public Platform { +public: virtual void initialize() { } @@ -155,97 +252,163 @@ public: // last chance for platform to tweak atoms virtual void postResolveTweaks(std::vector &all) {} -private: - std::vector &_files; + virtual bool outputUsesStubs() { return true; }; + + + struct KindMapping { + const char* string; + Reference::Kind value; + bool isBranch; + }; + + static const KindMapping _s_kindMappings[]; + + virtual Reference::Kind kindFromString(llvm::StringRef kindName) { + for (const KindMapping* p = _s_kindMappings; p->string != NULL; ++p) { + if ( kindName.equals(p->string) ) + return p->value; + } + int k; + kindName.getAsInteger(0, k); + return k; + } + + virtual llvm::StringRef kindToString(Reference::Kind value) { + for (const KindMapping* p = _s_kindMappings; p->string != NULL; ++p) { + if ( value == p->value) + return p->string; + } + return llvm::StringRef("???"); + } + + + virtual bool isBranch(const Reference* ref) { + Reference::Kind value = ref->kind(); + for (const KindMapping* p = _s_kindMappings; p->string != NULL; ++p) { + if ( value == p->value ) + return p->isBranch; + } + return false; + } + + virtual const Atom* makeStub(const SharedLibraryAtom& shlibAtom, File& file) { + return new TestingStubAtom(file, shlibAtom); + } }; -} -void LdCore::forEachInitialAtom(File::AtomHandler &handler) const { - for (std::vector::iterator it = _files.begin(); - it != _files.end(); ++it) { - const File *file = *it; - handler.doFile(*file); - file->forEachAtom(handler); - } -} -bool LdCore::searchLibraries(llvm::StringRef name, bool searchDylibs, - bool searchArchives, bool dataSymbolOnly, - File::AtomHandler &) const { - return false; -} +// +// Table of fixup kinds in YAML documents used for testing +// +const TestingPlatform::KindMapping TestingPlatform::_s_kindMappings[] = { + { "call32", 1, true }, + { "pcrel32", 2, false }, + { "gotLoad32", 3, false }, + { NULL, 0, false } + }; -namespace { -class MergedFile : public File { + +// +// A simple input files wrapper for testing. +// +class TestingInputFiles : public InputFiles { public: - MergedFile(std::vector &a) - : File("path"), _atoms(a) { } + TestingInputFiles(std::vector& f) : _files(f) { } - virtual bool forEachAtom(File::AtomHandler &handler) const { - handler.doFile(*this); - // visit defined atoms - for (std::vector::iterator it = _atoms.begin(); - it != _atoms.end(); ++it) { - const DefinedAtom* atom = (*it)->definedAtom(); - if ( atom ) - handler.doDefinedAtom(*atom); + // InputFiles interface + virtual void forEachInitialAtom(InputFiles::Handler& handler) const { + for (std::vector::iterator fit = _files.begin(); + fit != _files.end(); ++fit) { + const File* file = *fit; + handler.doFile(*file); + for(auto it=file->definedAtomsBegin(),end=file->definedAtomsEnd(); + it != end; ++it) { + handler.doDefinedAtom(**it); + } + for(auto it=file->undefinedAtomsBegin(), end=file->undefinedAtomsEnd(); + it != end; ++it) { + handler.doUndefinedAtom(**it); + } + for(auto it=file->sharedLibraryAtomsBegin(), end=file->sharedLibraryAtomsEnd(); + it != end; ++it) { + handler.doSharedLibraryAtom(**it); + } + for(auto it=file->absoluteAtomsBegin(),end=file->absoluteAtomsEnd(); + it != end; ++it) { + handler.doAbsoluteAtom(**it); + } } - // visit undefined atoms - for (std::vector::iterator it = _atoms.begin(); - it != _atoms.end(); ++it) { - const UndefinedAtom* atom = (*it)->undefinedAtom(); - if ( atom ) - handler.doUndefinedAtom(*atom); - } - // visit shared library atoms - for (std::vector::iterator it = _atoms.begin(); - it != _atoms.end(); ++it) { - const SharedLibraryAtom* atom = (*it)->sharedLibraryAtom(); - if ( atom ) - handler.doSharedLibraryAtom(*atom); - } - // visit absolute atoms - for (std::vector::iterator it = _atoms.begin(); - it != _atoms.end(); ++it) { - const AbsoluteAtom* atom = (*it)->absoluteAtom(); - if ( atom ) - handler.doAbsoluteAtom(*atom); - } - return true; } - virtual bool justInTimeforEachAtom(llvm::StringRef name, - File::AtomHandler &) const { + virtual bool searchLibraries(llvm::StringRef name, bool searchDylibs, + bool searchArchives, bool dataSymbolOnly, + InputFiles::Handler &) const { return false; } + private: - std::vector &_atoms; + std::vector& _files; }; -} //anonymous namespace +} -int main(int argc, const char *argv[]) { + + + + +llvm::cl::opt +gInputFilePath(llvm::cl::Positional, + llvm::cl::desc(""), + llvm::cl::init("-")); + +llvm::cl::opt +gOutputFilePath("o", + llvm::cl::desc("Specify output filename"), + llvm::cl::value_desc("filename")); + +llvm::cl::opt +gDoStubsPass("stubs_pass", + llvm::cl::desc("Run pass to create stub atoms")); + + +int main(int argc, char *argv[]) { // Print a stack trace if we signal out. llvm::sys::PrintStackTraceOnErrorSignal(); llvm::PrettyStackTraceProgram X(argc, argv); llvm::llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. + // parse options + llvm::cl::ParseCommandLineOptions(argc, argv); + + // create platform for testing + TestingPlatform testingPlatform; + // read input YAML doc into object file(s) - std::vector files; - if (error(yaml::parseObjectTextFileOrSTDIN(llvm::StringRef(argv[1]), files))) + std::vector files; + if (error(yaml::parseObjectTextFileOrSTDIN(gInputFilePath, + testingPlatform, files))) { return 1; - + } + + // create object to mange input files + TestingInputFiles inputFiles(files); + // merge all atom graphs - LdCore core(files); - Resolver resolver(core, core); - std::vector &mergedAtoms = resolver.resolve(); - MergedFile outFile(mergedAtoms); + Resolver resolver(testingPlatform, inputFiles); + resolver.resolve(); + // run passes + if ( gDoStubsPass ) { + StubsPass addStubs(resolver.resultFile(), testingPlatform); + addStubs.perform(); + } + // write new atom graph out as YAML doc std::string errorInfo; - llvm::raw_fd_ostream out("-", errorInfo); -// yaml::writeObjectText(outFile, out); + const char* outPath = gOutputFilePath.empty() ? "-" : gOutputFilePath.c_str(); + llvm::raw_fd_ostream out(outPath, errorInfo); +// yaml::writeObjectText(resolver.resultFile(), out); // make unique temp .o file to put generated object file int fd; @@ -254,7 +417,7 @@ int main(int argc, const char *argv[]) { llvm::raw_fd_ostream binaryOut(fd, /*shouldClose=*/true); // write native file - writeNativeObjectFile(outFile, binaryOut); + writeNativeObjectFile(resolver.resultFile(), binaryOut); binaryOut.close(); // manually close so that file can be read next // out << "native file: " << tempPath.str() << "\n"; @@ -265,7 +428,7 @@ int main(int argc, const char *argv[]) { return 1; // write new atom graph out as YAML doc - yaml::writeObjectText(*natFile, out); + yaml::writeObjectText(*natFile, testingPlatform, out); // delete temp .o file bool existed;