forked from OSchip/llvm-project
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
This commit is contained in:
parent
11e8c0d6b5
commit
1a6615dc88
|
@ -1,6 +1,8 @@
|
||||||
# If we are not building as a part of LLVM, build lld as a standalone project,
|
# If we are not building as a part of LLVM, build lld as a standalone project,
|
||||||
# using LLVM as an external library.
|
# using LLVM as an external library.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
|
if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
|
||||||
project(lld)
|
project(lld)
|
||||||
cmake_minimum_required(VERSION 2.8)
|
cmake_minimum_required(VERSION 2.8)
|
||||||
|
@ -58,6 +60,20 @@ if (CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR)
|
||||||
"`CMakeFiles'. Please delete them.")
|
"`CMakeFiles'. Please delete them.")
|
||||||
endif()
|
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)
|
macro(add_lld_library name)
|
||||||
llvm_process_sources(srcs ${ARGN})
|
llvm_process_sources(srcs ${ARGN})
|
||||||
if (MSVC_IDE OR XCODE)
|
if (MSVC_IDE OR XCODE)
|
||||||
|
|
|
@ -24,7 +24,7 @@ class UndefinedAtom;
|
||||||
class SharedLibraryAtom;
|
class SharedLibraryAtom;
|
||||||
class AbsoluteAtom;
|
class AbsoluteAtom;
|
||||||
|
|
||||||
///
|
///
|
||||||
/// The linker has a Graph Theory model of linking. An object file is seen
|
/// 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
|
/// 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
|
/// and each Reference is an edge. An Atom can be a DefinedAtom which has
|
||||||
|
|
|
@ -195,13 +195,6 @@ public:
|
||||||
uint16_t modulus;
|
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.
|
/// 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
|
/// This is used by the linker to order the layout of Atoms so that
|
||||||
/// the resulting image is stable and reproducible.
|
/// the resulting image is stable and reproducible.
|
||||||
|
@ -266,10 +259,43 @@ public:
|
||||||
/// rawContent - returns a reference to the raw (unrelocated) bytes of
|
/// rawContent - returns a reference to the raw (unrelocated) bytes of
|
||||||
/// this Atom's content.
|
/// this Atom's content.
|
||||||
virtual llvm::ArrayRef<uint8_t> rawContent() const = 0;
|
virtual llvm::ArrayRef<uint8_t> 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:
|
protected:
|
||||||
/// DefinedAtom is an abstract base class.
|
/// DefinedAtom is an abstract base class.
|
||||||
/// Only subclasses can access constructor.
|
/// Only subclasses can access constructor.
|
||||||
|
@ -280,6 +306,15 @@ protected:
|
||||||
/// delete on an Atom. In fact, some File objects may bulk allocate
|
/// delete on an Atom. In fact, some File objects may bulk allocate
|
||||||
/// an array of Atoms, so they cannot be individually deleted by anyone.
|
/// an array of Atoms, so they cannot be individually deleted by anyone.
|
||||||
virtual ~DefinedAtom() {}
|
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
|
} // namespace lld
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//===- Core/File.h - A Contaier of Atoms ----------------------------------===//
|
//===- Core/File.h - A Container of Atoms ---------------------------------===//
|
||||||
//
|
//
|
||||||
// The LLVM Linker
|
// The LLVM Linker
|
||||||
//
|
//
|
||||||
|
@ -10,6 +10,8 @@
|
||||||
#ifndef LLD_CORE_FILE_H_
|
#ifndef LLD_CORE_FILE_H_
|
||||||
#define LLD_CORE_FILE_H_
|
#define LLD_CORE_FILE_H_
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "llvm/ADT/StringRef.h"
|
#include "llvm/ADT/StringRef.h"
|
||||||
|
|
||||||
#include "lld/Core/DefinedAtom.h"
|
#include "lld/Core/DefinedAtom.h"
|
||||||
|
@ -19,31 +21,190 @@
|
||||||
|
|
||||||
namespace lld {
|
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 {
|
class File {
|
||||||
public:
|
public:
|
||||||
File(llvm::StringRef p) : _path(p) {}
|
|
||||||
virtual ~File();
|
virtual ~File();
|
||||||
|
|
||||||
class AtomHandler {
|
/// For error messages and debugging, this returns the path to the file
|
||||||
public:
|
/// which was used to create this object (e.g. "/tmp/foo.o").
|
||||||
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;
|
|
||||||
};
|
|
||||||
|
|
||||||
llvm::StringRef path() const {
|
llvm::StringRef path() const {
|
||||||
return _path;
|
return _path;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool forEachAtom(AtomHandler &) const = 0;
|
/// Returns the path of the source file used to create the object
|
||||||
virtual bool justInTimeforEachAtom( llvm::StringRef name
|
/// file which this (File) object represents. This information is usually
|
||||||
, AtomHandler &) const = 0;
|
/// 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 <typename T> class atom_iterator; // forward reference
|
||||||
|
public:
|
||||||
|
|
||||||
|
/// For use interating over DefinedAtoms in this File.
|
||||||
|
typedef atom_iterator<DefinedAtom> defined_iterator;
|
||||||
|
|
||||||
|
/// For use interating over UndefinedAtoms in this File.
|
||||||
|
typedef atom_iterator<UndefinedAtom> undefined_iterator;
|
||||||
|
|
||||||
|
/// For use interating over SharedLibraryAtoms in this File.
|
||||||
|
typedef atom_iterator<SharedLibraryAtom> shared_library_iterator;
|
||||||
|
|
||||||
|
/// For use interating over AbsoluteAtoms in this File.
|
||||||
|
typedef atom_iterator<AbsoluteAtom> 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 <typename T>
|
||||||
|
class atom_collection {
|
||||||
|
public:
|
||||||
|
virtual atom_iterator<T> begin() const = 0;
|
||||||
|
virtual atom_iterator<T> 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 <typename T>
|
||||||
|
class atom_iterator {
|
||||||
|
public:
|
||||||
|
atom_iterator(const atom_collection<T>& 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<T>& other) const {
|
||||||
|
return (this->_it != other._it);
|
||||||
|
}
|
||||||
|
|
||||||
|
atom_iterator<T>& operator++() {
|
||||||
|
_collection.next(_it);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
const atom_collection<T>& _collection;
|
||||||
|
const void* _it;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Must be implemented to return the atom_collection object for
|
||||||
|
/// all DefinedAtoms in this File.
|
||||||
|
virtual const atom_collection<DefinedAtom>& defined() const = 0;
|
||||||
|
|
||||||
|
/// Must be implemented to return the atom_collection object for
|
||||||
|
/// all UndefinedAtomw in this File.
|
||||||
|
virtual const atom_collection<UndefinedAtom>& undefined() const = 0;
|
||||||
|
|
||||||
|
/// Must be implemented to return the atom_collection object for
|
||||||
|
/// all SharedLibraryAtoms in this File.
|
||||||
|
virtual const atom_collection<SharedLibraryAtom>& sharedLibrary() const = 0;
|
||||||
|
|
||||||
|
/// Must be implemented to return the atom_collection object for
|
||||||
|
/// all AbsoluteAtoms in this File.
|
||||||
|
virtual const atom_collection<AbsoluteAtom>& absolute() const = 0;
|
||||||
|
|
||||||
|
/// This is a convenience class for File subclasses which manage their
|
||||||
|
/// atoms as a simple std::vector<>.
|
||||||
|
template <typename T>
|
||||||
|
class atom_collection_vector : public atom_collection<T> {
|
||||||
|
public:
|
||||||
|
virtual atom_iterator<T> begin() const {
|
||||||
|
return atom_iterator<T>(*this, reinterpret_cast<const void*>(&_atoms[0]));
|
||||||
|
}
|
||||||
|
virtual atom_iterator<T> end() const{
|
||||||
|
return atom_iterator<T>(*this, reinterpret_cast<const void*>
|
||||||
|
(&_atoms[_atoms.size()]));
|
||||||
|
}
|
||||||
|
virtual const T* deref(const void* it) const {
|
||||||
|
return *reinterpret_cast<const T* const*>(it);
|
||||||
|
}
|
||||||
|
virtual void next(const void*& it) const {
|
||||||
|
const T * const * p = reinterpret_cast<const T * const *>(it);
|
||||||
|
++p;
|
||||||
|
it = reinterpret_cast<const void*>(p);
|
||||||
|
}
|
||||||
|
std::vector<const T*> _atoms;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
llvm::StringRef _path;
|
llvm::StringRef _path;
|
||||||
|
|
|
@ -24,15 +24,26 @@ namespace lld {
|
||||||
/// The searchLibraries() method is used to lazily search libraries.
|
/// The searchLibraries() method is used to lazily search libraries.
|
||||||
class InputFiles {
|
class InputFiles {
|
||||||
public:
|
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
|
/// @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
|
/// @brief searches libraries for name
|
||||||
virtual bool searchLibraries( llvm::StringRef name
|
virtual bool searchLibraries( llvm::StringRef name
|
||||||
, bool searchDylibs
|
, bool searchDylibs
|
||||||
, bool searchArchives
|
, bool searchArchives
|
||||||
, bool dataSymbolOnly
|
, bool dataSymbolOnly
|
||||||
, File::AtomHandler &) const = 0;
|
, Handler &) const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace lld
|
} // namespace lld
|
||||||
|
|
|
@ -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 <vector>
|
||||||
|
|
||||||
|
#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_
|
|
@ -11,6 +11,7 @@
|
||||||
#define LLD_CORE_RESOLVER_H_
|
#define LLD_CORE_RESOLVER_H_
|
||||||
|
|
||||||
#include "lld/Core/File.h"
|
#include "lld/Core/File.h"
|
||||||
|
#include "lld/Core/InputFiles.h"
|
||||||
#include "lld/Core/SymbolTable.h"
|
#include "lld/Core/SymbolTable.h"
|
||||||
|
|
||||||
#include "llvm/ADT/DenseSet.h"
|
#include "llvm/ADT/DenseSet.h"
|
||||||
|
@ -30,7 +31,7 @@ class SymbolTable;
|
||||||
///
|
///
|
||||||
/// All platform specific resolving is done by delegating to the
|
/// All platform specific resolving is done by delegating to the
|
||||||
/// Platform object specified.
|
/// Platform object specified.
|
||||||
class Resolver : public File::AtomHandler {
|
class Resolver : public InputFiles::Handler {
|
||||||
public:
|
public:
|
||||||
Resolver(Platform &plat, const InputFiles &inputs)
|
Resolver(Platform &plat, const InputFiles &inputs)
|
||||||
: _platform(plat)
|
: _platform(plat)
|
||||||
|
@ -40,7 +41,7 @@ public:
|
||||||
, _addToFinalSection(false)
|
, _addToFinalSection(false)
|
||||||
, _completedInitialObjectFiles(false) {}
|
, _completedInitialObjectFiles(false) {}
|
||||||
|
|
||||||
// AtomHandler methods
|
// InputFiles::Handler methods
|
||||||
virtual void doDefinedAtom(const class DefinedAtom&);
|
virtual void doDefinedAtom(const class DefinedAtom&);
|
||||||
virtual void doUndefinedAtom(const class UndefinedAtom&);
|
virtual void doUndefinedAtom(const class UndefinedAtom&);
|
||||||
virtual void doSharedLibraryAtom(const class SharedLibraryAtom &);
|
virtual void doSharedLibraryAtom(const class SharedLibraryAtom &);
|
||||||
|
@ -48,7 +49,11 @@ public:
|
||||||
virtual void doFile(const File&);
|
virtual void doFile(const File&);
|
||||||
|
|
||||||
/// @brief do work of merging and resolving and return list
|
/// @brief do work of merging and resolving and return list
|
||||||
std::vector<const Atom *> &resolve();
|
void resolve();
|
||||||
|
|
||||||
|
File& resultFile() {
|
||||||
|
return _result;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct WhyLiveBackChain {
|
struct WhyLiveBackChain {
|
||||||
|
@ -73,31 +78,49 @@ private:
|
||||||
void addAtoms(const std::vector<const DefinedAtom *>&);
|
void addAtoms(const std::vector<const DefinedAtom *>&);
|
||||||
|
|
||||||
|
|
||||||
// helper to update targets for use with forEachReference()
|
class MergedFile : public File {
|
||||||
class MarkLiveReferences : public DefinedAtom::ReferenceHandler {
|
|
||||||
public:
|
public:
|
||||||
MarkLiveReferences(Resolver& resolver, WhyLiveBackChain* chain)
|
MergedFile() : File("<linker-internal>") { }
|
||||||
: _resolver(resolver), _chain(chain) { }
|
|
||||||
|
|
||||||
virtual void doReference(const Reference& ref) {
|
|
||||||
_resolver.markLive(*ref.target(), _chain);
|
|
||||||
}
|
virtual const atom_collection<DefinedAtom>& defined() const {
|
||||||
|
return _definedAtoms;
|
||||||
|
}
|
||||||
|
virtual const atom_collection<UndefinedAtom>& undefined() const {
|
||||||
|
return _undefinedAtoms;
|
||||||
|
}
|
||||||
|
virtual const atom_collection<SharedLibraryAtom>& sharedLibrary() const {
|
||||||
|
return _sharedLibraryAtoms;
|
||||||
|
}
|
||||||
|
virtual const atom_collection<AbsoluteAtom>& absolute() const {
|
||||||
|
return _absoluteAtoms;
|
||||||
|
}
|
||||||
|
|
||||||
|
void addAtoms(std::vector<const Atom*>& atoms);
|
||||||
|
|
||||||
|
virtual void addAtom(const Atom& atom);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Resolver& _resolver;
|
atom_collection_vector<DefinedAtom> _definedAtoms;
|
||||||
WhyLiveBackChain* _chain;
|
atom_collection_vector<UndefinedAtom> _undefinedAtoms;
|
||||||
|
atom_collection_vector<SharedLibraryAtom> _sharedLibraryAtoms;
|
||||||
|
atom_collection_vector<AbsoluteAtom> _absoluteAtoms;
|
||||||
};
|
};
|
||||||
|
|
||||||
Platform &_platform;
|
|
||||||
const InputFiles &_inputFiles;
|
|
||||||
SymbolTable _symbolTable;
|
Platform& _platform;
|
||||||
std::vector<const Atom *> _atoms;
|
const InputFiles& _inputFiles;
|
||||||
std::set<const Atom *> _deadStripRoots;
|
SymbolTable _symbolTable;
|
||||||
std::vector<const Atom *> _atomsWithUnresolvedReferences;
|
std::vector<const Atom *> _atoms;
|
||||||
llvm::DenseSet<const Atom *> _liveAtoms;
|
std::set<const Atom *> _deadStripRoots;
|
||||||
bool _haveLLVMObjs;
|
std::vector<const Atom *> _atomsWithUnresolvedReferences;
|
||||||
bool _addToFinalSection;
|
llvm::DenseSet<const Atom *> _liveAtoms;
|
||||||
bool _completedInitialObjectFiles;
|
MergedFile _result;
|
||||||
|
bool _haveLLVMObjs;
|
||||||
|
bool _addToFinalSection;
|
||||||
|
bool _completedInitialObjectFiles;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace lld
|
} // namespace lld
|
||||||
|
|
|
@ -10,8 +10,6 @@
|
||||||
#ifndef LLD_CORE_YAML_READER_H_
|
#ifndef LLD_CORE_YAML_READER_H_
|
||||||
#define LLD_CORE_YAML_READER_H_
|
#define LLD_CORE_YAML_READER_H_
|
||||||
|
|
||||||
#include "lld/Core/File.h"
|
|
||||||
|
|
||||||
#include "llvm/Support/system_error.h"
|
#include "llvm/Support/system_error.h"
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
@ -19,19 +17,25 @@
|
||||||
namespace llvm { class MemoryBuffer; }
|
namespace llvm { class MemoryBuffer; }
|
||||||
|
|
||||||
namespace lld {
|
namespace lld {
|
||||||
|
|
||||||
|
class Platform;
|
||||||
|
class File;
|
||||||
|
|
||||||
namespace yaml {
|
namespace yaml {
|
||||||
|
|
||||||
/// parseObjectTextFileOrSTDIN - Open the specified YAML file (use stdin if
|
/// parseObjectTextFileOrSTDIN - Open the specified YAML file (use stdin if
|
||||||
/// the path is "-") and parse into lld::File object(s) and append each to
|
/// the path is "-") and parse into lld::File object(s) and append each to
|
||||||
/// the specified vector<File*>.
|
/// the specified vector<File*>.
|
||||||
llvm::error_code parseObjectTextFileOrSTDIN(llvm::StringRef path
|
llvm::error_code parseObjectTextFileOrSTDIN(llvm::StringRef path
|
||||||
, std::vector<File *>&);
|
, Platform&
|
||||||
|
, std::vector<const File *>&);
|
||||||
|
|
||||||
|
|
||||||
/// parseObjectText - Parse the specified YAML formatted MemoryBuffer
|
/// parseObjectText - Parse the specified YAML formatted MemoryBuffer
|
||||||
/// into lld::File object(s) and append each to the specified vector<File*>.
|
/// into lld::File object(s) and append each to the specified vector<File*>.
|
||||||
llvm::error_code parseObjectText(llvm::MemoryBuffer *mb
|
llvm::error_code parseObjectText(llvm::MemoryBuffer *mb
|
||||||
, std::vector<File *>&);
|
, Platform&
|
||||||
|
, std::vector<const File *>&);
|
||||||
|
|
||||||
} // namespace yaml
|
} // namespace yaml
|
||||||
} // namespace lld
|
} // namespace lld
|
||||||
|
|
|
@ -10,15 +10,18 @@
|
||||||
#ifndef LLD_CORE_YAML_WRITER_H_
|
#ifndef LLD_CORE_YAML_WRITER_H_
|
||||||
#define LLD_CORE_YAML_WRITER_H_
|
#define LLD_CORE_YAML_WRITER_H_
|
||||||
|
|
||||||
#include "lld/Core/File.h"
|
|
||||||
#include "llvm/Support/raw_ostream.h"
|
#include "llvm/Support/raw_ostream.h"
|
||||||
|
|
||||||
namespace lld {
|
namespace lld {
|
||||||
|
|
||||||
|
class Platform;
|
||||||
|
class File;
|
||||||
|
|
||||||
namespace yaml {
|
namespace yaml {
|
||||||
|
|
||||||
/// writeObjectText - writes the lld::File object as in YAML
|
/// writeObjectText - writes the lld::File object as in YAML
|
||||||
/// format to the specified stream.
|
/// 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 yaml
|
||||||
} // namespace lld
|
} // namespace lld
|
||||||
|
|
|
@ -12,10 +12,13 @@
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "lld/Core/Reference.h"
|
||||||
|
|
||||||
namespace lld {
|
namespace lld {
|
||||||
class Atom;
|
class Atom;
|
||||||
class DefinedAtom;
|
class DefinedAtom;
|
||||||
|
|
||||||
|
|
||||||
/// The Platform class encapsulated plaform specific linking knowledge.
|
/// The Platform class encapsulated plaform specific linking knowledge.
|
||||||
///
|
///
|
||||||
/// Much of what it does is driving by platform specific linker options.
|
/// 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
|
/// @brief last chance for platform to tweak atoms
|
||||||
virtual void postResolveTweaks(std::vector<const Atom *>& all) = 0;
|
virtual void postResolveTweaks(std::vector<const Atom *>& 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
|
} // namespace lld
|
||||||
|
|
|
@ -1 +1,2 @@
|
||||||
add_subdirectory(Core)
|
add_subdirectory(Core)
|
||||||
|
add_subdirectory(Passes)
|
||||||
|
|
|
@ -13,8 +13,8 @@ namespace lld {
|
||||||
|
|
||||||
File::~File() {}
|
File::~File() {}
|
||||||
|
|
||||||
bool File::translationUnitSource(llvm::StringRef &path) const {
|
llvm::StringRef File::translationUnitSource() const {
|
||||||
return false;
|
return llvm::StringRef();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -92,9 +92,15 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual llvm::ArrayRef<uint8_t> rawContent() const;
|
virtual llvm::ArrayRef<uint8_t> 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:
|
private:
|
||||||
const NativeAtomAttributesV1& attributes() const;
|
const NativeAtomAttributesV1& attributes() const;
|
||||||
|
|
||||||
|
@ -299,53 +305,29 @@ public:
|
||||||
// the _definedAtoms array which was allocated to contain an array
|
// the _definedAtoms array which was allocated to contain an array
|
||||||
// of Atom objects. The atoms have empty destructors, so it is ok
|
// of Atom objects. The atoms have empty destructors, so it is ok
|
||||||
// to just delete the memory.
|
// to just delete the memory.
|
||||||
delete _definedAtoms.arrayStart;
|
delete _definedAtoms._arrayStart;
|
||||||
delete _undefinedAtoms.arrayStart;
|
delete _undefinedAtoms._arrayStart;
|
||||||
delete _sharedLibraryAtoms.arrayStart;
|
delete _sharedLibraryAtoms._arrayStart;
|
||||||
delete _absoluteAtoms.arrayStart;
|
delete _absoluteAtoms._arrayStart;
|
||||||
delete _references.arrayStart;
|
delete _references.arrayStart;
|
||||||
delete _targetsTable;
|
delete _targetsTable;
|
||||||
}
|
}
|
||||||
|
|
||||||
// visits each atom in the file
|
virtual const atom_collection<DefinedAtom>& defined() const {
|
||||||
virtual bool forEachAtom(AtomHandler& handler) const {
|
return _definedAtoms;
|
||||||
bool didSomething = false;
|
|
||||||
for(const uint8_t* p=_definedAtoms.arrayStart; p != _definedAtoms.arrayEnd;
|
|
||||||
p += _definedAtoms.elementSize) {
|
|
||||||
const DefinedAtom* atom = reinterpret_cast<const DefinedAtom*>(p);
|
|
||||||
handler.doDefinedAtom(*atom);
|
|
||||||
didSomething = true;
|
|
||||||
}
|
|
||||||
for(const uint8_t* p=_undefinedAtoms.arrayStart;
|
|
||||||
p != _undefinedAtoms.arrayEnd;
|
|
||||||
p += _undefinedAtoms.elementSize) {
|
|
||||||
const UndefinedAtom* atom = reinterpret_cast<const UndefinedAtom*>(p);
|
|
||||||
handler.doUndefinedAtom(*atom);
|
|
||||||
didSomething = true;
|
|
||||||
}
|
|
||||||
for(const uint8_t* p=_sharedLibraryAtoms.arrayStart;
|
|
||||||
p != _sharedLibraryAtoms.arrayEnd;
|
|
||||||
p += _sharedLibraryAtoms.elementSize) {
|
|
||||||
const SharedLibraryAtom* atom
|
|
||||||
= reinterpret_cast<const SharedLibraryAtom*>(p);
|
|
||||||
handler.doSharedLibraryAtom(*atom);
|
|
||||||
didSomething = true;
|
|
||||||
}
|
|
||||||
for(const uint8_t* p=_absoluteAtoms.arrayStart;
|
|
||||||
p != _absoluteAtoms.arrayEnd;
|
|
||||||
p += _absoluteAtoms.elementSize) {
|
|
||||||
const AbsoluteAtom* atom
|
|
||||||
= reinterpret_cast<const AbsoluteAtom*>(p);
|
|
||||||
handler.doAbsoluteAtom(*atom);
|
|
||||||
didSomething = true;
|
|
||||||
}
|
|
||||||
return didSomething;
|
|
||||||
}
|
}
|
||||||
|
virtual const atom_collection<UndefinedAtom>& undefined() const {
|
||||||
// not used
|
return _undefinedAtoms;
|
||||||
virtual bool justInTimeforEachAtom(llvm::StringRef name,
|
}
|
||||||
AtomHandler &) const {
|
virtual const atom_collection<SharedLibraryAtom>& sharedLibrary() const {
|
||||||
return false;
|
return _sharedLibraryAtoms;
|
||||||
|
}
|
||||||
|
virtual const atom_collection<AbsoluteAtom>& absolute() const {
|
||||||
|
return _absoluteAtoms;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void addAtom(const Atom&) {
|
||||||
|
assert(0 && "cannot add atoms to native .o files");
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -378,10 +360,10 @@ private:
|
||||||
new (atomAllocSpace) NativeDefinedAtomV1(*this, ivarData);
|
new (atomAllocSpace) NativeDefinedAtomV1(*this, ivarData);
|
||||||
++ivarData;
|
++ivarData;
|
||||||
}
|
}
|
||||||
this->_definedAtoms.arrayStart = atomsStart;
|
this->_definedAtoms._arrayStart = atomsStart;
|
||||||
this->_definedAtoms.arrayEnd = atomsEnd;
|
this->_definedAtoms._arrayEnd = atomsEnd;
|
||||||
this->_definedAtoms.elementSize = atomSize;
|
this->_definedAtoms._elementSize = atomSize;
|
||||||
this->_definedAtoms.elementCount = chunk->elementCount;
|
this->_definedAtoms._elementCount = chunk->elementCount;
|
||||||
return make_error_code(native_reader_error::success);
|
return make_error_code(native_reader_error::success);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -416,10 +398,10 @@ private:
|
||||||
new (atomAllocSpace) NativeUndefinedAtomV1(*this, ivarData);
|
new (atomAllocSpace) NativeUndefinedAtomV1(*this, ivarData);
|
||||||
++ivarData;
|
++ivarData;
|
||||||
}
|
}
|
||||||
this->_undefinedAtoms.arrayStart = atomsStart;
|
this->_undefinedAtoms._arrayStart = atomsStart;
|
||||||
this->_undefinedAtoms.arrayEnd = atomsEnd;
|
this->_undefinedAtoms._arrayEnd = atomsEnd;
|
||||||
this->_undefinedAtoms.elementSize = atomSize;
|
this->_undefinedAtoms._elementSize = atomSize;
|
||||||
this->_undefinedAtoms.elementCount = chunk->elementCount;
|
this->_undefinedAtoms._elementCount = chunk->elementCount;
|
||||||
return make_error_code(native_reader_error::success);
|
return make_error_code(native_reader_error::success);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -447,10 +429,10 @@ private:
|
||||||
new (atomAllocSpace) NativeSharedLibraryAtomV1(*this, ivarData);
|
new (atomAllocSpace) NativeSharedLibraryAtomV1(*this, ivarData);
|
||||||
++ivarData;
|
++ivarData;
|
||||||
}
|
}
|
||||||
this->_sharedLibraryAtoms.arrayStart = atomsStart;
|
this->_sharedLibraryAtoms._arrayStart = atomsStart;
|
||||||
this->_sharedLibraryAtoms.arrayEnd = atomsEnd;
|
this->_sharedLibraryAtoms._arrayEnd = atomsEnd;
|
||||||
this->_sharedLibraryAtoms.elementSize = atomSize;
|
this->_sharedLibraryAtoms._elementSize = atomSize;
|
||||||
this->_sharedLibraryAtoms.elementCount = chunk->elementCount;
|
this->_sharedLibraryAtoms._elementCount = chunk->elementCount;
|
||||||
return make_error_code(native_reader_error::success);
|
return make_error_code(native_reader_error::success);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -478,10 +460,10 @@ private:
|
||||||
new (atomAllocSpace) NativeAbsoluteAtomV1(*this, ivarData);
|
new (atomAllocSpace) NativeAbsoluteAtomV1(*this, ivarData);
|
||||||
++ivarData;
|
++ivarData;
|
||||||
}
|
}
|
||||||
this->_absoluteAtoms.arrayStart = atomsStart;
|
this->_absoluteAtoms._arrayStart = atomsStart;
|
||||||
this->_absoluteAtoms.arrayEnd = atomsEnd;
|
this->_absoluteAtoms._arrayEnd = atomsEnd;
|
||||||
this->_absoluteAtoms.elementSize = atomSize;
|
this->_absoluteAtoms._elementSize = atomSize;
|
||||||
this->_absoluteAtoms.elementCount = chunk->elementCount;
|
this->_absoluteAtoms._elementCount = chunk->elementCount;
|
||||||
return make_error_code(native_reader_error::success);
|
return make_error_code(native_reader_error::success);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -529,33 +511,33 @@ private:
|
||||||
this->_targetsTable = new const Atom*[chunk->elementCount];
|
this->_targetsTable = new const Atom*[chunk->elementCount];
|
||||||
for (uint32_t i=0; i < chunk->elementCount; ++i) {
|
for (uint32_t i=0; i < chunk->elementCount; ++i) {
|
||||||
const uint32_t index = targetIndexes[i];
|
const uint32_t index = targetIndexes[i];
|
||||||
if ( index < _definedAtoms.elementCount ) {
|
if ( index < _definedAtoms._elementCount ) {
|
||||||
const uint8_t* p = _definedAtoms.arrayStart
|
const uint8_t* p = _definedAtoms._arrayStart
|
||||||
+ index * _definedAtoms.elementSize;
|
+ index * _definedAtoms._elementSize;
|
||||||
this->_targetsTable[i] = reinterpret_cast<const DefinedAtom*>(p);
|
this->_targetsTable[i] = reinterpret_cast<const DefinedAtom*>(p);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const uint32_t undefIndex = index - _definedAtoms.elementCount;
|
const uint32_t undefIndex = index - _definedAtoms._elementCount;
|
||||||
if ( undefIndex < _undefinedAtoms.elementCount ) {
|
if ( undefIndex < _undefinedAtoms._elementCount ) {
|
||||||
const uint8_t* p = _undefinedAtoms.arrayStart
|
const uint8_t* p = _undefinedAtoms._arrayStart
|
||||||
+ undefIndex * _undefinedAtoms.elementSize;
|
+ undefIndex * _undefinedAtoms._elementSize;
|
||||||
this->_targetsTable[i] = reinterpret_cast<const UndefinedAtom*>(p);
|
this->_targetsTable[i] = reinterpret_cast<const UndefinedAtom*>(p);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const uint32_t slIndex = index - _definedAtoms.elementCount
|
const uint32_t slIndex = index - _definedAtoms._elementCount
|
||||||
- _undefinedAtoms.elementCount;
|
- _undefinedAtoms._elementCount;
|
||||||
if ( slIndex < _sharedLibraryAtoms.elementCount ) {
|
if ( slIndex < _sharedLibraryAtoms._elementCount ) {
|
||||||
const uint8_t* p = _sharedLibraryAtoms.arrayStart
|
const uint8_t* p = _sharedLibraryAtoms._arrayStart
|
||||||
+ slIndex * _sharedLibraryAtoms.elementSize;
|
+ slIndex * _sharedLibraryAtoms._elementSize;
|
||||||
this->_targetsTable[i] = reinterpret_cast<const SharedLibraryAtom*>(p);
|
this->_targetsTable[i] = reinterpret_cast<const SharedLibraryAtom*>(p);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const uint32_t abIndex = index - _definedAtoms.elementCount
|
const uint32_t abIndex = index - _definedAtoms._elementCount
|
||||||
- _undefinedAtoms.elementCount
|
- _undefinedAtoms._elementCount
|
||||||
- _sharedLibraryAtoms.elementCount;
|
- _sharedLibraryAtoms._elementCount;
|
||||||
if ( abIndex < _absoluteAtoms.elementCount ) {
|
if ( abIndex < _absoluteAtoms._elementCount ) {
|
||||||
const uint8_t* p = _absoluteAtoms.arrayStart
|
const uint8_t* p = _absoluteAtoms._arrayStart
|
||||||
+ slIndex * _absoluteAtoms.elementSize;
|
+ slIndex * _absoluteAtoms._elementSize;
|
||||||
this->_targetsTable[i] = reinterpret_cast<const AbsoluteAtom*>(p);
|
this->_targetsTable[i] = reinterpret_cast<const AbsoluteAtom*>(p);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -612,21 +594,13 @@ private:
|
||||||
assert((result+size) <= _contentEnd);
|
assert((result+size) <= _contentEnd);
|
||||||
return result;
|
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<const NativeReferenceV1*>(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<const NativeReferenceV1*>(p);
|
||||||
|
}
|
||||||
|
|
||||||
const Atom* target(uint32_t index) const {
|
const Atom* target(uint32_t index) const {
|
||||||
assert(index < _targetsTableCount);
|
assert(index < _targetsTableCount);
|
||||||
return _targetsTable[index];
|
return _targetsTable[index];
|
||||||
|
@ -656,21 +630,52 @@ private:
|
||||||
(_buffer->getBufferStart());
|
(_buffer->getBufferStart());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class AtomArray : public File::atom_collection<T> {
|
||||||
|
public:
|
||||||
|
AtomArray() : _arrayStart(NULL), _arrayEnd(NULL),
|
||||||
|
_elementSize(0), _elementCount(0) { }
|
||||||
|
|
||||||
|
virtual atom_iterator<T> begin() const {
|
||||||
|
return atom_iterator<T>(*this, reinterpret_cast<const void*>(_arrayStart));
|
||||||
|
}
|
||||||
|
virtual atom_iterator<T> end() const{
|
||||||
|
return atom_iterator<T>(*this, reinterpret_cast<const void*>(_arrayEnd));
|
||||||
|
}
|
||||||
|
virtual const T* deref(const void* it) const {
|
||||||
|
return reinterpret_cast<const T*>(it);
|
||||||
|
}
|
||||||
|
virtual void next(const void*& it) const {
|
||||||
|
const uint8_t* p = reinterpret_cast<const uint8_t*>(it);
|
||||||
|
p += _elementSize;
|
||||||
|
it = reinterpret_cast<const void*>(p);
|
||||||
|
}
|
||||||
|
const uint8_t* _arrayStart;
|
||||||
|
const uint8_t* _arrayEnd;
|
||||||
|
uint32_t _elementSize;
|
||||||
|
uint32_t _elementCount;
|
||||||
|
};
|
||||||
|
|
||||||
struct IvarArray {
|
struct IvarArray {
|
||||||
IvarArray() : arrayStart(NULL), arrayEnd(NULL),
|
IvarArray() :
|
||||||
elementSize(0), elementCount(0) { }
|
arrayStart(NULL),
|
||||||
|
arrayEnd(NULL),
|
||||||
|
elementSize(0),
|
||||||
|
elementCount(0) { }
|
||||||
|
|
||||||
const uint8_t* arrayStart;
|
const uint8_t* arrayStart;
|
||||||
const uint8_t* arrayEnd;
|
const uint8_t* arrayEnd;
|
||||||
uint32_t elementSize;
|
uint32_t elementSize;
|
||||||
uint32_t elementCount;
|
uint32_t elementCount;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
llvm::OwningPtr<llvm::MemoryBuffer> _buffer;
|
llvm::OwningPtr<llvm::MemoryBuffer> _buffer;
|
||||||
const NativeFileHeader* _header;
|
const NativeFileHeader* _header;
|
||||||
IvarArray _definedAtoms;
|
AtomArray<DefinedAtom> _definedAtoms;
|
||||||
IvarArray _undefinedAtoms;
|
AtomArray<UndefinedAtom> _undefinedAtoms;
|
||||||
IvarArray _sharedLibraryAtoms;
|
AtomArray<SharedLibraryAtom> _sharedLibraryAtoms;
|
||||||
IvarArray _absoluteAtoms;
|
AtomArray<AbsoluteAtom> _absoluteAtoms;
|
||||||
const uint8_t* _attributes;
|
const uint8_t* _attributes;
|
||||||
uint32_t _attributesMaxOffset;
|
uint32_t _attributesMaxOffset;
|
||||||
IvarArray _references;
|
IvarArray _references;
|
||||||
|
@ -684,14 +689,14 @@ private:
|
||||||
const uint8_t* _contentEnd;
|
const uint8_t* _contentEnd;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
inline const class File& NativeDefinedAtomV1::file() const {
|
inline const class File& NativeDefinedAtomV1::file() const {
|
||||||
return *_file;
|
return *_file;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline uint64_t NativeDefinedAtomV1:: ordinal() const {
|
inline uint64_t NativeDefinedAtomV1:: ordinal() const {
|
||||||
const uint8_t* p = reinterpret_cast<const uint8_t*>(_ivarData);
|
const uint8_t* p = reinterpret_cast<const uint8_t*>(_ivarData);
|
||||||
return p - _file->_definedAtoms.arrayStart;
|
return p - _file->_definedAtoms._arrayStart;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline llvm::StringRef NativeDefinedAtomV1::name() const {
|
inline llvm::StringRef NativeDefinedAtomV1::name() const {
|
||||||
|
@ -715,11 +720,27 @@ inline llvm::StringRef NativeDefinedAtomV1::customSectionName() const {
|
||||||
return _file->string(offset);
|
return _file->string(offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void NativeDefinedAtomV1::forEachReference(ReferenceHandler& hnd) const {
|
DefinedAtom::reference_iterator NativeDefinedAtomV1::referencesBegin() const {
|
||||||
if ( _ivarData->referencesCount == 0 )
|
uintptr_t index = _ivarData->referencesStartIndex;
|
||||||
return;
|
const void* it = reinterpret_cast<const void*>(index);
|
||||||
_file->forEachReference(hnd, _ivarData->referencesStartIndex,
|
return reference_iterator(*this, it);
|
||||||
_ivarData->referencesCount);
|
}
|
||||||
|
|
||||||
|
DefinedAtom::reference_iterator NativeDefinedAtomV1::referencesEnd() const {
|
||||||
|
uintptr_t index = _ivarData->referencesStartIndex+_ivarData->referencesCount;
|
||||||
|
const void* it = reinterpret_cast<const void*>(index);
|
||||||
|
return reference_iterator(*this, it);
|
||||||
|
}
|
||||||
|
|
||||||
|
const Reference* NativeDefinedAtomV1::derefIterator(const void* it) const {
|
||||||
|
uintptr_t index = reinterpret_cast<uintptr_t>(it);
|
||||||
|
return _file->referenceByIndex(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NativeDefinedAtomV1::incrementIterator(const void*& it) const {
|
||||||
|
uintptr_t index = reinterpret_cast<uintptr_t>(it);
|
||||||
|
++index;
|
||||||
|
it = reinterpret_cast<const void*>(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const class File& NativeUndefinedAtomV1::file() const {
|
inline const class File& NativeUndefinedAtomV1::file() const {
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <map>
|
|
||||||
|
|
||||||
#include "llvm/ADT/StringRef.h"
|
#include "llvm/ADT/StringRef.h"
|
||||||
#include "llvm/ADT/ArrayRef.h"
|
#include "llvm/ADT/ArrayRef.h"
|
||||||
|
@ -26,15 +25,36 @@ namespace lld {
|
||||||
///
|
///
|
||||||
/// Class for writing native object files.
|
/// Class for writing native object files.
|
||||||
///
|
///
|
||||||
class NativeWriter : public File::AtomHandler,
|
class NativeWriter {
|
||||||
public DefinedAtom::ReferenceHandler {
|
|
||||||
public:
|
public:
|
||||||
/// construct writer for an lld::File object
|
/// construct writer for an lld::File object
|
||||||
NativeWriter(const lld::File& file) : _file(file) {
|
NativeWriter(const lld::File& file) : _file(file) {
|
||||||
// reserve first byte for unnamed atoms
|
// reserve first byte for unnamed atoms
|
||||||
_stringPool.push_back('\0');
|
_stringPool.push_back('\0');
|
||||||
// visit all atoms
|
// 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
|
// construct file header based on atom information accumulated
|
||||||
makeHeader();
|
makeHeader();
|
||||||
}
|
}
|
||||||
|
@ -105,8 +125,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
// visitor routine called by forEachAtom()
|
void addIVarsForDefinedAtom(const DefinedAtom& atom) {
|
||||||
virtual void doDefinedAtom(const DefinedAtom& atom) {
|
|
||||||
_definedAtomIndex[&atom] = _definedAtomIvars.size();
|
_definedAtomIndex[&atom] = _definedAtomIvars.size();
|
||||||
NativeDefinedAtomIvarsV1 ivar;
|
NativeDefinedAtomIvarsV1 ivar;
|
||||||
unsigned refsCount;
|
unsigned refsCount;
|
||||||
|
@ -119,8 +138,7 @@ private:
|
||||||
_definedAtomIvars.push_back(ivar);
|
_definedAtomIvars.push_back(ivar);
|
||||||
}
|
}
|
||||||
|
|
||||||
// visitor routine called by forEachAtom()
|
void addIVarsForUndefinedAtom(const UndefinedAtom& atom) {
|
||||||
virtual void doUndefinedAtom(const UndefinedAtom& atom) {
|
|
||||||
_undefinedAtomIndex[&atom] = _undefinedAtomIvars.size();
|
_undefinedAtomIndex[&atom] = _undefinedAtomIvars.size();
|
||||||
NativeUndefinedAtomIvarsV1 ivar;
|
NativeUndefinedAtomIvarsV1 ivar;
|
||||||
ivar.nameOffset = getNameOffset(atom);
|
ivar.nameOffset = getNameOffset(atom);
|
||||||
|
@ -128,8 +146,7 @@ private:
|
||||||
_undefinedAtomIvars.push_back(ivar);
|
_undefinedAtomIvars.push_back(ivar);
|
||||||
}
|
}
|
||||||
|
|
||||||
// visitor routine called by forEachAtom()
|
void addIVarsForSharedLibraryAtom(const SharedLibraryAtom& atom) {
|
||||||
virtual void doSharedLibraryAtom(const SharedLibraryAtom& atom) {
|
|
||||||
_sharedLibraryAtomIndex[&atom] = _sharedLibraryAtomIvars.size();
|
_sharedLibraryAtomIndex[&atom] = _sharedLibraryAtomIvars.size();
|
||||||
NativeSharedLibraryAtomIvarsV1 ivar;
|
NativeSharedLibraryAtomIvarsV1 ivar;
|
||||||
ivar.nameOffset = getNameOffset(atom);
|
ivar.nameOffset = getNameOffset(atom);
|
||||||
|
@ -138,8 +155,7 @@ private:
|
||||||
_sharedLibraryAtomIvars.push_back(ivar);
|
_sharedLibraryAtomIvars.push_back(ivar);
|
||||||
}
|
}
|
||||||
|
|
||||||
// visitor routine called by forEachAtom()
|
void addIVarsForAbsoluteAtom(const AbsoluteAtom& atom) {
|
||||||
virtual void doAbsoluteAtom(const AbsoluteAtom& atom) {
|
|
||||||
_absoluteAtomIndex[&atom] = _absoluteAtomIvars.size();
|
_absoluteAtomIndex[&atom] = _absoluteAtomIvars.size();
|
||||||
NativeAbsoluteAtomIvarsV1 ivar;
|
NativeAbsoluteAtomIvarsV1 ivar;
|
||||||
ivar.nameOffset = getNameOffset(atom);
|
ivar.nameOffset = getNameOffset(atom);
|
||||||
|
@ -148,10 +164,6 @@ private:
|
||||||
_absoluteAtomIvars.push_back(ivar);
|
_absoluteAtomIvars.push_back(ivar);
|
||||||
}
|
}
|
||||||
|
|
||||||
// visitor routine called by forEachAtom()
|
|
||||||
virtual void doFile(const File &) {
|
|
||||||
}
|
|
||||||
|
|
||||||
// fill out native file header and chunk directory
|
// fill out native file header and chunk directory
|
||||||
void makeHeader() {
|
void makeHeader() {
|
||||||
const bool hasDefines = !_definedAtomIvars.empty();
|
const bool hasDefines = !_definedAtomIvars.empty();
|
||||||
|
@ -304,6 +316,7 @@ private:
|
||||||
return chunks[i];
|
return chunks[i];
|
||||||
}
|
}
|
||||||
assert(0 && "findChunk() signature not found");
|
assert(0 && "findChunk() signature not found");
|
||||||
|
static NativeChunk x; return x; // suppress warning
|
||||||
}
|
}
|
||||||
|
|
||||||
// append atom name to string pool and return offset
|
// append atom name to string pool and return offset
|
||||||
|
@ -403,23 +416,23 @@ private:
|
||||||
count = 0;
|
count = 0;
|
||||||
size_t startRefSize = _references.size();
|
size_t startRefSize = _references.size();
|
||||||
uint32_t result = startRefSize;
|
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;
|
count = _references.size() - startRefSize;
|
||||||
if ( count == 0 )
|
if ( count == 0 )
|
||||||
return 0;
|
return 0;
|
||||||
else
|
else
|
||||||
return result;
|
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) {
|
uint32_t getTargetIndex(const Atom* target) {
|
||||||
TargetToIndex::const_iterator pos = _targetsTableIndex.find(target);
|
TargetToIndex::const_iterator pos = _targetsTableIndex.find(target);
|
||||||
if ( pos != _targetsTableIndex.end() ) {
|
if ( pos != _targetsTableIndex.end() ) {
|
||||||
|
|
|
@ -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<Reference*>(&ref))->setTarget(newTarget);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
SymbolTable& _symbolTable;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// switch all references to undefined or coalesced away atoms
|
// switch all references to undefined or coalesced away atoms
|
||||||
// to the new defined atom
|
// to the new defined atom
|
||||||
void Resolver::updateReferences() {
|
void Resolver::updateReferences() {
|
||||||
ReferenceUpdater updater(_symbolTable);
|
for (auto ait = _atoms.begin(); ait != _atoms.end(); ++ait) {
|
||||||
for (std::vector<const Atom *>::iterator it = _atoms.begin();
|
if ( const DefinedAtom* defAtom = (*ait)->definedAtom() ) {
|
||||||
it != _atoms.end(); ++it) {
|
for (auto rit=defAtom->referencesBegin(), end=defAtom->referencesEnd();
|
||||||
if ( const DefinedAtom* defAtom = (*it)->definedAtom() ) {
|
rit != end; ++rit) {
|
||||||
defAtom->forEachReference(updater);
|
const Reference* ref = *rit;
|
||||||
|
const Atom* newTarget = _symbolTable.replacement(ref->target());
|
||||||
|
(const_cast<Reference*>(ref))->setTarget(newTarget);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -272,8 +261,11 @@ void Resolver::markLive(const Atom &atom, WhyLiveBackChain *previous) {
|
||||||
thisChain.previous = previous;
|
thisChain.previous = previous;
|
||||||
thisChain.referer = &atom;
|
thisChain.referer = &atom;
|
||||||
if ( const DefinedAtom* defAtom = atom.definedAtom() ) {
|
if ( const DefinedAtom* defAtom = atom.definedAtom() ) {
|
||||||
MarkLiveReferences markRefs(*this, &thisChain);
|
for (auto rit=defAtom->referencesBegin(), end=defAtom->referencesEnd();
|
||||||
defAtom->forEachReference(markRefs);
|
rit != end; ++rit) {
|
||||||
|
const Reference* ref = *rit;
|
||||||
|
this->markLive(*ref->target(), &thisChain);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -382,7 +374,7 @@ void Resolver::linkTimeOptimize() {
|
||||||
// FIX ME
|
// FIX ME
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<const Atom *> &Resolver::resolve() {
|
void Resolver::resolve() {
|
||||||
this->initializeState();
|
this->initializeState();
|
||||||
this->addInitialUndefines();
|
this->addInitialUndefines();
|
||||||
this->buildInitialAtomList();
|
this->buildInitialAtomList();
|
||||||
|
@ -394,7 +386,32 @@ std::vector<const Atom *> &Resolver::resolve() {
|
||||||
this->checkDylibSymbolCollisions();
|
this->checkDylibSymbolCollisions();
|
||||||
this->linkTimeOptimize();
|
this->linkTimeOptimize();
|
||||||
this->tweakAtoms();
|
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<const Atom*>& all) {
|
||||||
|
for(std::vector<const Atom*>::iterator it=all.begin(); it != all.end(); ++it) {
|
||||||
|
this->addAtom(**it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} // namespace lld
|
} // namespace lld
|
||||||
|
|
|
@ -137,6 +137,7 @@ struct ContentTypeMapping {
|
||||||
static const ContentTypeMapping typeMappings[] = {
|
static const ContentTypeMapping typeMappings[] = {
|
||||||
{ "unknown", DefinedAtom::typeUnknown },
|
{ "unknown", DefinedAtom::typeUnknown },
|
||||||
{ "code", DefinedAtom::typeCode },
|
{ "code", DefinedAtom::typeCode },
|
||||||
|
{ "stub", DefinedAtom::typeStub },
|
||||||
{ "resolver", DefinedAtom::typeResolver },
|
{ "resolver", DefinedAtom::typeResolver },
|
||||||
{ "constant", DefinedAtom::typeConstant },
|
{ "constant", DefinedAtom::typeConstant },
|
||||||
{ "c-string", DefinedAtom::typeCString },
|
{ "c-string", DefinedAtom::typeCString },
|
||||||
|
|
|
@ -20,6 +20,8 @@
|
||||||
#include "lld/Core/File.h"
|
#include "lld/Core/File.h"
|
||||||
#include "lld/Core/Reference.h"
|
#include "lld/Core/Reference.h"
|
||||||
|
|
||||||
|
#include "lld/Platform/Platform.h"
|
||||||
|
|
||||||
#include "llvm/ADT/OwningPtr.h"
|
#include "llvm/ADT/OwningPtr.h"
|
||||||
#include "llvm/ADT/StringRef.h"
|
#include "llvm/ADT/StringRef.h"
|
||||||
#include "llvm/ADT/ArrayRef.h"
|
#include "llvm/ADT/ArrayRef.h"
|
||||||
|
@ -297,10 +299,23 @@ public:
|
||||||
: File("path")
|
: File("path")
|
||||||
, _lastRefIndex(0) {}
|
, _lastRefIndex(0) {}
|
||||||
|
|
||||||
virtual bool forEachAtom(File::AtomHandler &) const;
|
virtual const atom_collection<DefinedAtom>& defined() const {
|
||||||
virtual bool justInTimeforEachAtom(llvm::StringRef name,
|
return _definedAtoms;
|
||||||
File::AtomHandler &) const;
|
}
|
||||||
|
virtual const atom_collection<UndefinedAtom>& undefined() const {
|
||||||
|
return _undefinedAtoms;
|
||||||
|
}
|
||||||
|
virtual const atom_collection<SharedLibraryAtom>& sharedLibrary() const {
|
||||||
|
return _sharedLibraryAtoms;
|
||||||
|
}
|
||||||
|
virtual const atom_collection<AbsoluteAtom>& absolute() const {
|
||||||
|
return _absoluteAtoms;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void addAtom(const Atom&) {
|
||||||
|
assert(0 && "cannot add atoms to YAML files");
|
||||||
|
}
|
||||||
|
|
||||||
void bindTargetReferences();
|
void bindTargetReferences();
|
||||||
void addDefinedAtom(YAMLDefinedAtom* atom, const char* refName);
|
void addDefinedAtom(YAMLDefinedAtom* atom, const char* refName);
|
||||||
void addUndefinedAtom(UndefinedAtom* atom);
|
void addUndefinedAtom(UndefinedAtom* atom);
|
||||||
|
@ -314,13 +329,13 @@ public:
|
||||||
Atom* atom;
|
Atom* atom;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<YAMLDefinedAtom*> _definedAtoms;
|
atom_collection_vector<DefinedAtom> _definedAtoms;
|
||||||
std::vector<UndefinedAtom*> _undefinedAtoms;
|
atom_collection_vector<UndefinedAtom> _undefinedAtoms;
|
||||||
std::vector<SharedLibraryAtom*> _sharedLibraryAtoms;
|
atom_collection_vector<SharedLibraryAtom> _sharedLibraryAtoms;
|
||||||
std::vector<AbsoluteAtom*> _absoluteAtoms;
|
atom_collection_vector<AbsoluteAtom> _absoluteAtoms;
|
||||||
std::vector<YAMLReference> _references;
|
std::vector<YAMLReference> _references;
|
||||||
std::vector<NameAtomPair> _nameToAtomMapping;
|
std::vector<NameAtomPair> _nameToAtomMapping;
|
||||||
unsigned int _lastRefIndex;
|
unsigned int _lastRefIndex;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -434,14 +449,35 @@ public:
|
||||||
return _ord;
|
return _ord;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DefinedAtom::reference_iterator referencesBegin() const {
|
||||||
virtual void forEachReference(ReferenceHandler& handler) const {
|
uintptr_t index = _refStartIndex;
|
||||||
for (uint32_t i=_refStartIndex; i < _refEndIndex; ++i) {
|
const void* it = reinterpret_cast<const void*>(index);
|
||||||
handler.doReference(_file._references[i]);
|
return reference_iterator(*this, it);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void bindTargetReferences() {
|
DefinedAtom::reference_iterator referencesEnd() const {
|
||||||
|
uintptr_t index = _refEndIndex;
|
||||||
|
const void* it = reinterpret_cast<const void*>(index);
|
||||||
|
return reference_iterator(*this, it);
|
||||||
|
}
|
||||||
|
|
||||||
|
const Reference* derefIterator(const void* it) const {
|
||||||
|
uintptr_t index = reinterpret_cast<uintptr_t>(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<uintptr_t>(it);
|
||||||
|
++index;
|
||||||
|
it = reinterpret_cast<const void*>(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void bindTargetReferences() const {
|
||||||
for (unsigned int i=_refStartIndex; i < _refEndIndex; ++i) {
|
for (unsigned int i=_refStartIndex; i < _refEndIndex; ++i) {
|
||||||
const char* targetName = _file._references[i]._targetName;
|
const char* targetName = _file._references[i]._targetName;
|
||||||
Atom* targetAtom = _file.findAtom(targetName);
|
Atom* targetAtom = _file.findAtom(targetName);
|
||||||
|
@ -559,40 +595,9 @@ private:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool YAMLFile::forEachAtom(File::AtomHandler &handler) const {
|
|
||||||
handler.doFile(*this);
|
|
||||||
for (std::vector<YAMLDefinedAtom *>::const_iterator it = _definedAtoms.begin();
|
|
||||||
it != _definedAtoms.end(); ++it) {
|
|
||||||
handler.doDefinedAtom(**it);
|
|
||||||
}
|
|
||||||
for (std::vector<UndefinedAtom *>::const_iterator it = _undefinedAtoms.begin();
|
|
||||||
it != _undefinedAtoms.end(); ++it) {
|
|
||||||
handler.doUndefinedAtom(**it);
|
|
||||||
}
|
|
||||||
for (std::vector<SharedLibraryAtom *>::const_iterator
|
|
||||||
it = _sharedLibraryAtoms.begin();
|
|
||||||
it != _sharedLibraryAtoms.end(); ++it) {
|
|
||||||
handler.doSharedLibraryAtom(**it);
|
|
||||||
}
|
|
||||||
for (std::vector<AbsoluteAtom *>::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() {
|
void YAMLFile::bindTargetReferences() {
|
||||||
for (std::vector<YAMLDefinedAtom *>::const_iterator
|
for (defined_iterator it = definedAtomsBegin(); it != definedAtomsEnd(); ++it) {
|
||||||
it = _definedAtoms.begin(); it != _definedAtoms.end(); ++it) {
|
const YAMLDefinedAtom* atom = reinterpret_cast<const YAMLDefinedAtom*>(*it);
|
||||||
YAMLDefinedAtom* atom = *it;
|
|
||||||
atom->bindTargetReferences();
|
atom->bindTargetReferences();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -607,31 +612,31 @@ Atom* YAMLFile::findAtom(const char* name) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void YAMLFile::addDefinedAtom(YAMLDefinedAtom* atom, const char* refName) {
|
void YAMLFile::addDefinedAtom(YAMLDefinedAtom* atom, const char* refName) {
|
||||||
_definedAtoms.push_back(atom);
|
_definedAtoms._atoms.push_back(atom);
|
||||||
assert(refName != NULL);
|
assert(refName != NULL);
|
||||||
_nameToAtomMapping.push_back(NameAtomPair(refName, atom));
|
_nameToAtomMapping.push_back(NameAtomPair(refName, atom));
|
||||||
}
|
}
|
||||||
|
|
||||||
void YAMLFile::addUndefinedAtom(UndefinedAtom* atom) {
|
void YAMLFile::addUndefinedAtom(UndefinedAtom* atom) {
|
||||||
_undefinedAtoms.push_back(atom);
|
_undefinedAtoms._atoms.push_back(atom);
|
||||||
_nameToAtomMapping.push_back(NameAtomPair(atom->name().data(), atom));
|
_nameToAtomMapping.push_back(NameAtomPair(atom->name().data(), atom));
|
||||||
}
|
}
|
||||||
|
|
||||||
void YAMLFile::addSharedLibraryAtom(SharedLibraryAtom* atom) {
|
void YAMLFile::addSharedLibraryAtom(SharedLibraryAtom* atom) {
|
||||||
_sharedLibraryAtoms.push_back(atom);
|
_sharedLibraryAtoms._atoms.push_back(atom);
|
||||||
_nameToAtomMapping.push_back(NameAtomPair(atom->name().data(), atom));
|
_nameToAtomMapping.push_back(NameAtomPair(atom->name().data(), atom));
|
||||||
}
|
}
|
||||||
|
|
||||||
void YAMLFile::addAbsoluteAtom(AbsoluteAtom* atom) {
|
void YAMLFile::addAbsoluteAtom(AbsoluteAtom* atom) {
|
||||||
_absoluteAtoms.push_back(atom);
|
_absoluteAtoms._atoms.push_back(atom);
|
||||||
_nameToAtomMapping.push_back(NameAtomPair(atom->name().data(), atom));
|
_nameToAtomMapping.push_back(NameAtomPair(atom->name().data(), atom));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class YAMLAtomState {
|
class YAMLAtomState {
|
||||||
public:
|
public:
|
||||||
YAMLAtomState();
|
YAMLAtomState(Platform& platform);
|
||||||
|
|
||||||
void setName(const char *n);
|
void setName(const char *n);
|
||||||
void setRefName(const char *n);
|
void setRefName(const char *n);
|
||||||
void setAlign2(const char *n);
|
void setAlign2(const char *n);
|
||||||
|
@ -642,6 +647,7 @@ public:
|
||||||
|
|
||||||
void makeAtom(YAMLFile&);
|
void makeAtom(YAMLFile&);
|
||||||
|
|
||||||
|
Platform& _platform;
|
||||||
const char * _name;
|
const char * _name;
|
||||||
const char * _refName;
|
const char * _refName;
|
||||||
const char * _sectionName;
|
const char * _sectionName;
|
||||||
|
@ -666,8 +672,9 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
YAMLAtomState::YAMLAtomState()
|
YAMLAtomState::YAMLAtomState(Platform& platform)
|
||||||
: _name(NULL)
|
: _platform(platform)
|
||||||
|
, _name(NULL)
|
||||||
, _refName(NULL)
|
, _refName(NULL)
|
||||||
, _sectionName(NULL)
|
, _sectionName(NULL)
|
||||||
, _loadName(NULL)
|
, _loadName(NULL)
|
||||||
|
@ -764,15 +771,7 @@ void YAMLAtomState::setAlign2(const char *s) {
|
||||||
|
|
||||||
|
|
||||||
void YAMLAtomState::setFixupKind(const char *s) {
|
void YAMLAtomState::setFixupKind(const char *s) {
|
||||||
if (strcmp(s, "pcrel32") == 0)
|
_ref._kind = _platform.kindFromString(llvm::StringRef(s));
|
||||||
_ref._kind = 1;
|
|
||||||
else if (strcmp(s, "call32") == 0)
|
|
||||||
_ref._kind = 2;
|
|
||||||
else {
|
|
||||||
int k;
|
|
||||||
llvm::StringRef(s).getAsInteger(10, k);
|
|
||||||
_ref._kind = k;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void YAMLAtomState::setFixupTarget(const char *s) {
|
void YAMLAtomState::setFixupTarget(const char *s) {
|
||||||
|
@ -800,12 +799,13 @@ void YAMLAtomState::addFixup(YAMLFile *f) {
|
||||||
/// parseObjectText - Parse the specified YAML formatted MemoryBuffer
|
/// parseObjectText - Parse the specified YAML formatted MemoryBuffer
|
||||||
/// into lld::File object(s) and append each to the specified vector<File*>.
|
/// into lld::File object(s) and append each to the specified vector<File*>.
|
||||||
llvm::error_code parseObjectText( llvm::MemoryBuffer *mb
|
llvm::error_code parseObjectText( llvm::MemoryBuffer *mb
|
||||||
, std::vector<File *> &result) {
|
, Platform& platform
|
||||||
|
, std::vector<const File *> &result) {
|
||||||
std::vector<const YAML::Entry *> entries;
|
std::vector<const YAML::Entry *> entries;
|
||||||
YAML::parse(mb, entries);
|
YAML::parse(mb, entries);
|
||||||
|
|
||||||
YAMLFile *file = NULL;
|
YAMLFile *file = NULL;
|
||||||
YAMLAtomState atomState;
|
YAMLAtomState atomState(platform);
|
||||||
bool inAtoms = false;
|
bool inAtoms = false;
|
||||||
bool inFixups = false;
|
bool inFixups = false;
|
||||||
int depthForAtoms = -1;
|
int depthForAtoms = -1;
|
||||||
|
@ -985,13 +985,14 @@ llvm::error_code parseObjectText( llvm::MemoryBuffer *mb
|
||||||
// Fill in vector<File*> from path to input text file.
|
// Fill in vector<File*> from path to input text file.
|
||||||
//
|
//
|
||||||
llvm::error_code parseObjectTextFileOrSTDIN(llvm::StringRef path
|
llvm::error_code parseObjectTextFileOrSTDIN(llvm::StringRef path
|
||||||
, std::vector<File*>& result) {
|
, Platform& platform
|
||||||
|
, std::vector<const File*>& result) {
|
||||||
llvm::OwningPtr<llvm::MemoryBuffer> mb;
|
llvm::OwningPtr<llvm::MemoryBuffer> mb;
|
||||||
llvm::error_code ec = llvm::MemoryBuffer::getFileOrSTDIN(path, mb);
|
llvm::error_code ec = llvm::MemoryBuffer::getFileOrSTDIN(path, mb);
|
||||||
if ( ec )
|
if ( ec )
|
||||||
return ec;
|
return ec;
|
||||||
|
|
||||||
return parseObjectText(mb.get(), result);
|
return parseObjectText(mb.get(), platform, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,8 @@
|
||||||
#include "lld/Core/File.h"
|
#include "lld/Core/File.h"
|
||||||
#include "lld/Core/Reference.h"
|
#include "lld/Core/Reference.h"
|
||||||
|
|
||||||
|
#include "lld/Platform/Platform.h"
|
||||||
|
|
||||||
#include "llvm/ADT/OwningPtr.h"
|
#include "llvm/ADT/OwningPtr.h"
|
||||||
#include "llvm/ADT/DenseMap.h"
|
#include "llvm/ADT/DenseMap.h"
|
||||||
#include "llvm/ADT/StringExtras.h"
|
#include "llvm/ADT/StringExtras.h"
|
||||||
|
@ -41,44 +43,50 @@ namespace {
|
||||||
/// In that case referencing the function by name is ambiguous, so a unique
|
/// In that case referencing the function by name is ambiguous, so a unique
|
||||||
/// ref-name is added.
|
/// ref-name is added.
|
||||||
///
|
///
|
||||||
class RefNameBuilder : public File::AtomHandler,
|
class RefNameBuilder {
|
||||||
public DefinedAtom::ReferenceHandler {
|
|
||||||
public:
|
public:
|
||||||
RefNameBuilder() { }
|
RefNameBuilder(const File& file)
|
||||||
|
: _collisionCount(0), _unnamedCounter(0) {
|
||||||
virtual void doReference(const Reference& ref) {
|
// visit all atoms
|
||||||
// create refname for any unnamed reference target
|
for(File::defined_iterator it=file.definedAtomsBegin(),
|
||||||
if ( ref.target()->name().empty() ) {
|
end=file.definedAtomsEnd();
|
||||||
char* buffer;
|
it != end; ++it) {
|
||||||
asprintf(&buffer, "L%03d", _unnamedCounter++);
|
const DefinedAtom* atom = *it;
|
||||||
_refNames[ref.target()] = buffer;
|
// 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) {
|
void buildDuplicateNameMap(const Atom& atom) {
|
||||||
assert(!atom.name().empty());
|
assert(!atom.name().empty());
|
||||||
NameToAtom::iterator pos = _nameMap.find(atom.name());
|
NameToAtom::iterator pos = _nameMap.find(atom.name());
|
||||||
|
@ -131,27 +139,55 @@ private:
|
||||||
///
|
///
|
||||||
/// Helper class for writeObjectText() to write out atoms in yaml format.
|
/// Helper class for writeObjectText() to write out atoms in yaml format.
|
||||||
///
|
///
|
||||||
class AtomWriter : public File::AtomHandler,
|
class AtomWriter {
|
||||||
public DefinedAtom::ReferenceHandler {
|
|
||||||
public:
|
public:
|
||||||
AtomWriter(RefNameBuilder& rnb, llvm::raw_ostream &out)
|
AtomWriter(const File& file, Platform& platform, RefNameBuilder& rnb)
|
||||||
: _out(out), _rnb(rnb), _firstAtom(true) { }
|
: _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 ) {
|
if ( _firstAtom ) {
|
||||||
_out << "atoms:\n";
|
out << "atoms:\n";
|
||||||
_firstAtom = false;
|
_firstAtom = false;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// add blank line between atoms for readability
|
// add blank line between atoms for readability
|
||||||
_out << "\n";
|
out << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hasDash = false;
|
bool hasDash = false;
|
||||||
if ( !atom.name().empty() ) {
|
if ( !atom.name().empty() ) {
|
||||||
_out << " - "
|
out << " - "
|
||||||
<< KeyValues::nameKeyword
|
<< KeyValues::nameKeyword
|
||||||
<< ":"
|
<< ":"
|
||||||
<< spacePadding(KeyValues::nameKeyword)
|
<< spacePadding(KeyValues::nameKeyword)
|
||||||
|
@ -161,7 +197,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( _rnb.hasRefName(&atom) ) {
|
if ( _rnb.hasRefName(&atom) ) {
|
||||||
_out << (hasDash ? " " : " - ")
|
out << (hasDash ? " " : " - ")
|
||||||
<< KeyValues::refNameKeyword
|
<< KeyValues::refNameKeyword
|
||||||
<< ":"
|
<< ":"
|
||||||
<< spacePadding(KeyValues::refNameKeyword)
|
<< spacePadding(KeyValues::refNameKeyword)
|
||||||
|
@ -171,7 +207,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( atom.definition() != KeyValues::definitionDefault ) {
|
if ( atom.definition() != KeyValues::definitionDefault ) {
|
||||||
_out << (hasDash ? " " : " - ")
|
out << (hasDash ? " " : " - ")
|
||||||
<< KeyValues::definitionKeyword
|
<< KeyValues::definitionKeyword
|
||||||
<< ":"
|
<< ":"
|
||||||
<< spacePadding(KeyValues::definitionKeyword)
|
<< spacePadding(KeyValues::definitionKeyword)
|
||||||
|
@ -181,7 +217,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( atom.scope() != KeyValues::scopeDefault ) {
|
if ( atom.scope() != KeyValues::scopeDefault ) {
|
||||||
_out << (hasDash ? " " : " - ")
|
out << (hasDash ? " " : " - ")
|
||||||
<< KeyValues::scopeKeyword
|
<< KeyValues::scopeKeyword
|
||||||
<< ":"
|
<< ":"
|
||||||
<< spacePadding(KeyValues::scopeKeyword)
|
<< spacePadding(KeyValues::scopeKeyword)
|
||||||
|
@ -191,7 +227,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( atom.interposable() != KeyValues::interposableDefault ) {
|
if ( atom.interposable() != KeyValues::interposableDefault ) {
|
||||||
_out << " "
|
out << " "
|
||||||
<< KeyValues::interposableKeyword
|
<< KeyValues::interposableKeyword
|
||||||
<< ":"
|
<< ":"
|
||||||
<< spacePadding(KeyValues::interposableKeyword)
|
<< spacePadding(KeyValues::interposableKeyword)
|
||||||
|
@ -200,7 +236,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( atom.merge() != KeyValues::mergeDefault ) {
|
if ( atom.merge() != KeyValues::mergeDefault ) {
|
||||||
_out << " "
|
out << " "
|
||||||
<< KeyValues::mergeKeyword
|
<< KeyValues::mergeKeyword
|
||||||
<< ":"
|
<< ":"
|
||||||
<< spacePadding(KeyValues::mergeKeyword)
|
<< spacePadding(KeyValues::mergeKeyword)
|
||||||
|
@ -209,7 +245,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( atom.contentType() != KeyValues::contentTypeDefault ) {
|
if ( atom.contentType() != KeyValues::contentTypeDefault ) {
|
||||||
_out << " "
|
out << " "
|
||||||
<< KeyValues::contentTypeKeyword
|
<< KeyValues::contentTypeKeyword
|
||||||
<< ":"
|
<< ":"
|
||||||
<< spacePadding(KeyValues::contentTypeKeyword)
|
<< spacePadding(KeyValues::contentTypeKeyword)
|
||||||
|
@ -218,7 +254,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( atom.deadStrip() != KeyValues::deadStripKindDefault ) {
|
if ( atom.deadStrip() != KeyValues::deadStripKindDefault ) {
|
||||||
_out << " "
|
out << " "
|
||||||
<< KeyValues::deadStripKindKeyword
|
<< KeyValues::deadStripKindKeyword
|
||||||
<< ":"
|
<< ":"
|
||||||
<< spacePadding(KeyValues::deadStripKindKeyword)
|
<< spacePadding(KeyValues::deadStripKindKeyword)
|
||||||
|
@ -227,14 +263,14 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( atom.sectionChoice() != KeyValues::sectionChoiceDefault ) {
|
if ( atom.sectionChoice() != KeyValues::sectionChoiceDefault ) {
|
||||||
_out << " "
|
out << " "
|
||||||
<< KeyValues::sectionChoiceKeyword
|
<< KeyValues::sectionChoiceKeyword
|
||||||
<< ":"
|
<< ":"
|
||||||
<< spacePadding(KeyValues::sectionChoiceKeyword)
|
<< spacePadding(KeyValues::sectionChoiceKeyword)
|
||||||
<< KeyValues::sectionChoice(atom.sectionChoice())
|
<< KeyValues::sectionChoice(atom.sectionChoice())
|
||||||
<< "\n";
|
<< "\n";
|
||||||
assert( ! atom.customSectionName().empty() );
|
assert( ! atom.customSectionName().empty() );
|
||||||
_out << " "
|
out << " "
|
||||||
<< KeyValues::sectionNameKeyword
|
<< KeyValues::sectionNameKeyword
|
||||||
<< ":"
|
<< ":"
|
||||||
<< spacePadding(KeyValues::sectionNameKeyword)
|
<< spacePadding(KeyValues::sectionNameKeyword)
|
||||||
|
@ -243,7 +279,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( atom.isThumb() != KeyValues::isThumbDefault ) {
|
if ( atom.isThumb() != KeyValues::isThumbDefault ) {
|
||||||
_out << " "
|
out << " "
|
||||||
<< KeyValues::isThumbKeyword
|
<< KeyValues::isThumbKeyword
|
||||||
<< ":"
|
<< ":"
|
||||||
<< spacePadding(KeyValues::isThumbKeyword)
|
<< spacePadding(KeyValues::isThumbKeyword)
|
||||||
|
@ -252,7 +288,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( atom.isAlias() != KeyValues::isAliasDefault ) {
|
if ( atom.isAlias() != KeyValues::isAliasDefault ) {
|
||||||
_out << " "
|
out << " "
|
||||||
<< KeyValues::isAliasKeyword
|
<< KeyValues::isAliasKeyword
|
||||||
<< ":"
|
<< ":"
|
||||||
<< spacePadding(KeyValues::isAliasKeyword)
|
<< spacePadding(KeyValues::isAliasKeyword)
|
||||||
|
@ -262,7 +298,7 @@ public:
|
||||||
|
|
||||||
if ( (atom.contentType() != DefinedAtom::typeZeroFill)
|
if ( (atom.contentType() != DefinedAtom::typeZeroFill)
|
||||||
&& (atom.size() != 0) ) {
|
&& (atom.size() != 0) ) {
|
||||||
_out << " "
|
out << " "
|
||||||
<< KeyValues::contentKeyword
|
<< KeyValues::contentKeyword
|
||||||
<< ":"
|
<< ":"
|
||||||
<< spacePadding(KeyValues::contentKeyword)
|
<< spacePadding(KeyValues::contentKeyword)
|
||||||
|
@ -271,77 +307,77 @@ public:
|
||||||
bool needComma = false;
|
bool needComma = false;
|
||||||
for (unsigned int i=0; i < arr.size(); ++i) {
|
for (unsigned int i=0; i < arr.size(); ++i) {
|
||||||
if ( needComma )
|
if ( needComma )
|
||||||
_out << ", ";
|
out << ", ";
|
||||||
_out << hexdigit(arr[i] >> 4);
|
out << hexdigit(arr[i] >> 4);
|
||||||
_out << hexdigit(arr[i] & 0x0F);
|
out << hexdigit(arr[i] & 0x0F);
|
||||||
needComma = true;
|
needComma = true;
|
||||||
}
|
}
|
||||||
_out << " ]\n";
|
out << " ]\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
_wroteFirstFixup = false;
|
bool wroteFirstFixup = false;
|
||||||
atom.forEachReference(*this);
|
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";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
void writeUndefinedAtom(const UndefinedAtom &atom, llvm::raw_ostream& out) {
|
||||||
virtual void doUndefinedAtom(const class UndefinedAtom &atom) {
|
|
||||||
if ( _firstAtom ) {
|
if ( _firstAtom ) {
|
||||||
_out << "atoms:\n";
|
out << "atoms:\n";
|
||||||
_firstAtom = false;
|
_firstAtom = false;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// add blank line between atoms for readability
|
// add blank line between atoms for readability
|
||||||
_out << "\n";
|
out << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
_out << " - "
|
out << " - "
|
||||||
<< KeyValues::nameKeyword
|
<< KeyValues::nameKeyword
|
||||||
<< ":"
|
<< ":"
|
||||||
<< spacePadding(KeyValues::nameKeyword)
|
<< spacePadding(KeyValues::nameKeyword)
|
||||||
<< atom.name()
|
<< atom.name()
|
||||||
<< "\n";
|
<< "\n";
|
||||||
|
|
||||||
_out << " "
|
out << " "
|
||||||
<< KeyValues::definitionKeyword
|
<< KeyValues::definitionKeyword
|
||||||
<< ":"
|
<< ":"
|
||||||
<< spacePadding(KeyValues::definitionKeyword)
|
<< spacePadding(KeyValues::definitionKeyword)
|
||||||
|
@ -349,7 +385,7 @@ public:
|
||||||
<< "\n";
|
<< "\n";
|
||||||
|
|
||||||
if ( atom.canBeNull() != KeyValues::canBeNullDefault ) {
|
if ( atom.canBeNull() != KeyValues::canBeNullDefault ) {
|
||||||
_out << " "
|
out << " "
|
||||||
<< KeyValues::canBeNullKeyword
|
<< KeyValues::canBeNullKeyword
|
||||||
<< ":"
|
<< ":"
|
||||||
<< spacePadding(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 ) {
|
if ( _firstAtom ) {
|
||||||
_out << "atoms:\n";
|
out << "atoms:\n";
|
||||||
_firstAtom = false;
|
_firstAtom = false;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// add blank line between atoms for readability
|
// add blank line between atoms for readability
|
||||||
_out << "\n";
|
out << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
_out << " - "
|
out << " - "
|
||||||
<< KeyValues::nameKeyword
|
<< KeyValues::nameKeyword
|
||||||
<< ":"
|
<< ":"
|
||||||
<< spacePadding(KeyValues::nameKeyword)
|
<< spacePadding(KeyValues::nameKeyword)
|
||||||
<< atom.name()
|
<< atom.name()
|
||||||
<< "\n";
|
<< "\n";
|
||||||
|
|
||||||
_out << " "
|
out << " "
|
||||||
<< KeyValues::definitionKeyword
|
<< KeyValues::definitionKeyword
|
||||||
<< ":"
|
<< ":"
|
||||||
<< spacePadding(KeyValues::definitionKeyword)
|
<< spacePadding(KeyValues::definitionKeyword)
|
||||||
|
@ -383,7 +419,7 @@ public:
|
||||||
<< "\n";
|
<< "\n";
|
||||||
|
|
||||||
if ( !atom.loadName().empty() ) {
|
if ( !atom.loadName().empty() ) {
|
||||||
_out << " "
|
out << " "
|
||||||
<< KeyValues::loadNameKeyword
|
<< KeyValues::loadNameKeyword
|
||||||
<< ":"
|
<< ":"
|
||||||
<< spacePadding(KeyValues::loadNameKeyword)
|
<< spacePadding(KeyValues::loadNameKeyword)
|
||||||
|
@ -392,7 +428,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( atom.canBeNullAtRuntime() ) {
|
if ( atom.canBeNullAtRuntime() ) {
|
||||||
_out << " "
|
out << " "
|
||||||
<< KeyValues::canBeNullKeyword
|
<< KeyValues::canBeNullKeyword
|
||||||
<< ":"
|
<< ":"
|
||||||
<< spacePadding(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 ) {
|
if ( _firstAtom ) {
|
||||||
_out << "atoms:\n";
|
out << "atoms:\n";
|
||||||
_firstAtom = false;
|
_firstAtom = false;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// add blank line between atoms for readability
|
// add blank line between atoms for readability
|
||||||
_out << "\n";
|
out << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
_out << " - "
|
out << " - "
|
||||||
<< KeyValues::nameKeyword
|
<< KeyValues::nameKeyword
|
||||||
<< ":"
|
<< ":"
|
||||||
<< spacePadding(KeyValues::nameKeyword)
|
<< spacePadding(KeyValues::nameKeyword)
|
||||||
<< atom.name()
|
<< atom.name()
|
||||||
<< "\n";
|
<< "\n";
|
||||||
|
|
||||||
_out << " "
|
out << " "
|
||||||
<< KeyValues::definitionKeyword
|
<< KeyValues::definitionKeyword
|
||||||
<< ":"
|
<< ":"
|
||||||
<< spacePadding(KeyValues::definitionKeyword)
|
<< spacePadding(KeyValues::definitionKeyword)
|
||||||
<< KeyValues::definition(atom.definition())
|
<< KeyValues::definition(atom.definition())
|
||||||
<< "\n";
|
<< "\n";
|
||||||
|
|
||||||
_out << " "
|
out << " "
|
||||||
<< KeyValues::valueKeyword
|
<< KeyValues::valueKeyword
|
||||||
<< ":"
|
<< ":"
|
||||||
<< spacePadding(KeyValues::valueKeyword)
|
<< spacePadding(KeyValues::valueKeyword)
|
||||||
<< "0x";
|
<< "0x";
|
||||||
_out.write_hex(atom.value());
|
out.write_hex(atom.value());
|
||||||
_out << "\n";
|
out << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -450,10 +486,10 @@ private:
|
||||||
return 'A' + nibble - 0x0A;
|
return 'A' + nibble - 0x0A;
|
||||||
}
|
}
|
||||||
|
|
||||||
llvm::raw_ostream& _out;
|
const File& _file;
|
||||||
RefNameBuilder _rnb;
|
Platform& _platform;
|
||||||
|
RefNameBuilder& _rnb;
|
||||||
bool _firstAtom;
|
bool _firstAtom;
|
||||||
bool _wroteFirstFixup;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
@ -464,16 +500,14 @@ private:
|
||||||
/// writeObjectText - writes the lld::File object as in YAML
|
/// writeObjectText - writes the lld::File object as in YAML
|
||||||
/// format to the specified stream.
|
/// 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
|
// Figure what ref-name labels are needed
|
||||||
RefNameBuilder rnb;
|
RefNameBuilder rnb(file);
|
||||||
file.forEachAtom(rnb);
|
|
||||||
|
|
||||||
// Write out all atoms
|
// Write out all atoms
|
||||||
AtomWriter h(rnb, out);
|
AtomWriter writer(file, platform, rnb);
|
||||||
out << "---\n";
|
writer.write(out);
|
||||||
file.forEachAtom(h);
|
|
||||||
out << "...\n";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace yaml
|
} // namespace yaml
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
add_lld_library(lldPasses
|
||||||
|
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<const SharedLibraryAtom*, const Atom*> 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<Reference*>(ref))->setTarget(stub);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// add all created stubs to file
|
||||||
|
for (auto it=shlibToStub.begin(), end=shlibToStub.end(); it != end; ++it) {
|
||||||
|
_file.addAtom(*it->second);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -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: ...
|
|
@ -1,5 +1,6 @@
|
||||||
set(LLVM_USED_LIBS
|
set(LLVM_USED_LIBS
|
||||||
lldCore
|
lldCore
|
||||||
|
lldPasses
|
||||||
)
|
)
|
||||||
|
|
||||||
set(LLVM_LINK_COMPONENTS
|
set(LLVM_LINK_COMPONENTS
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include "lld/Core/Atom.h"
|
#include "lld/Core/Atom.h"
|
||||||
#include "lld/Core/DefinedAtom.h"
|
#include "lld/Core/DefinedAtom.h"
|
||||||
#include "lld/Core/UndefinedAtom.h"
|
#include "lld/Core/UndefinedAtom.h"
|
||||||
|
#include "lld/Core/Pass.h"
|
||||||
#include "lld/Core/Resolver.h"
|
#include "lld/Core/Resolver.h"
|
||||||
#include "lld/Core/YamlReader.h"
|
#include "lld/Core/YamlReader.h"
|
||||||
#include "lld/Core/YamlWriter.h"
|
#include "lld/Core/YamlWriter.h"
|
||||||
|
@ -22,6 +23,7 @@
|
||||||
#include "llvm/ADT/StringRef.h"
|
#include "llvm/ADT/StringRef.h"
|
||||||
#include "llvm/ADT/SmallString.h"
|
#include "llvm/ADT/SmallString.h"
|
||||||
#include "llvm/ADT/Twine.h"
|
#include "llvm/ADT/Twine.h"
|
||||||
|
#include "llvm/Support/CommandLine.h"
|
||||||
#include "llvm/Support/DataTypes.h"
|
#include "llvm/Support/DataTypes.h"
|
||||||
#include "llvm/Support/ManagedStatic.h"
|
#include "llvm/Support/ManagedStatic.h"
|
||||||
#include "llvm/Support/MemoryBuffer.h"
|
#include "llvm/Support/MemoryBuffer.h"
|
||||||
|
@ -49,15 +51,110 @@ static bool error(llvm::error_code ec) {
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
class LdCore : public InputFiles, public Platform {
|
|
||||||
public:
|
|
||||||
LdCore(std::vector<File *> &f) : _files(f) { }
|
|
||||||
|
|
||||||
// InputFiles interface
|
|
||||||
virtual void forEachInitialAtom(File::AtomHandler &) const;
|
//
|
||||||
virtual bool searchLibraries(llvm::StringRef name, bool searchDylibs,
|
// Simple atoms created by the stubs pass.
|
||||||
bool searchArchives, bool dataSymbolOnly,
|
//
|
||||||
File::AtomHandler &) const;
|
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<uint8_t> rawContent() const {
|
||||||
|
return llvm::ArrayRef<uint8_t>();
|
||||||
|
}
|
||||||
|
|
||||||
|
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() { }
|
virtual void initialize() { }
|
||||||
|
|
||||||
|
@ -155,97 +252,163 @@ public:
|
||||||
// last chance for platform to tweak atoms
|
// last chance for platform to tweak atoms
|
||||||
virtual void postResolveTweaks(std::vector<const Atom *> &all) {}
|
virtual void postResolveTweaks(std::vector<const Atom *> &all) {}
|
||||||
|
|
||||||
private:
|
virtual bool outputUsesStubs() { return true; };
|
||||||
std::vector<File *> &_files;
|
|
||||||
|
|
||||||
|
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<File *>::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,
|
// Table of fixup kinds in YAML documents used for testing
|
||||||
File::AtomHandler &) const {
|
//
|
||||||
return false;
|
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:
|
public:
|
||||||
MergedFile(std::vector<const Atom *> &a)
|
TestingInputFiles(std::vector<const File*>& f) : _files(f) { }
|
||||||
: File("path"), _atoms(a) { }
|
|
||||||
|
|
||||||
virtual bool forEachAtom(File::AtomHandler &handler) const {
|
// InputFiles interface
|
||||||
handler.doFile(*this);
|
virtual void forEachInitialAtom(InputFiles::Handler& handler) const {
|
||||||
// visit defined atoms
|
for (std::vector<const File *>::iterator fit = _files.begin();
|
||||||
for (std::vector<const Atom *>::iterator it = _atoms.begin();
|
fit != _files.end(); ++fit) {
|
||||||
it != _atoms.end(); ++it) {
|
const File* file = *fit;
|
||||||
const DefinedAtom* atom = (*it)->definedAtom();
|
handler.doFile(*file);
|
||||||
if ( atom )
|
for(auto it=file->definedAtomsBegin(),end=file->definedAtomsEnd();
|
||||||
handler.doDefinedAtom(*atom);
|
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<const Atom *>::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<const Atom *>::iterator it = _atoms.begin();
|
|
||||||
it != _atoms.end(); ++it) {
|
|
||||||
const SharedLibraryAtom* atom = (*it)->sharedLibraryAtom();
|
|
||||||
if ( atom )
|
|
||||||
handler.doSharedLibraryAtom(*atom);
|
|
||||||
}
|
|
||||||
// visit absolute atoms
|
|
||||||
for (std::vector<const Atom *>::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,
|
virtual bool searchLibraries(llvm::StringRef name, bool searchDylibs,
|
||||||
File::AtomHandler &) const {
|
bool searchArchives, bool dataSymbolOnly,
|
||||||
|
InputFiles::Handler &) const {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<const Atom *> &_atoms;
|
std::vector<const File*>& _files;
|
||||||
};
|
};
|
||||||
} //anonymous namespace
|
}
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, const char *argv[]) {
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
llvm::cl::opt<std::string>
|
||||||
|
gInputFilePath(llvm::cl::Positional,
|
||||||
|
llvm::cl::desc("<input file>"),
|
||||||
|
llvm::cl::init("-"));
|
||||||
|
|
||||||
|
llvm::cl::opt<std::string>
|
||||||
|
gOutputFilePath("o",
|
||||||
|
llvm::cl::desc("Specify output filename"),
|
||||||
|
llvm::cl::value_desc("filename"));
|
||||||
|
|
||||||
|
llvm::cl::opt<bool>
|
||||||
|
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.
|
// Print a stack trace if we signal out.
|
||||||
llvm::sys::PrintStackTraceOnErrorSignal();
|
llvm::sys::PrintStackTraceOnErrorSignal();
|
||||||
llvm::PrettyStackTraceProgram X(argc, argv);
|
llvm::PrettyStackTraceProgram X(argc, argv);
|
||||||
llvm::llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
|
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)
|
// read input YAML doc into object file(s)
|
||||||
std::vector<File *> files;
|
std::vector<const File *> files;
|
||||||
if (error(yaml::parseObjectTextFileOrSTDIN(llvm::StringRef(argv[1]), files)))
|
if (error(yaml::parseObjectTextFileOrSTDIN(gInputFilePath,
|
||||||
|
testingPlatform, files))) {
|
||||||
return 1;
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// create object to mange input files
|
||||||
|
TestingInputFiles inputFiles(files);
|
||||||
|
|
||||||
// merge all atom graphs
|
// merge all atom graphs
|
||||||
LdCore core(files);
|
Resolver resolver(testingPlatform, inputFiles);
|
||||||
Resolver resolver(core, core);
|
resolver.resolve();
|
||||||
std::vector<const Atom *> &mergedAtoms = resolver.resolve();
|
|
||||||
MergedFile outFile(mergedAtoms);
|
|
||||||
|
|
||||||
|
// run passes
|
||||||
|
if ( gDoStubsPass ) {
|
||||||
|
StubsPass addStubs(resolver.resultFile(), testingPlatform);
|
||||||
|
addStubs.perform();
|
||||||
|
}
|
||||||
|
|
||||||
// write new atom graph out as YAML doc
|
// write new atom graph out as YAML doc
|
||||||
std::string errorInfo;
|
std::string errorInfo;
|
||||||
llvm::raw_fd_ostream out("-", errorInfo);
|
const char* outPath = gOutputFilePath.empty() ? "-" : gOutputFilePath.c_str();
|
||||||
// yaml::writeObjectText(outFile, out);
|
llvm::raw_fd_ostream out(outPath, errorInfo);
|
||||||
|
// yaml::writeObjectText(resolver.resultFile(), out);
|
||||||
|
|
||||||
// make unique temp .o file to put generated object file
|
// make unique temp .o file to put generated object file
|
||||||
int fd;
|
int fd;
|
||||||
|
@ -254,7 +417,7 @@ int main(int argc, const char *argv[]) {
|
||||||
llvm::raw_fd_ostream binaryOut(fd, /*shouldClose=*/true);
|
llvm::raw_fd_ostream binaryOut(fd, /*shouldClose=*/true);
|
||||||
|
|
||||||
// write native file
|
// write native file
|
||||||
writeNativeObjectFile(outFile, binaryOut);
|
writeNativeObjectFile(resolver.resultFile(), binaryOut);
|
||||||
binaryOut.close(); // manually close so that file can be read next
|
binaryOut.close(); // manually close so that file can be read next
|
||||||
|
|
||||||
// out << "native file: " << tempPath.str() << "\n";
|
// out << "native file: " << tempPath.str() << "\n";
|
||||||
|
@ -265,7 +428,7 @@ int main(int argc, const char *argv[]) {
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
// write new atom graph out as YAML doc
|
// write new atom graph out as YAML doc
|
||||||
yaml::writeObjectText(*natFile, out);
|
yaml::writeObjectText(*natFile, testingPlatform, out);
|
||||||
|
|
||||||
// delete temp .o file
|
// delete temp .o file
|
||||||
bool existed;
|
bool existed;
|
||||||
|
|
Loading…
Reference in New Issue