diff options
author | Stephen Hines <srhines@google.com> | 2013-03-04 19:51:03 -0800 |
---|---|---|
committer | Stephen Hines <srhines@google.com> | 2013-03-04 20:01:30 -0800 |
commit | 6f75755c9204b1d8817ae5a65a2f7e5af0ec3f70 (patch) | |
tree | 35a64dc0a0ad870f64fae2c88f4357d88270def8 | |
parent | 86036a3bd999904d071826b2f0a84023e28aeebc (diff) | |
download | mclinker-tools_r22.2.tar.gz |
Update mclinker to 176d79dc69b439b23ce7101ef8c3250057119664.android-4.3_r3.1android-4.3_r3android-4.3_r2.3android-4.3_r2.2android-4.3_r2.1android-4.3_r2android-4.3_r1.1android-4.3_r1android-4.3_r0.9.1android-4.3_r0.9android-4.3.1_r1tools_r22.2jb-mr2.0.0-releasejb-mr2.0-releasejb-mr2-releasejb-mr2-dev
Change-Id: Ibae073aefc7838fce46875a6bf6ce7b7e18eced8
Date: Mon Mar 4 22:29:06 2013 +0100
168 files changed, 8854 insertions, 4454 deletions
diff --git a/include/mcld/ADT/BinTree.h b/include/mcld/ADT/BinTree.h index f015ac8..76de607 100644 --- a/include/mcld/ADT/BinTree.h +++ b/include/mcld/ADT/BinTree.h @@ -12,8 +12,9 @@ #include <gtest.h> #endif -#include "mcld/ADT/Uncopyable.h" -#include "mcld/ADT/TreeAllocator.h" +#include <mcld/ADT/Uncopyable.h> +#include <mcld/ADT/TreeBase.h> +#include <mcld/ADT/TreeAllocator.h> #include <cstddef> #include <iterator> @@ -21,8 +22,7 @@ #include <queue> #include <stack> -namespace mcld -{ +namespace mcld { template<class DataType> class BinaryTree; diff --git a/include/mcld/ADT/SizeTraits.h b/include/mcld/ADT/SizeTraits.h index c8822cf..dbd5d7b 100644 --- a/include/mcld/ADT/SizeTraits.h +++ b/include/mcld/ADT/SizeTraits.h @@ -13,6 +13,7 @@ #endif #include <llvm/Support/DataTypes.h> +#include <llvm/Support/ELF.h> namespace mcld { @@ -40,6 +41,50 @@ public: typedef int64_t SWord; }; +// FIXME: move this to mcld internal ELF header file? +template<size_t SIZE> +class ELFSizeTraits; + +template<> +class ELFSizeTraits<32> +{ +public: + typedef llvm::ELF::Elf32_Addr Addr; // Program address + typedef llvm::ELF::Elf32_Off Off; // File offset + typedef llvm::ELF::Elf32_Half Half; + typedef llvm::ELF::Elf32_Word Word; + typedef llvm::ELF::Elf32_Sword Sword; + + typedef llvm::ELF::Elf32_Ehdr Ehdr; + typedef llvm::ELF::Elf32_Shdr Shdr; + typedef llvm::ELF::Elf32_Sym Sym; + typedef llvm::ELF::Elf32_Rel Rel; + typedef llvm::ELF::Elf32_Rela Rela; + typedef llvm::ELF::Elf32_Phdr Phdr; + typedef llvm::ELF::Elf32_Dyn Dyn; +}; + +template<> +class ELFSizeTraits<64> +{ +public: + typedef llvm::ELF::Elf64_Addr Addr; + typedef llvm::ELF::Elf64_Off Off; + typedef llvm::ELF::Elf64_Half Half; + typedef llvm::ELF::Elf64_Word Word; + typedef llvm::ELF::Elf64_Sword Sword; + typedef llvm::ELF::Elf64_Xword Xword; + typedef llvm::ELF::Elf64_Sxword Sxword; + + typedef llvm::ELF::Elf64_Ehdr Ehdr; + typedef llvm::ELF::Elf64_Shdr Shdr; + typedef llvm::ELF::Elf64_Sym Sym; + typedef llvm::ELF::Elf64_Rel Rel; + typedef llvm::ELF::Elf64_Rela Rela; + typedef llvm::ELF::Elf64_Phdr Phdr; + typedef llvm::ELF::Elf64_Dyn Dyn; +}; + /// alignAddress - helper function to align an address with given alignment /// constraint /// diff --git a/include/mcld/ADT/TreeAllocator.h b/include/mcld/ADT/TreeAllocator.h index 899896c..10de761 100644 --- a/include/mcld/ADT/TreeAllocator.h +++ b/include/mcld/ADT/TreeAllocator.h @@ -13,10 +13,8 @@ #endif #include <set> #include "mcld/Support/GCFactory.h" -#include "mcld/ADT/TreeBase.h" -namespace mcld -{ +namespace mcld { /** \class NodeFactory * \brief NodeFactory manages the creation and destruction of mcld::Node. diff --git a/include/mcld/ADT/TreeBase.h b/include/mcld/ADT/TreeBase.h index 6fb3bf6..13eb474 100644 --- a/include/mcld/ADT/TreeBase.h +++ b/include/mcld/ADT/TreeBase.h @@ -11,6 +11,8 @@ #include "mcld/ADT/TypeTraits.h" #include <cstddef> +#include <cassert> +#include <iterator> namespace mcld { diff --git a/include/mcld/Config/Config.h.in b/include/mcld/Config/Config.h.in index 7b55240..1967ca1 100644 --- a/include/mcld/Config/Config.h.in +++ b/include/mcld/Config/Config.h.in @@ -1,3 +1,6 @@ +/* include/mcld/Config/Config.h.in. Generated from configure.ac by autoheader. */ + + //===- Config.h.in --------------------------------------------------------===// // // The MCLinker Project @@ -9,8 +12,84 @@ #ifndef MCLD_CONFIG_H #define MCLD_CONFIG_H -#define @MCLD_ON_PLATFORM@ 1 -#define MCLD_VERSION "@MCLD_VERSION@" + +/* Define to 1 if you have the <fcntl.h> header file. */ +#undef HAVE_FCNTL_H + +/* Define to 1 if you have the <inttypes.h> header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the <memory.h> header file. */ +#undef HAVE_MEMORY_H + +/* Define if you have POSIX threads libraries and header files. */ +#undef HAVE_PTHREAD + +/* Define to 1 if you have the <stdint.h> header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the <stdlib.h> header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the <strings.h> header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the <string.h> header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the <sys/stat.h> header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the <sys/types.h> header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the <unistd.h> header file. */ +#undef HAVE_UNISTD_H + +/* Define if this is Unixish platform */ +#undef MCLD_ON_UNIX + +/* Define if this is Win32ish platform */ +#undef MCLD_ON_WIN32 + +/* MCLINKER version */ +#undef MCLD_VERSION + +/* Name of package */ +#undef PACKAGE + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the home page for this package. */ +#undef PACKAGE_URL + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* Define to necessary symbol if this constant uses a non-standard name on + your system. */ +#undef PTHREAD_CREATE_JOINABLE + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Define for standalone Android linker */ +#undef TARGET_BUILD + +/* Version number of package */ +#undef VERSION + + #define MCLD_REGION_CHUNK_SIZE 32 #define MCLD_NUM_OF_INPUTS 32 #define MCLD_SECTIONS_PER_INPUT 16 diff --git a/include/mcld/Fragment/FGNode.h b/include/mcld/Fragment/FGNode.h new file mode 100644 index 0000000..0afee0e --- /dev/null +++ b/include/mcld/Fragment/FGNode.h @@ -0,0 +1,91 @@ +//===- FGNode.h -----------------------------------------------------------===// +// +// The MCLinker Project +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#ifndef MCLD_FGNODE_H +#define MCLD_FGNODE_H +#ifdef ENABLE_UNITTEST +#include <gtest.h> +#endif + +#include <llvm/Support/DataTypes.h> + +#include <vector> + +namespace mcld +{ + +class Relocation; +class ResolveInfo; +class Fragment; + +/** \class FGNode + * \brief FGNode is a node for FragmentGraph + */ +class FGNode +{ +public: + typedef ResolveInfo* Slot; + typedef Relocation* Signal; + + typedef std::vector<Fragment*> FragmentListType; + typedef FragmentListType::iterator frag_iterator; + typedef FragmentListType::const_iterator const_frag_iterator; + + typedef std::vector<Slot> SlotListType; + typedef SlotListType::iterator slot_iterator; + typedef SlotListType::const_iterator const_slot_iterator; + + typedef std::vector<Signal> SignalListType; + typedef SignalListType::iterator signal_iterator; + typedef SignalListType::const_iterator const_signal_iterator; + +public: + FGNode(); + explicit FGNode(uint32_t pIndex); + + void addFragment(Fragment* pFrag); + void addSignal(Signal pSignal); + void addSlot(Slot pSlot); + + /// ----- observers ----- /// + uint32_t getIndex() const + { return m_Index; } + + slot_iterator slot_begin () { return m_Slots.begin(); } + const_slot_iterator slot_begin () const { return m_Slots.begin(); } + slot_iterator slot_end () { return m_Slots.end(); } + const_slot_iterator slot_end () const { return m_Slots.end(); } + + signal_iterator signal_begin () { return m_Signals.begin(); } + const_signal_iterator signal_begin () const { return m_Signals.begin(); } + signal_iterator signal_end () { return m_Signals.end(); } + const_signal_iterator signal_end () const { return m_Signals.end(); } + + frag_iterator frag_begin () { return m_Fragments.begin(); } + const_frag_iterator frag_begin () const { return m_Fragments.begin(); } + frag_iterator frag_end () { return m_Fragments.end(); } + const_frag_iterator frag_end () const { return m_Fragments.end(); } + +private: + FragmentListType m_Fragments; + + /// m_Signals - a list of relocations describes the possible fan-out of this + /// node + SignalListType m_Signals; + + /// m_Slots - a list of symbols describes the possible fan-in of this node + SlotListType m_Slots; + + /// m_Index - the index in the reachability matrix + uint32_t m_Index; +}; + +} // namespace of mcld + +#endif + diff --git a/include/mcld/Fragment/FragmentGraph.h b/include/mcld/Fragment/FragmentGraph.h new file mode 100644 index 0000000..96d438f --- /dev/null +++ b/include/mcld/Fragment/FragmentGraph.h @@ -0,0 +1,177 @@ +//===- FragmentGraph.h ----------------------------------------------------===// +// +// The MCLinker Project +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#ifndef MCLD_FRAGMENTGRAPH_H +#define MCLD_FRAGMENTGRAPH_H +#ifdef ENABLE_UNITTEST +#include <gtest.h> +#endif + +#include <vector> + +#include <mcld/ADT/HashTable.h> +#include <mcld/ADT/HashEntry.h> +#include <mcld/Config/Config.h> +#include <mcld/Fragment/FGNode.h> +#include <mcld/Fragment/FGEdge.h> +#include <mcld/Support/GCFactory.h> + +#include <llvm/Support/DataTypes.h> + +namespace mcld +{ +class Module; +class ResolveInfo; +class Relocation; +class LinkerConfig; + +/** \class FragmentGraph + * \brief FragmentGraph describes the references between fragments. + */ +class FragmentGraph +{ +public: + typedef FGNode::Slot Slot; + typedef FGNode::Signal Signal; + + typedef GCFactory<FGNode, MCLD_SECTIONS_PER_INPUT> NodeFactoryType; + typedef NodeFactoryType::iterator node_iterator; + typedef NodeFactoryType::const_iterator const_node_iterator; + + typedef std::vector<FGEdge> EdgeListType; + typedef EdgeListType::iterator edge_iterator; + typedef EdgeListType::const_iterator const_edge_iterator; + + +public: + FragmentGraph(); + ~FragmentGraph(); + + /// construct - construct the whole graph from input Fragments, relocations + /// and symbols + bool construct(const LinkerConfig& pConfig, Module& pModule); + + /// connect - connect two nodes + bool connect(Signal pSignal, Slot pSlot); + bool connect(FGNode& pFrom, Slot pSlot); + + /// getEdges - given a node, get the list of edges which are the fan-out of + /// this node + /// @param pEdges - the edge list which contains the found edges + /// @return false - the given node + bool getEdges(FGNode& pNode, EdgeListType& pEdges); + + /// ----- observers -----/// + /// getNode - given a fragment, finde the node which the fragment is belong to + FGNode* getNode(const Fragment& pFrag); + const FGNode* getNode(const Fragment& pFrag) const; + + FGNode* getNode(const ResolveInfo& pSym); + const FGNode* getNode(const ResolveInfo& pSym) const; + +private: + typedef std::vector<Relocation*> RelocationListType; + typedef RelocationListType::iterator reloc_iterator; + typedef RelocationListType::const_iterator const_reloc_iterator; + + struct PtrCompare + { + bool operator()(const void* X, const void* Y) const + { return (X==Y); } + }; + + struct PtrHash + { + size_t operator()(const void* pKey) const + { + return (unsigned((uintptr_t)pKey) >> 4) ^ + (unsigned((uintptr_t)pKey) >> 9); + } + }; + + /// HashTable for Fragment* to Node* + typedef HashEntry<const Fragment*, FGNode*, PtrCompare> FragHashEntryType; + typedef HashTable<FragHashEntryType, + PtrHash, + EntryFactory<FragHashEntryType> > FragHashTableType; + + /// HashTable for ResolveInfo* to Node* + typedef HashEntry<const ResolveInfo*, FGNode*, PtrCompare> SymHashEntryType; + typedef HashTable<SymHashEntryType, + PtrHash, + EntryFactory<SymHashEntryType> > SymHashTableType; + + /** \class ReachMatrix + * \brief ReachMatrix is the reachability matrix which describes the relation + * of Nodes in FragmentGraph + */ + class ReachMatrix + { + public: + typedef std::vector<uint32_t> MatrixDataType; + + public: + ReachMatrix(size_t pSize); + ~ReachMatrix(); + uint32_t& at(uint32_t pX, uint32_t pY); + uint32_t at(uint32_t pX, uint32_t pY) const; + + uint32_t getN() const + { return m_N; } + + void print(); + + private: + // m_Data - the contents of the matrix. Here we use a one dimensional array + // to represent the two dimensional matrix + MatrixDataType m_Data; + + // m_N - this is an m_N x m_N matrix + size_t m_N; + }; + +private: + FGNode* producePseudoNode(); + FGNode* produceRegularNode(); + void destroyPseudoNode(); + void destroyRegularNode(); + + void initMatrix(); + + bool createRegularNodes(Module& pModule); + bool setNodeSlots(Module& pModule); + bool createPseudoNodes(Module& pModule); + + bool createRegularEdges(Module& pModule); + bool createPseudoEdges(Module& pModule); + +private: + NodeFactoryType* m_pPseudoNodeFactory; + NodeFactoryType* m_pRegularNodeFactory; + + /// m_pFragNodeMap - HashTable to map the fragment to the node it belongs to + FragHashTableType* m_pFragNodeMap; + + /// m_pSymNodeMap - HashTable to map the ResolveInfo to the node. The node is + /// the pseudo node which the contains it's fan-out is to the ResolveInfo + SymHashTableType* m_pSymNodeMap; + + ReachMatrix* m_pMatrix; + + /// m_NumOfPNodes - number of pseudo nodes + size_t m_NumOfPNodes; + /// m_NumOfRNodes - number of regular nodes + size_t m_NumOfRNodes; + /// m_NumOfEdges - number of edges + size_t m_NumOfEdges; +}; + +} // namespace of mcld + +#endif + diff --git a/include/mcld/Fragment/FragmentLinker.h b/include/mcld/Fragment/FragmentLinker.h index 17e80bd..45ef85d 100644 --- a/include/mcld/Fragment/FragmentLinker.h +++ b/include/mcld/Fragment/FragmentLinker.h @@ -30,14 +30,7 @@ namespace mcld { class Module; class TargetLDBackend; class LinkerConfig; -class LDSection; -class LDSectionFactory; -class SectionData; -class Output; -class EhFrame; -class EhFrameHdr; class MemoryArea; -class RelocData; /** \class FragmentLinker * \brief FragmentLinker provides a pass to link object files. @@ -45,56 +38,12 @@ class RelocData; class FragmentLinker { public: - enum DefinePolicy - { - Force, - AsRefered - }; - - enum ResolvePolicy - { - Unresolve, - Resolve - }; - -public: FragmentLinker(const LinkerConfig& pConfig, Module& pModule, TargetLDBackend& pBackend); ~FragmentLinker(); - // ----- about symbols ----- // - /// defineSymbol - add a symbol - /// defineSymbol define a output symbol - /// - /// @tparam POLICY idicate how to define the symbol. - /// - Force - /// - Define the symbol forcefully. If the symbol has existed, override - /// it. Otherwise, define it. - /// - AsRefered - /// - If the symbol has existed, override it. Otherwise, return NULL - /// immediately. - /// - /// @tparam RESOLVE indicate whether to resolve the symbol or not. - /// - Unresolve - /// - Do not resolve the symbol, and override the symbol immediately. - /// - Resolve - /// - Resolve the defined symbol. - /// - /// @return If the output symbol has existed, return it. Otherwise, create - /// a new symbol and return the new one. - template<DefinePolicy POLICY, ResolvePolicy RESOLVE> - LDSymbol* defineSymbol(const llvm::StringRef& pName, - bool pIsDyn, - ResolveInfo::Type pType, - ResolveInfo::Desc pDesc, - ResolveInfo::Binding pBinding, - ResolveInfo::SizeType pSize, - LDSymbol::ValueType pValue, - FragmentRef* pFragmentRef, - ResolveInfo::Visibility pVisibility = ResolveInfo::Default); - bool finalizeSymbols(); /// applyRelocations - apply all relocation enties. @@ -104,67 +53,7 @@ public: /// data to output file. void syncRelocationResult(MemoryArea& pOutput); - // ----- capacity ----- // - const LinkerConfig& getLDInfo() const { return m_Config; } - - // ----- output attribute ----- // - /// isOutputPIC - return whether the output is position-independent - bool isOutputPIC() const; - - /// isStaticLink - return whether we're doing static link - bool isStaticLink() const; - private: - LDSymbol* defineSymbolForcefully(const llvm::StringRef& pName, - bool pIsDyn, - ResolveInfo::Type pType, - ResolveInfo::Desc pDesc, - ResolveInfo::Binding pBinding, - ResolveInfo::SizeType pSize, - LDSymbol::ValueType pValue, - FragmentRef* pFragmentRef, - ResolveInfo::Visibility pVisibility); - - LDSymbol* defineAndResolveSymbolForcefully(const llvm::StringRef& pName, - bool pIsDyn, - ResolveInfo::Type pType, - ResolveInfo::Desc pDesc, - ResolveInfo::Binding pBinding, - ResolveInfo::SizeType pSize, - LDSymbol::ValueType pValue, - FragmentRef* pFragmentRef, - ResolveInfo::Visibility pVisibility); - - LDSymbol* defineSymbolAsRefered(const llvm::StringRef& pName, - bool pIsDyn, - ResolveInfo::Type pType, - ResolveInfo::Desc pDesc, - ResolveInfo::Binding pBinding, - ResolveInfo::SizeType pSize, - LDSymbol::ValueType pValue, - FragmentRef* pFragmentRef, - ResolveInfo::Visibility pVisibility); - - LDSymbol* defineAndResolveSymbolAsRefered(const llvm::StringRef& pName, - bool pIsDyn, - ResolveInfo::Type pType, - ResolveInfo::Desc pDesc, - ResolveInfo::Binding pBinding, - ResolveInfo::SizeType pSize, - LDSymbol::ValueType pValue, - FragmentRef* pFragmentRef, - ResolveInfo::Visibility pVisibility); - - bool shouldForceLocal(const ResolveInfo& pInfo) const; - - /// checkIsOutputPIC - return whether the output is position-independent, - /// called by isOutputPIC() - bool checkIsOutputPIC() const; - - /// checkIsStaticLink - return whether we're doing static link, called by - /// isStaticLink() - bool checkIsStaticLink() const; - /// normalSyncRelocationResult - sync relocation result when producing shared /// objects or executables void normalSyncRelocationResult(MemoryArea& pOutput); @@ -183,8 +72,6 @@ private: TargetLDBackend& m_Backend; }; -#include "FragmentLinker.tcc" - } // namespace of mcld #endif diff --git a/include/mcld/Fragment/FragmentLinker.tcc b/include/mcld/Fragment/FragmentLinker.tcc deleted file mode 100644 index cc3fad6..0000000 --- a/include/mcld/Fragment/FragmentLinker.tcc +++ /dev/null @@ -1,68 +0,0 @@ -//===- FragmentLinker.tcc --------------------------------------------------===// -// -// The MCLinker Project -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// defineSymbol - define a new symbol -template<FragmentLinker::DefinePolicy POLICY, - FragmentLinker::ResolvePolicy RESOLVE> -LDSymbol* FragmentLinker::defineSymbol(const llvm::StringRef& pName, - bool pIsDyn, - ResolveInfo::Type pType, - ResolveInfo::Desc pDesc, - ResolveInfo::Binding pBinding, - ResolveInfo::SizeType pSize, - LDSymbol::ValueType pValue, - FragmentRef* pFragmentRef, - ResolveInfo::Visibility pVisibility) -{ - // These if/return should be optimized by compiler. - // This function is defined for clarity. - if (FragmentLinker::Force == POLICY && FragmentLinker::Unresolve == RESOLVE) - return defineSymbolForcefully(pName, - pIsDyn, - pType, - pDesc, - pBinding, - pSize, - pValue, - pFragmentRef, - pVisibility); - - if (FragmentLinker::AsRefered == POLICY && FragmentLinker::Unresolve == RESOLVE) - return defineSymbolAsRefered(pName, - pIsDyn, - pType, - pDesc, - pBinding, - pSize, - pValue, - pFragmentRef, - pVisibility); - - if (FragmentLinker::Force == POLICY && FragmentLinker::Resolve == RESOLVE) - return defineAndResolveSymbolForcefully(pName, - pIsDyn, - pType, - pDesc, - pBinding, - pSize, - pValue, - pFragmentRef, - pVisibility); - - if (FragmentLinker::AsRefered == POLICY && FragmentLinker::Resolve == RESOLVE) - return defineAndResolveSymbolAsRefered(pName, - pIsDyn, - pType, - pDesc, - pBinding, - pSize, - pValue, - pFragmentRef, - pVisibility); -} - diff --git a/include/mcld/Fragment/Relocation.h b/include/mcld/Fragment/Relocation.h index 37b32f6..e8c57e4 100644 --- a/include/mcld/Fragment/Relocation.h +++ b/include/mcld/Fragment/Relocation.h @@ -32,9 +32,10 @@ friend class Chunk<Relocation, MCLD_RELOCATIONS_PER_INPUT>; public: typedef uint64_t Address; // FIXME: use SizeTrait<T>::Address instead - typedef uint64_t DWord; // FIXME: use SizeTrait<T>::Word instead - typedef int64_t SWord; // FIXME: use SizeTrait<T>::SWord instead - typedef uint8_t Type; + typedef uint64_t DWord; // FIXME: use SizeTrait<T>::Word instead + typedef int64_t SWord; // FIXME: use SizeTrait<T>::SWord instead + typedef uint8_t Type; + typedef uint32_t Size; private: Relocation(); @@ -80,6 +81,9 @@ public: /// place - P value - address of the place being relocated Address place() const; + /// size - the size of the relocation in bit + Size size(Relocator& pRelocator) const; + /// symbol info - binding, type const ResolveInfo* symInfo() const { return m_pSymInfo; } ResolveInfo* symInfo() { return m_pSymInfo; } @@ -105,8 +109,6 @@ public: void setSymInfo(ResolveInfo* pSym); - size_t size() const; - private: /// m_Type - the type of the relocation entries Type m_Type; diff --git a/include/mcld/GeneralOptions.h b/include/mcld/GeneralOptions.h index 1468704..9d31097 100644 --- a/include/mcld/GeneralOptions.h +++ b/include/mcld/GeneralOptions.h @@ -30,6 +30,28 @@ class Input; class GeneralOptions { public: + enum StripSymbolMode { + KeepAllSymbols, + StripTemporaries, + StripLocals, + StripAllSymbols + }; + + enum HashStyle { + SystemV = 0x1, + GNU = 0x2, + Both = 0x3 + }; + + typedef std::vector<std::string> RpathList; + typedef RpathList::iterator rpath_iterator; + typedef RpathList::const_iterator const_rpath_iterator; + + typedef std::vector<std::string> AuxiliaryList; + typedef AuxiliaryList::iterator aux_iterator; + typedef AuxiliaryList::const_iterator const_aux_iterator; + +public: GeneralOptions(); ~GeneralOptions(); @@ -43,6 +65,8 @@ public: void setSysroot(const sys::fs::Path &pPath); + bool hasSysroot() const; + /// search directory SearchDirs& directories() { return m_SearchDirs; } @@ -98,12 +122,6 @@ public: const std::string& soname() const { return m_SOName; } - void setAllowShlibUndefined(bool pEnabled = true) - { m_bAllowShlibUndefined = pEnabled; } - - bool isAllowShlibUndefined() const - { return m_bAllowShlibUndefined; } - void setVerbose(int8_t pVerbose = -1) { m_Verbose = pVerbose; } @@ -201,7 +219,7 @@ public: void setNMagic(bool pMagic = true) { m_bNMagic = pMagic; } - bool nnagic() const + bool nmagic() const { return m_bNMagic; } // -N, --omagic @@ -250,6 +268,56 @@ public: bool isFatalWarnings() const { return m_bFatalWarnings; } + StripSymbolMode getStripSymbolMode() const + { return m_StripSymbols; } + + void setStripSymbols(StripSymbolMode pMode) + { m_StripSymbols = pMode; } + + void setNewDTags(bool pEnable = true) + { m_bNewDTags = pEnable; } + + bool hasNewDTags() const + { return m_bNewDTags; } + + void setNoStdlib(bool pEnable = true) + { m_bNoStdlib = pEnable; } + + bool nostdlib() const + { return m_bNoStdlib; } + + unsigned int getHashStyle() const { return m_HashStyle; } + + void setHashStyle(unsigned int pStyle) + { m_HashStyle = pStyle; } + + // ----- link-in rpath ----- // + const RpathList& getRpathList() const { return m_RpathList; } + RpathList& getRpathList() { return m_RpathList; } + + const_rpath_iterator rpath_begin() const { return m_RpathList.begin(); } + rpath_iterator rpath_begin() { return m_RpathList.begin(); } + const_rpath_iterator rpath_end () const { return m_RpathList.end(); } + rpath_iterator rpath_end () { return m_RpathList.end(); } + + // ----- filter and auxiliary filter ----- // + void setFilter(const std::string& pFilter) + { m_Filter = pFilter; } + + const std::string& filter() const + { return m_Filter; } + + bool hasFilter() const + { return !m_Filter.empty(); } + + const AuxiliaryList& getAuxiliaryList() const { return m_AuxiliaryList; } + AuxiliaryList& getAuxiliaryList() { return m_AuxiliaryList; } + + const_aux_iterator aux_begin() const { return m_AuxiliaryList.begin(); } + aux_iterator aux_begin() { return m_AuxiliaryList.begin(); } + const_aux_iterator aux_end () const { return m_AuxiliaryList.end(); } + aux_iterator aux_end () { return m_AuxiliaryList.end(); } + private: enum status { YES, @@ -289,7 +357,6 @@ private: bool m_Bgroup : 1; bool m_bPIE : 1; bool m_bColor : 1; // --color[=true,false,auto] - bool m_bAllowShlibUndefined : 1; // --[no-]allow-shlib-undefined and bool m_bCreateEhFrameHdr : 1; // --eh-frame-hdr bool m_bNMagic : 1; // -n, --nmagic bool m_bOMagic : 1; // -N, --omagic @@ -299,6 +366,13 @@ private: bool m_bBinaryInput : 1; // -b [input-format], --format=[input-format] bool m_bDefineCommon : 1; // -d, -dc, -dp bool m_bFatalWarnings : 1; // --fatal-warnings + bool m_bNewDTags: 1; // --enable-new-dtags + bool m_bNoStdlib: 1; // -nostdlib + StripSymbolMode m_StripSymbols; + RpathList m_RpathList; + unsigned int m_HashStyle; + std::string m_Filter; + AuxiliaryList m_AuxiliaryList; }; } // namespace of mcld diff --git a/include/mcld/IRBuilder.h b/include/mcld/IRBuilder.h index 3de292f..e189ce8 100644 --- a/include/mcld/IRBuilder.h +++ b/include/mcld/IRBuilder.h @@ -25,6 +25,7 @@ #include <mcld/Fragment/Relocation.h> #include <mcld/Fragment/RegionFragment.h> #include <mcld/Fragment/FillFragment.h> +#include <mcld/Fragment/FragmentRef.h> #include <mcld/Support/Path.h> #include <mcld/Support/FileHandle.h> @@ -53,6 +54,16 @@ public: COFF }; + enum SymbolDefinePolicy { + Force, + AsReferred + }; + + enum SymbolResolvePolicy { + Unresolve, + Resolve + }; + public: IRBuilder(Module& pModule, const LinkerConfig& pConfig); @@ -361,15 +372,19 @@ public: /// @return Total size of the inserted fragments. static uint64_t AppendEhFrame(EhFrame::CIE& pCIE, EhFrame& pEhFrame); - /// AddSymbol - To add a symbol to the input file and module. The symbol is - /// resolved immediately. + /// AddSymbol - To add a symbol to the input file. + /// This function create a new symbol and insert it into the input file. If + /// mcld::Module has another symbol with the same name, then this function + /// resolves these two symbols and keeps one in mcld::Module by their + /// attributes. /// /// This is a general method for all kinds of symbol. /// /// @param [in, out] pInput The input file. Either a relocatable or dynamic /// object /// @param [in] pName The name of the symbol - /// @param [in] pType What the symbol refers to + /// @param [in] pType What the symbol refers to. May be a object, + /// function, no-type and so on. @see ResolveInfo /// @param [in] pDesc { Undefined, Define, Common, Indirect } /// @param [in] pBind { Global, Weak, Local, Absolute } /// @param [in] pSize The size of the symbol. Bigger common symbols @@ -381,6 +396,9 @@ public: /// @param [in] pSection Absolute, undefined, common symbols do not have /// pSection. Keep their pSection be NULL. /// @oaram [in] pVis The visibility of the symbol + /// + /// @return The added symbol. If the insertion fails due to the resoluction, + /// return NULL. LDSymbol* AddSymbol(Input& pInput, const std::string& pName, ResolveInfo::Type pType, @@ -391,6 +409,51 @@ public: LDSection* pSection = NULL, ResolveInfo::Visibility pVis = ResolveInfo::Default); + /// AddSymbol - To add a symbol in mcld::Module + /// This function create a new symbol and insert it into mcld::Module. + /// + /// @tparam POLICY idicate the condition to define or not to define the + /// symbol. + /// - AsRefered + /// - Define a symbol only if mcld::Module contains a symbol with + /// identical name. If mcld::Module does not have any symbol with + /// the same name, this function returns NULL. + /// + /// - Force + /// - Define a symbol no matter mcld::Module has a symbol with identical + /// name or not. + /// + /// @tparam RESOLVE indicate the method to define a symbol. If we must define + /// a symbol in mcld::Module, then how to define it. + /// + /// - Resolve + /// - Follow the symbol resolution rule to bind the symbol references. + /// Resolution of the symbols with idential name depends on their + /// attributes. + /// + /// - Unresolve + /// - Forcefully override the symbol in mcld::Module. With this + /// argument, AddSymbol function turns a blind eye to symbol + /// resolution rules. + /// + /// @param [in] pName The name of the symbol + /// @param [in] pType The type of the symbol + /// @param [in] pDesc The description of the symbol, Could be one of + /// { Undefined, Define, Common, Indirect } + /// @param [in] pBinding The binding of the symbol. Could be one of + /// { Global, Weak, Local, Absolute } + /// + /// @return The symbol kept in mcld::Module. + template<SymbolDefinePolicy POLICY, SymbolResolvePolicy RESOLVE> + LDSymbol* AddSymbol(const llvm::StringRef& pName, + ResolveInfo::Type pType, + ResolveInfo::Desc pDesc, + ResolveInfo::Binding pBinding, + ResolveInfo::SizeType pSize = 0, + LDSymbol::ValueType pValue = 0x0, + FragmentRef* pFragmentRef = FragmentRef::Null(), + ResolveInfo::Visibility pVisibility = ResolveInfo::Default); + /// AddRelocation - To add a relocation entry /// /// @param [in] pSection The relocation section. pSection's link should point to @@ -415,7 +478,8 @@ private: FragmentRef* pFragmentRef, ResolveInfo::Visibility pVisibility); - LDSymbol* addSymbolFromDynObj(const std::string& pName, + LDSymbol* addSymbolFromDynObj(Input& pInput, + const std::string& pName, ResolveInfo::Type pType, ResolveInfo::Desc pDesc, ResolveInfo::Binding pBinding, @@ -430,6 +494,50 @@ private: InputBuilder m_InputBuilder; }; +template<> LDSymbol* +IRBuilder::AddSymbol<IRBuilder::Force, IRBuilder::Unresolve>( + const llvm::StringRef& pName, + ResolveInfo::Type pType, + ResolveInfo::Desc pDesc, + ResolveInfo::Binding pBinding, + ResolveInfo::SizeType pSize, + LDSymbol::ValueType pValue, + FragmentRef* pFragmentRef, + ResolveInfo::Visibility pVisibility); + +template<> LDSymbol* +IRBuilder::AddSymbol<IRBuilder::AsReferred, IRBuilder::Unresolve>( + const llvm::StringRef& pName, + ResolveInfo::Type pType, + ResolveInfo::Desc pDesc, + ResolveInfo::Binding pBinding, + ResolveInfo::SizeType pSize, + LDSymbol::ValueType pValue, + FragmentRef* pFragmentRef, + ResolveInfo::Visibility pVisibility); + +template<> LDSymbol* +IRBuilder::AddSymbol<IRBuilder::Force, IRBuilder::Resolve>( + const llvm::StringRef& pName, + ResolveInfo::Type pType, + ResolveInfo::Desc pDesc, + ResolveInfo::Binding pBinding, + ResolveInfo::SizeType pSize, + LDSymbol::ValueType pValue, + FragmentRef* pFragmentRef, + ResolveInfo::Visibility pVisibility); + +template<> LDSymbol* +IRBuilder::AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>( + const llvm::StringRef& pName, + ResolveInfo::Type pType, + ResolveInfo::Desc pDesc, + ResolveInfo::Binding pBinding, + ResolveInfo::SizeType pSize, + LDSymbol::ValueType pValue, + FragmentRef* pFragmentRef, + ResolveInfo::Visibility pVisibility); + } // end of namespace mcld #endif diff --git a/include/mcld/LD/BinaryWriter.h b/include/mcld/LD/BinaryWriter.h deleted file mode 100644 index d8133c4..0000000 --- a/include/mcld/LD/BinaryWriter.h +++ /dev/null @@ -1,39 +0,0 @@ -//===- BinaryWriter.h -----------------------------------------------------===// -// -// The MCLinker Project -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -#ifndef MCLD_BINARY_WRITER_INTERFACE_H -#define MCLD_BINARY_WRITER_INTERFACE_H -#ifdef ENABLE_UNITTEST -#include <gtest.h> -#endif -#include <llvm/Support/system_error.h> - -namespace mcld { - -class Module; -class MemoryArea; -class GNULDBackend; - -/** \class BinaryWriter - * \brief BinaryWriter provides a common interface for Binary file writers. - */ -class BinaryWriter -{ -protected: - BinaryWriter(GNULDBackend& pBackend); - -public: - virtual ~BinaryWriter(); - - virtual llvm::error_code writeBinary(Module& pModule, MemoryArea& pOutput) = 0; -}; - -} // namespace of mcld - -#endif - diff --git a/include/mcld/LD/DiagCommonKinds.inc b/include/mcld/LD/DiagCommonKinds.inc index 08850e7..ae54fe4 100644 --- a/include/mcld/LD/DiagCommonKinds.inc +++ b/include/mcld/LD/DiagCommonKinds.inc @@ -24,9 +24,8 @@ DIAG(err_unsupported_Bdynamic, DiagnosticEngine::Error, "Target does not support DIAG(err_enable_as_needed_on_static_system, DiagnosticEngine::Warning, "can not enable --as-needed on the target which does not support shared objects", "can not enable --as-needed on the target which does not support shared objects") DIAG(err_mix_static_as_needed, DiagnosticEngine::Warning, "cannot mix --static with --as-needed", "cannot mix --static with --as-needed") DIAG(err_cannot_change_file_size, DiagnosticEngine::Error, "cannot truncate file `%0' to size %1", "cannot truncate ffile `%0' to size %1") -DIAG(err_cannot_open_file, DiagnosticEngine::Error, "cannot open file %0.\nError Code: %1", "cannot open file %0.\nError Code: %1") -DIAG(err_cannot_close_file, DiagnosticEngine::Error, "cannot close file %0.\nError Code: %1", "cannot close file %0.\nError Code: %1") -DIAG(err_cannot_get_file_status, DiagnosticEngine::Error, "cannot get file status.\nError Code: %0", "cannot get file status.\nError Code: %0") +DIAG(err_cannot_open_file, DiagnosticEngine::Error, "cannot open file `%0': %1.", "cannot open file `%0': %1.") +DIAG(err_cannot_close_file, DiagnosticEngine::Error, "cannot close file `%0': %1.", "cannot close file `%0': %1.") DIAG(err_cannot_read_file, DiagnosticEngine::Error, "cannot read file %0 from offset %1 to length %2.", "cannot read file %0 from offset %1 to length %2.") DIAG(err_cannot_read_small_file, DiagnosticEngine::Fatal, "file %0 is too small to read.\n file size is %1.\n read from %2.", "file %0 is too small to read.\n file size is %1.\n read from %2.") DIAG(err_cannot_mmap_file, DiagnosticEngine::Error, "cannot open memory mapped file %0 from offset %1 to length %2.", "cannot open memoory mpped file %0 from offset %1 to length %2.") @@ -46,3 +45,5 @@ DIAG(fatal_unwritable_output, DiagnosticEngine::Fatal, "unable to write output f DIAG(warn_unsupported_option, DiagnosticEngine::Warning, "Option `%0' is not implemented yet!", "Option `%0' is not implemented yet!") DIAG(warn_shared_textrel, DiagnosticEngine::Warning, "Add DT_TEXTREL in a shared object!", "Add DT_TEXTREL in a shared object.") DIAG(fatal_illegal_codegen_type, DiagnosticEngine::Fatal, "illegal output format of output %0", "illegal output format of output %0") +DIAG(err_nmagic_not_static, DiagnosticEngine::Error, "cannot mix -nmagic option with -shared", "cannot mix -nmagic option with -shared") +DIAG(err_omagic_not_static, DiagnosticEngine::Error, "cannot mix -omagic option with -shared", "cannot mix -omagic option with -shared") diff --git a/include/mcld/LD/DynObjWriter.h b/include/mcld/LD/DynObjWriter.h deleted file mode 100644 index 89d9765..0000000 --- a/include/mcld/LD/DynObjWriter.h +++ /dev/null @@ -1,44 +0,0 @@ -//===- DynObjWriter.h -----------------------------------------------------===// -// -// The MCLinker Project -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -#ifndef MCLD_DYNAMIC_SHARED_OBJECT_WRITER_H -#define MCLD_DYNAMIC_SHARED_OBJECT_WRITER_H -#ifdef ENABLE_UNITTEST -#include <gtest.h> -#endif -#include <mcld/LD/LDWriter.h> -#include <llvm/Support/system_error.h> - -namespace mcld { - -class Module; -class MemoryArea; -class TargetLDBackend; - -/** \class DynObjWriter - * \brief DynObjWriter provides an common interface for different object - * formats. - */ -class DynObjWriter : public LDWriter -{ -protected: - // force to have a TargetLDBackend - DynObjWriter(TargetLDBackend& pLDBackend) - { } - -public: - virtual ~DynObjWriter() { } - - virtual llvm::error_code writeDynObj(Module& pModule, - MemoryArea& pOutput) = 0; -}; - -} // namespace of mcld - -#endif - diff --git a/include/mcld/LD/ELFBinaryWriter.h b/include/mcld/LD/ELFBinaryWriter.h deleted file mode 100644 index 593b54b..0000000 --- a/include/mcld/LD/ELFBinaryWriter.h +++ /dev/null @@ -1,46 +0,0 @@ -//===- ELFBinaryWriter.h --------------------------------------------------===// -// -// The MCLinker Project -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -#ifndef MCLD_ELF_BINARY_WRITER_H -#define MCLD_ELF_BINARY_WRITER_H -#ifdef ENABLE_UNITTEST -#include <gtest.h> -#endif -#include <llvm/Support/system_error.h> -#include <mcld/LD/BinaryWriter.h> -#include <mcld/LD/ELFWriter.h> - -namespace mcld { - -class Module; -class LinkerConfig; -class MemoryArea; -class GNULDBackend; - -/** \class ELFBinaryWriter - * \brief ELFBinaryWriter writes the target-independent parts of Binary files. - * ELFBinaryWriter reads a MCLDFile and writes into raw_ostream - * - */ -class ELFBinaryWriter : public BinaryWriter, protected ELFWriter -{ -public: - ELFBinaryWriter(GNULDBackend& pBackend, const LinkerConfig& pConfig); - - ~ELFBinaryWriter(); - - llvm::error_code writeBinary(Module& pModule, MemoryArea& pOutput); - -private: - const LinkerConfig& m_Config; -}; - -} // namespace of mcld - -#endif - diff --git a/include/mcld/LD/ELFDynObjWriter.h b/include/mcld/LD/ELFDynObjWriter.h deleted file mode 100644 index 774943e..0000000 --- a/include/mcld/LD/ELFDynObjWriter.h +++ /dev/null @@ -1,47 +0,0 @@ -//===- ELFDynObjWriter.h --------------------------------------------------===// -// -// The MCLinker Project -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -#ifndef MCLD_ELF_DYNAMIC_SHARED_OBJECT_WRITER_H -#define MCLD_ELF_DYNAMIC_SHARED_OBJECT_WRITER_H -#ifdef ENABLE_UNITTEST -#include <gtest.h> -#endif -#include <mcld/LD/DynObjWriter.h> -#include <mcld/LD/ELFWriter.h> - -namespace mcld { - -class Module; -class LinkerConfig; -class MemoryArea; -class GNULDBackend; - -/** \class ELFDynObjWriter - * \brief ELFDynObjWriter writes the dynamic sections. - */ -class ELFDynObjWriter : public DynObjWriter, private ELFWriter -{ -public: - typedef ELFWriter::FileOffset FileOffset; - -public: - ELFDynObjWriter(GNULDBackend& pBackend, - const LinkerConfig& pConfig); - - ~ELFDynObjWriter(); - - llvm::error_code writeDynObj(Module& pModule, MemoryArea& pOutput); - -private: - const LinkerConfig& m_Config; -}; - -} // namespace of mcld - -#endif - diff --git a/include/mcld/LD/ELFExecWriter.h b/include/mcld/LD/ELFExecWriter.h deleted file mode 100644 index ca69235..0000000 --- a/include/mcld/LD/ELFExecWriter.h +++ /dev/null @@ -1,47 +0,0 @@ -//===- ELFDynObjWriter.h --------------------------------------------------===// -// -// The MCLinker Project -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -#ifndef MCLD_ELF_EXECUTABLE_OBJECT_WRITER_H -#define MCLD_ELF_EXECUTABLE_OBJECT_WRITER_H -#ifdef ENABLE_UNITTEST -#include <gtest.h> -#endif -#include <mcld/LD/ExecWriter.h> -#include <mcld/LD/ELFWriter.h> - -namespace mcld { - -class Module; -class LinkerConfig; -class MemoryArea; -class GNULDBackend; - -/** \class ELFDynObjWriter - * \brief ELFDynObjWriter writes the dynamic sections. - */ -class ELFExecWriter : public ExecWriter, private ELFWriter -{ -public: - typedef ELFWriter::FileOffset FileOffset; - -public: - ELFExecWriter(GNULDBackend& pBackend, - const LinkerConfig& pConfig); - - ~ELFExecWriter(); - - llvm::error_code writeExecutable(Module& pModule, MemoryArea& pOutput); - -private: - const LinkerConfig& m_Config; -}; - -} // namespace of mcld - -#endif - diff --git a/include/mcld/LD/ELFFileFormat.h b/include/mcld/LD/ELFFileFormat.h index e52a813..5ed8997 100644 --- a/include/mcld/LD/ELFFileFormat.h +++ b/include/mcld/LD/ELFFileFormat.h @@ -180,6 +180,9 @@ public: bool hasDataRelRoLocal() const { return (NULL != f_pDataRelRoLocal) && (0 != f_pDataRelRoLocal->size()); } + bool hasGNUHashTab() const + { return (NULL != f_pGNUHashTab) && (0 != f_pGNUHashTab->size()); } + // ----- access functions ----- // /// @ref Special Sections, Ch. 4.17, System V ABI, 4th edition. LDSection& getNULLSection() { @@ -634,6 +637,16 @@ public: return *f_pDataRelRoLocal; } + LDSection& getGNUHashTab() { + assert(NULL != f_pGNUHashTab); + return *f_pGNUHashTab; + } + + const LDSection& getGNUHashTab() const { + assert(NULL != f_pGNUHashTab); + return *f_pGNUHashTab; + } + protected: // variable name : ELF /// @ref Special Sections, Ch. 4.17, System V ABI, 4th edition. @@ -688,6 +701,7 @@ protected: LDSection* f_pStack; // .stack LDSection* f_pStackNote; // .note.GNU-stack LDSection* f_pDataRelRoLocal; // .data.rel.ro.local + LDSection* f_pGNUHashTab; // .gnu.hash }; } // namespace of mcld diff --git a/include/mcld/LD/ELFObjectWriter.h b/include/mcld/LD/ELFObjectWriter.h index 28bbba8..ec4311e 100644 --- a/include/mcld/LD/ELFObjectWriter.h +++ b/include/mcld/LD/ELFObjectWriter.h @@ -12,7 +12,7 @@ #include <gtest.h> #endif #include <mcld/LD/ObjectWriter.h> -#include <mcld/LD/ELFWriter.h> +#include <cassert> #include <llvm/Support/system_error.h> @@ -20,17 +20,27 @@ namespace mcld { class Module; class LinkerConfig; -class MemoryArea; class GNULDBackend; +class FragmentLinker; +class Relocation; +class LDSection; +class SectionData; +class RelocData; +class Output; +class MemoryRegion; +class MemoryArea; /** \class ELFObjectWriter * \brief ELFObjectWriter writes the target-independent parts of object files. * ELFObjectWriter reads a MCLDFile and writes into raw_ostream * */ -class ELFObjectWriter : public ObjectWriter, protected ELFWriter +class ELFObjectWriter : public ObjectWriter { public: + typedef uint64_t FileOffset; + +public: ELFObjectWriter(GNULDBackend& pBackend, const LinkerConfig& pConfig); @@ -39,9 +49,87 @@ public: llvm::error_code writeObject(Module& pModule, MemoryArea& pOutput); private: + void writeSection(MemoryArea& pOutput, LDSection *section); + + GNULDBackend& target() { return m_Backend; } + + const GNULDBackend& target() const { return m_Backend; } + + // writeELFHeader - emit ElfXX_Ehdr + template<size_t SIZE> + void writeELFHeader(const LinkerConfig& pConfig, + const Module& pModule, + MemoryArea& pOutput) const; + + uint64_t getEntryPoint(const LinkerConfig& pConfig, + const Module& pModule) const; + + // emitSectionHeader - emit ElfXX_Shdr + template<size_t SIZE> + void emitSectionHeader(const Module& pModule, + const LinkerConfig& pConfig, + MemoryArea& pOutput) const; + + // emitProgramHeader - emit ElfXX_Phdr + template<size_t SIZE> + void emitProgramHeader(MemoryArea& pOutput) const; + + // emitShStrTab - emit .shstrtab + void emitShStrTab(const LDSection& pShStrTab, + const Module& pModule, + MemoryArea& pOutput); + + void emitSectionData(const LDSection& pSection, + MemoryRegion& pRegion) const; + + void emitRelocation(const LinkerConfig& pConfig, + const LDSection& pSection, + MemoryRegion& pRegion) const; + + // emitRel - emit ElfXX_Rel + template<size_t SIZE> + void emitRel(const LinkerConfig& pConfig, + const RelocData& pRelocData, + MemoryRegion& pRegion) const; + + // emitRela - emit ElfXX_Rela + template<size_t SIZE> + void emitRela(const LinkerConfig& pConfig, + const RelocData& pRelocData, + MemoryRegion& pRegion) const; + + // getSectEntrySize - compute ElfXX_Shdr::sh_entsize + template<size_t SIZE> + uint64_t getSectEntrySize(const LDSection& pSection) const; + + // getSectLink - compute ElfXX_Shdr::sh_link + uint64_t getSectLink(const LDSection& pSection, + const LinkerConfig& pConfig) const; + + // getSectInfo - compute ElfXX_Shdr::sh_info + uint64_t getSectInfo(const LDSection& pSection) const; + + template<size_t SIZE> + uint64_t getLastStartOffset(const Module& pModule) const + { + assert(0 && "Call invalid ELFObjectWriter::getLastStartOffset"); + return 0; + } + + void emitSectionData(const SectionData& pSD, MemoryRegion& pRegion) const; + +private: + GNULDBackend& m_Backend; + const LinkerConfig& m_Config; }; +template<> +uint64_t ELFObjectWriter::getLastStartOffset<32>(const Module& pModule) const; + +template<> +uint64_t ELFObjectWriter::getLastStartOffset<64>(const Module& pModule) const; + } // namespace of mcld #endif diff --git a/include/mcld/LD/ELFReader.h b/include/mcld/LD/ELFReader.h index 146a00a..b42b272 100644 --- a/include/mcld/LD/ELFReader.h +++ b/include/mcld/LD/ELFReader.h @@ -6,8 +6,8 @@ // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// -#ifndef MCLD_ELF_READER_INTERFACE_H -#define MCLD_ELF_READER_INTERFACE_H +#ifndef MCLD_ELF_READER_H +#define MCLD_ELF_READER_H #ifdef ENABLE_UNITTEST #include <gtest.h> #endif @@ -16,139 +16,105 @@ #include <llvm/Support/ELF.h> #include <llvm/Support/Host.h> -#include <mcld/Module.h> -#include <mcld/LinkerConfig.h> -#include <mcld/MC/MCLDInput.h> +#include <mcld/LD/ELFReaderIf.h> #include <mcld/LD/ResolveInfo.h> -#include <mcld/LD/LDContext.h> #include <mcld/Target/GNULDBackend.h> #include <mcld/Support/MemoryRegion.h> #include <mcld/Support/MemoryArea.h> -#include <mcld/Support/MsgHandling.h> namespace mcld { -class Module; +//class Module; class IRBuilder; -class FragmentRef; class SectionData; class LDSection; -/** \class ELFReaderIF - * \brief ELFReaderIF provides common interface for all kind of ELF readers. +/** \class ELFReader + * \brief ELFReader is a template scaffolding for partial specification. + */ +template<size_t BIT, bool LITTLEENDIAN> +class ELFReader +{ }; + +/** \class ELFReader<32, true> + * \brief ELFReader<32, true> is a 32-bit, little endian ELFReader. */ -class ELFReaderIF +template<> +class ELFReader<32, true> : public ELFReaderIF { public: - ELFReaderIF(GNULDBackend& pBackend) - : m_Backend(pBackend) - { } + typedef llvm::ELF::Elf32_Ehdr ELFHeader; + typedef llvm::ELF::Elf32_Shdr SectionHeader; + typedef llvm::ELF::Elf32_Sym Symbol; + typedef llvm::ELF::Elf32_Rel Rel; + typedef llvm::ELF::Elf32_Rela Rela; + +public: + ELFReader(GNULDBackend& pBackend); - virtual ~ELFReaderIF() { } + ~ELFReader(); /// ELFHeaderSize - return the size of the ELFHeader - virtual size_t getELFHeaderSize() const = 0; + size_t getELFHeaderSize() const + { return sizeof(ELFHeader); } /// isELF - is this a ELF file - virtual bool isELF(void* pELFHeader) const = 0; + bool isELF(void* pELFHeader) const; /// isMyEndian - is this ELF file in the same endian to me? - virtual bool isMyEndian(void* pELFHeader) const = 0; + bool isMyEndian(void* pELFHeader) const; /// isMyMachine - is this ELF file generated for the same machine. - virtual bool isMyMachine(void* pELFHeader) const = 0; + bool isMyMachine(void* pELFHeader) const; /// fileType - the file type of this file - virtual Input::Type fileType(void* pELFHeader) const = 0; - - /// target - the target backend - const GNULDBackend& target() const { return m_Backend; } - GNULDBackend& target() { return m_Backend; } - + Input::Type fileType(void* pELFHeader) const; /// readSectionHeaders - read ELF section header table and create LDSections - virtual bool readSectionHeaders(Input& pInput, void* pELFHeader) const = 0; + bool readSectionHeaders(Input& pInput, void* pELFHeader) const; /// readRegularSection - read a regular section and create fragments. - virtual bool readRegularSection(Input& pInput, SectionData& pSD) const = 0; + bool readRegularSection(Input& pInput, SectionData& pSD) const; /// readSymbols - read ELF symbols and create LDSymbol - virtual bool readSymbols(Input& pInput, - IRBuilder& pBuilder, - const MemoryRegion& pRegion, - const char* StrTab) const = 0; + bool readSymbols(Input& pInput, + IRBuilder& pBuilder, + const MemoryRegion& pRegion, + const char* StrTab) const; /// readSignature - read a symbol from the given Input and index in symtab /// This is used to get the signature of a group section. - virtual ResolveInfo* readSignature(Input& pInput, - LDSection& pSymTab, - uint32_t pSymIdx) const = 0; + ResolveInfo* readSignature(Input& pInput, + LDSection& pSymTab, + uint32_t pSymIdx) const; /// readRela - read ELF rela and create Relocation - virtual bool readRela(Input& pInput, - LDSection& pSection, - const MemoryRegion& pRegion) const = 0; + bool readRela(Input& pInput, + LDSection& pSection, + const MemoryRegion& pRegion) const; /// readRel - read ELF rel and create Relocation - virtual bool readRel(Input& pInput, - LDSection& pSection, - const MemoryRegion& pRegion) const = 0; + bool readRel(Input& pInput, + LDSection& pSection, + const MemoryRegion& pRegion) const; /// readDynamic - read ELF .dynamic in input dynobj - virtual bool readDynamic(Input& pInput) const = 0; - -protected: - /// LinkInfo - some section needs sh_link and sh_info, remember them. - struct LinkInfo { - LDSection* section; - uint32_t sh_link; - uint32_t sh_info; - }; - - typedef std::vector<LinkInfo> LinkInfoList; - -protected: - ResolveInfo::Type getSymType(uint8_t pInfo, uint16_t pShndx) const; - - ResolveInfo::Desc getSymDesc(uint16_t pShndx, const Input& pInput) const; - - ResolveInfo::Binding getSymBinding(uint8_t pBinding, - uint16_t pShndx, - uint8_t pVisibility) const; - - uint64_t getSymValue(uint64_t pValue, - uint16_t pShndx, - const Input& pInput) const; - - FragmentRef* getSymFragmentRef(Input& pInput, - uint16_t pShndx, - uint32_t pOffset) const; - - ResolveInfo::Visibility getSymVisibility(uint8_t pVis) const; - -protected: - GNULDBackend& m_Backend; + bool readDynamic(Input& pInput) const; }; -/** \class ELFReader - * \brief ELFReader is a template scaffolding for partial specification. - */ -template<size_t BIT, bool LITTLEENDIAN> -class ELFReader -{ }; -/** \class ELFReader<32, true> - * \brief ELFReader<32, true> is a 32-bit, little endian ELFReader. +/** \class ELFReader<64, true> + * \brief ELFReader<64, true> is a 64-bit, little endian ELFReader. */ template<> -class ELFReader<32, true> : public ELFReaderIF +class ELFReader<64, true> : public ELFReaderIF { public: - typedef llvm::ELF::Elf32_Ehdr ELFHeader; - typedef llvm::ELF::Elf32_Shdr SectionHeader; - typedef llvm::ELF::Elf32_Sym Symbol; - typedef llvm::ELF::Elf32_Rel Rel; - typedef llvm::ELF::Elf32_Rela Rela; + typedef llvm::ELF::Elf64_Ehdr ELFHeader; + typedef llvm::ELF::Elf64_Shdr SectionHeader; + typedef llvm::ELF::Elf64_Sym Symbol; + typedef llvm::ELF::Elf64_Rel Rel; + typedef llvm::ELF::Elf64_Rela Rela; public: ELFReader(GNULDBackend& pBackend); diff --git a/include/mcld/LD/ELFReaderIf.h b/include/mcld/LD/ELFReaderIf.h new file mode 100644 index 0000000..245b542 --- /dev/null +++ b/include/mcld/LD/ELFReaderIf.h @@ -0,0 +1,132 @@ +//===- ELFReader.h --------------------------------------------------------===// +// +// The MCLinker Project +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#ifndef MCLD_ELF_READER_INTERFACE_H +#define MCLD_ELF_READER_INTERFACE_H +#ifdef ENABLE_UNITTEST +#include <gtest.h> +#endif + +#include <llvm/ADT/StringRef.h> +#include <llvm/Support/ELF.h> +#include <llvm/Support/Host.h> + +#include <mcld/Module.h> +#include <mcld/LinkerConfig.h> +#include <mcld/LD/LDContext.h> +#include <mcld/Target/GNULDBackend.h> +#include <mcld/Support/MsgHandling.h> + +namespace mcld { + +class Module; +class IRBuilder; +class FragmentRef; +class SectionData; +class LDSection; + +/** \class ELFReaderIF + * \brief ELFReaderIF provides common interface for all kind of ELF readers. + */ +class ELFReaderIF +{ +public: + ELFReaderIF(GNULDBackend& pBackend) + : m_Backend(pBackend) + { } + + virtual ~ELFReaderIF() { } + + /// ELFHeaderSize - return the size of the ELFHeader + virtual size_t getELFHeaderSize() const = 0; + + /// isELF - is this a ELF file + virtual bool isELF(void* pELFHeader) const = 0; + + /// isMyEndian - is this ELF file in the same endian to me? + virtual bool isMyEndian(void* pELFHeader) const = 0; + + /// isMyMachine - is this ELF file generated for the same machine. + virtual bool isMyMachine(void* pELFHeader) const = 0; + + /// fileType - the file type of this file + virtual Input::Type fileType(void* pELFHeader) const = 0; + + /// target - the target backend + const GNULDBackend& target() const { return m_Backend; } + GNULDBackend& target() { return m_Backend; } + + + /// readSectionHeaders - read ELF section header table and create LDSections + virtual bool readSectionHeaders(Input& pInput, void* pELFHeader) const = 0; + + /// readRegularSection - read a regular section and create fragments. + virtual bool readRegularSection(Input& pInput, SectionData& pSD) const = 0; + + /// readSymbols - read ELF symbols and create LDSymbol + virtual bool readSymbols(Input& pInput, + IRBuilder& pBuilder, + const MemoryRegion& pRegion, + const char* StrTab) const = 0; + + /// readSignature - read a symbol from the given Input and index in symtab + /// This is used to get the signature of a group section. + virtual ResolveInfo* readSignature(Input& pInput, + LDSection& pSymTab, + uint32_t pSymIdx) const = 0; + + /// readRela - read ELF rela and create Relocation + virtual bool readRela(Input& pInput, + LDSection& pSection, + const MemoryRegion& pRegion) const = 0; + + /// readRel - read ELF rel and create Relocation + virtual bool readRel(Input& pInput, + LDSection& pSection, + const MemoryRegion& pRegion) const = 0; + + /// readDynamic - read ELF .dynamic in input dynobj + virtual bool readDynamic(Input& pInput) const = 0; + +protected: + /// LinkInfo - some section needs sh_link and sh_info, remember them. + struct LinkInfo { + LDSection* section; + uint32_t sh_link; + uint32_t sh_info; + }; + + typedef std::vector<LinkInfo> LinkInfoList; + +protected: + ResolveInfo::Type getSymType(uint8_t pInfo, uint16_t pShndx) const; + + ResolveInfo::Desc getSymDesc(uint16_t pShndx, const Input& pInput) const; + + ResolveInfo::Binding getSymBinding(uint8_t pBinding, + uint16_t pShndx, + uint8_t pVisibility) const; + + uint64_t getSymValue(uint64_t pValue, + uint16_t pShndx, + const Input& pInput) const; + + FragmentRef* getSymFragmentRef(Input& pInput, + uint16_t pShndx, + uint32_t pOffset) const; + + ResolveInfo::Visibility getSymVisibility(uint8_t pVis) const; + +protected: + GNULDBackend& m_Backend; +}; + +} // namespace of mcld + +#endif + diff --git a/include/mcld/LD/ELFWriter.h b/include/mcld/LD/ELFWriter.h deleted file mode 100644 index b0c4d81..0000000 --- a/include/mcld/LD/ELFWriter.h +++ /dev/null @@ -1,124 +0,0 @@ -//===- ELFWriter.h --------------------------------------------------------===// -// -// The MCLinker Project -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -#ifndef MCLD_ELF_WRITER_H -#define MCLD_ELF_WRITER_H -#ifdef ENABLE_UNITTEST -#include <gtest.h> -#endif - -#include <llvm/Support/ELF.h> - -namespace mcld { - -class Module; -class FragmentLinker; -class LinkerConfig; -class GNULDBackend; -class Relocation; -class LDSection; -class SectionData; -class RelocData; -class Output; -class MemoryRegion; -class MemoryArea; - -/** \class ELFWriter - * \brief ELFWriter provides basic functions to write ELF sections, symbols, - * and so on. - */ -class ELFWriter -{ -public: - typedef uint64_t FileOffset; - -protected: - ELFWriter(GNULDBackend& pBackend) - : f_Backend(pBackend) { - } - -public: - virtual ~ELFWriter() { } - - GNULDBackend& target() - { return f_Backend; } - - const GNULDBackend& target() const - { return f_Backend; } - - virtual void writeELF32Header(const LinkerConfig& pConfig, - const Module& pModule, - MemoryArea& pOutput) const; - - virtual void writeELF64Header(const LinkerConfig& pConfig, - const Module& pModule, - MemoryArea& pOutput) const; - - virtual uint64_t getEntryPoint(const LinkerConfig& pConfig, - const Module& pModule) const; - -protected: - void emitELF32SectionHeader(const Module& pModule, - const LinkerConfig& pConfig, - MemoryArea& pOutput) const; - - void emitELF64SectionHeader(const Module& pModule, - const LinkerConfig& pConfig, - MemoryArea& pOutput) const; - - void emitELF32ProgramHeader(MemoryArea& pOutput) const; - - void emitELF64ProgramHeader(MemoryArea& pOutput) const; - - // emitShStrTab - emit .shstrtab - void emitELFShStrTab(const LDSection& pShStrTab, const Module& pModule, - MemoryArea& pOutput); - - void emitSectionData(const LDSection& pSection, - MemoryRegion& pRegion) const; - - void emitRelocation(const LinkerConfig& pConfig, - const LDSection& pSection, - MemoryRegion& pRegion) const; - - void emitRel(const LinkerConfig& pConfig, - const RelocData& pRelocData, - MemoryRegion& pRegion) const; - - void emitRela(const LinkerConfig& pConfig, - const RelocData& pRelocData, - MemoryRegion& pRegion) const; - -private: - // getSectEntrySize - compute ElfXX_Shdr::sh_entsize - uint64_t getELF32SectEntrySize(const LDSection& pSection) const; - - // getSectEntrySize - compute ElfXX_Shdr::sh_entsize - uint64_t getELF64SectEntrySize(const LDSection& pSection) const; - - // getSectEntrySize - compute ElfXX_Shdr::sh_link - uint64_t getSectLink(const LDSection& pSection, - const LinkerConfig& pConfig) const; - - // getSectEntrySize - compute ElfXX_Shdr::sh_info - uint64_t getSectInfo(const LDSection& pSection) const; - - uint64_t getELF32LastStartOffset(const Module& pModule) const; - - uint64_t getELF64LastStartOffset(const Module& pModule) const; - - void emitSectionData(const SectionData& pSD, MemoryRegion& pRegion) const; - -protected: - GNULDBackend& f_Backend; -}; - -} // namespace of mcld - -#endif - diff --git a/include/mcld/LD/EhFrame.h b/include/mcld/LD/EhFrame.h index dc360a2..695f72b 100644 --- a/include/mcld/LD/EhFrame.h +++ b/include/mcld/LD/EhFrame.h @@ -12,8 +12,11 @@ #include <gtest.h> #endif -#include <vector> +#include <mcld/Config/Config.h> #include <mcld/Fragment/RegionFragment.h> +#include <mcld/Support/Allocators.h> + +#include <vector> namespace mcld { @@ -25,6 +28,17 @@ class SectionData; */ class EhFrame { +private: + friend class Chunk<EhFrame, MCLD_SECTIONS_PER_INPUT>; + + EhFrame(); + explicit EhFrame(LDSection& pSection); + + ~EhFrame(); + + EhFrame(const EhFrame&); // DO NOT IMPLEMENT + EhFrame& operator=(const EhFrame&); // DO NOT IMPLEMENT + public: /** \class CIE * \brief Common Information Entry. @@ -56,6 +70,7 @@ public: const CIE& getCIE() const { return m_CIE; } uint32_t getDataStart() const { return m_DataStart; } + private: const CIE& m_CIE; uint32_t m_DataStart; @@ -74,15 +89,17 @@ public: typedef FDEList::const_iterator const_fde_iterator; public: - EhFrame(LDSection& pSection); + static EhFrame* Create(LDSection& pSection); - ~EhFrame(); + static void Destroy(EhFrame*& pSection); + + static void Clear(); /// merge - move all data from pOther to this object. EhFrame& merge(EhFrame& pOther); - const LDSection& getSection() const { return m_Section; } - LDSection& getSection() { return m_Section; } + const LDSection& getSection() const; + LDSection& getSection(); const SectionData& getSectionData() const { return *m_pSectionData; } SectionData& getSectionData() { return *m_pSectionData; } @@ -125,7 +142,7 @@ public: size_t numOfFDEs() const { return m_FDEs.size(); } private: - LDSection& m_Section; + LDSection* m_pSection; SectionData* m_pSectionData; CIEList m_CIEs; diff --git a/include/mcld/LD/EhFrameHdr.h b/include/mcld/LD/EhFrameHdr.h index 3a5971d..e9d8702 100644 --- a/include/mcld/LD/EhFrameHdr.h +++ b/include/mcld/LD/EhFrameHdr.h @@ -70,6 +70,9 @@ private: template<> void EhFrameHdr::emitOutput<32>(MemoryArea& pOutput); +template<> +void EhFrameHdr::emitOutput<64>(MemoryArea& pOutput); + } // namespace of mcld #endif diff --git a/include/mcld/LD/ExecWriter.h b/include/mcld/LD/ExecWriter.h deleted file mode 100644 index e0ea325..0000000 --- a/include/mcld/LD/ExecWriter.h +++ /dev/null @@ -1,44 +0,0 @@ -//===- ExecWriter.h -------------------------------------------------------===// -// -// The MCLinker Project -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -#ifndef MCLD_EXECUTABLE_OBJECT_WRITER_H -#define MCLD_EXECUTABLE_OBJECT_WRITER_H -#ifdef ENABLE_UNITTEST -#include <gtest.h> -#endif -#include <mcld/LD/LDWriter.h> -#include <llvm/Support/system_error.h> - -namespace mcld { - -class Module; -class MemoryArea; -class TargetLDBackend; - -/** \class ExecWriter - * \brief ExecWriter provides an common interface for different object - * formats. - */ -class ExecWriter : public LDWriter -{ -protected: - // force to have a TargetLDBackend - ExecWriter(TargetLDBackend& pLDBackend) - { } - -public: - virtual ~ExecWriter() { } - - virtual llvm::error_code writeExecutable(Module& pModule, - MemoryArea& pOutput) = 0; -}; - -} // namespace of mcld - -#endif - diff --git a/include/mcld/LD/LDSymbol.h b/include/mcld/LD/LDSymbol.h index 326c82f..b40213c 100644 --- a/include/mcld/LD/LDSymbol.h +++ b/include/mcld/LD/LDSymbol.h @@ -19,6 +19,8 @@ #include <mcld/LD/ResolveInfo.h> #include <mcld/Support/Allocators.h> +#include <llvm/Support/ManagedStatic.h> + namespace mcld { class FragmentRef; @@ -127,6 +129,7 @@ public: private: friend class Chunk<LDSymbol, MCLD_SYMBOLS_PER_INPUT>; + template<class T> friend void* llvm::object_creator(); LDSymbol(); LDSymbol(const LDSymbol& pCopy); diff --git a/include/mcld/LD/LDWriter.h b/include/mcld/LD/LDWriter.h deleted file mode 100644 index b7dd14c..0000000 --- a/include/mcld/LD/LDWriter.h +++ /dev/null @@ -1,39 +0,0 @@ -//===- LDWriter.h ---------------------------------------------------------===// -// -// The MCLinker Project -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// LDWriter provides an interface used by MCLinker, -// which writes the result of linking into a .so file or a executable. -// -//===----------------------------------------------------------------------===// -#ifndef MCLD_WRITER_INTERFACE_H -#define MCLD_WRITER_INTERFACE_H -#ifdef ENABLE_UNITTEST -#include <gtest.h> -#endif - -namespace mcld { - -/** \class LDWriter - * \brief LDWriter provides the basic interfaces for all writers. - * (ObjectWriter, DynObjWriter, and EXEObjWriter) - */ -class LDWriter -{ -protected: - LDWriter() { } - -public: - virtual ~LDWriter() { } - -}; - -} //end namespace - -#endif - diff --git a/include/mcld/LD/NamePool.h b/include/mcld/LD/NamePool.h index 12b4b91..fa0bb10 100644 --- a/include/mcld/LD/NamePool.h +++ b/include/mcld/LD/NamePool.h @@ -12,15 +12,17 @@ #include <gtest.h> #endif -#include <utility> - -#include <llvm/ADT/StringRef.h> - +#include <mcld/Config/Config.h> #include <mcld/ADT/HashTable.h> #include <mcld/ADT/StringHash.h> #include <mcld/ADT/Uncopyable.h> #include <mcld/LD/Resolver.h> #include <mcld/LD/ResolveInfo.h> +#include <mcld/Support/GCFactory.h> + +#include <utility> + +#include <llvm/ADT/StringRef.h> namespace mcld { @@ -97,9 +99,12 @@ public: size_type capacity() const; private: + typedef GCFactory<ResolveInfo*, 128> FreeInfoSet; + +private: Resolver* m_pResolver; Table m_Table; - + FreeInfoSet m_FreeInfoSet; }; } // namespace of mcld diff --git a/include/mcld/LD/ObjectWriter.h b/include/mcld/LD/ObjectWriter.h index a84e0d3..c1dcac6 100644 --- a/include/mcld/LD/ObjectWriter.h +++ b/include/mcld/LD/ObjectWriter.h @@ -17,7 +17,6 @@ namespace mcld { class Module; class MemoryArea; -class GNULDBackend; /** \class ObjectWriter * \brief ObjectWriter provides a common interface for object file writers. @@ -25,7 +24,7 @@ class GNULDBackend; class ObjectWriter { protected: - ObjectWriter(GNULDBackend& pBackend); + ObjectWriter(); public: virtual ~ObjectWriter(); diff --git a/include/mcld/LD/Relocator.h b/include/mcld/LD/Relocator.h index 6fd431e..8589894 100644 --- a/include/mcld/LD/Relocator.h +++ b/include/mcld/LD/Relocator.h @@ -26,10 +26,11 @@ class TargetLDBackend; class Relocator { public: - typedef Relocation::Type Type; + typedef Relocation::Type Type; typedef Relocation::Address Address; - typedef Relocation::DWord DWord; - typedef Relocation::SWord SWord; + typedef Relocation::DWord DWord; + typedef Relocation::SWord SWord; + typedef Relocation::Size Size; public: enum Result { @@ -41,33 +42,21 @@ public: }; public: - virtual ~Relocator() {} + virtual ~Relocator() = 0; /// apply - general apply function virtual Result applyRelocation(Relocation& pRelocation) = 0; - void setFragmentLinker(const FragmentLinker& pLinker) - { m_pLinker = &pLinker; } - // ------ observers -----// - const FragmentLinker& getFragmentLinker() const - { - assert(NULL != m_pLinker); - return *m_pLinker; - } - - bool hasFragmentLinker() const - { return (NULL != m_pLinker); } - virtual TargetLDBackend& getTarget() = 0; virtual const TargetLDBackend& getTarget() const = 0; + /// getName - get the name of a relocation virtual const char* getName(Type pType) const = 0; -private: - const FragmentLinker* m_pLinker; - + /// getSize - get the size of a relocation in bit + virtual Size getSize(Type pType) const = 0; }; } // namespace of mcld diff --git a/include/mcld/LD/StubFactory.h b/include/mcld/LD/StubFactory.h index b38a96f..8548e5a 100644 --- a/include/mcld/LD/StubFactory.h +++ b/include/mcld/LD/StubFactory.h @@ -20,7 +20,7 @@ namespace mcld { class Stub; class Relocation; class BranchIslandFactory; -class FragmentLinker; +class IRBuilder; /** \class StubFactory * \brief the clone factory of Stub @@ -37,7 +37,7 @@ public: /// create - create a stub if needed, otherwise return NULL Stub* create(Relocation& pReloc, uint64_t pTargetSymValue, - FragmentLinker& pLinker, + IRBuilder& pBuilder, BranchIslandFactory& pBRIslandFactory); private: diff --git a/include/mcld/Linker.h b/include/mcld/Linker.h index 891372c..d5fc438 100644 --- a/include/mcld/Linker.h +++ b/include/mcld/Linker.h @@ -38,14 +38,26 @@ public: ~Linker(); + /// config - To set up target-dependent options in pConfig. bool config(LinkerConfig& pConfig); + /// resolve - To read participatory input files and build up mcld::Module + bool resolve(Module& pModule, IRBuilder& pBuilder); + + /// layout - To serialize the final result of the output mcld::Module + bool layout(); + + /// link - A convenient way to resolve and to layout the output mcld::Module. bool link(Module& pModule, IRBuilder& pBuilder); + /// emit - To emit output mcld::Module to a output MemoryArea bool emit(MemoryArea& pOutput); + /// emit - To open a file for output in pPath and to emit output mcld::Module + /// to the file. bool emit(const std::string& pPath); + /// emit - To emit output mcld::Module in the pFileDescriptor. bool emit(int pFileDescriptor); bool reset(); @@ -61,7 +73,6 @@ private: private: LinkerConfig* m_pConfig; - Module* m_pModule; IRBuilder* m_pIRBuilder; const Target* m_pTarget; diff --git a/include/mcld/LinkerConfig.h b/include/mcld/LinkerConfig.h index 9e70ecf..f0c2c87 100644 --- a/include/mcld/LinkerConfig.h +++ b/include/mcld/LinkerConfig.h @@ -44,6 +44,28 @@ public: Binary }; + /** \enum CodePosition + * CodePosition indicates the ability of the generated output to be + * loaded at different addresses. If the output can be loaded at different + * addresses, we say the output is position independent. Shared libraries + * and position-independent executable programs (PIE) are in this category. + * ::Independent indicates the output is position independent. + * If a executable program can not be loaded at arbitrary addresses, but it + * can call outside functions, we say the program is dynamic dependent on + * the address to be loaded. ::DynamicDependent indicates the output is not + * only a executable program, but also dynamic dependent. In general, + * executable programs are dynamic dependent. + * If a executable program can not be loaded at different addresses, and + * only call inner functions, then we say the program is static dependent on + * its loaded address. ::StaticDependent is used to indicate this kind of + * output. + */ + enum CodePosition { + Independent, ///< Position Independent + DynamicDependent, ///< Can call outside libraries + StaticDependent ///< Can not call outside libraries + }; + public: LinkerConfig(); @@ -70,6 +92,13 @@ public: void setCodeGenType(CodeGenType pType) { m_CodeGenType = pType; } + CodePosition codePosition() const { return m_CodePosition; } + void setCodePosition(CodePosition pPosition) { m_CodePosition = pPosition; } + + bool isCodeIndep() const { return (Independent == m_CodePosition); } + bool isCodeDynamic() const { return (DynamicDependent == m_CodePosition); } + bool isCodeStatic() const { return (StaticDependent == m_CodePosition); } + static const char* version(); private: @@ -81,6 +110,7 @@ private: AttributeOption m_Attribute; CodeGenType m_CodeGenType; + CodePosition m_CodePosition; }; } // namespace of mcld diff --git a/include/mcld/MC/SearchDirs.h b/include/mcld/MC/SearchDirs.h index 13cc12f..0c0c657 100644 --- a/include/mcld/MC/SearchDirs.h +++ b/include/mcld/MC/SearchDirs.h @@ -65,6 +65,8 @@ public: iterator end () { return m_DirList.end(); } // ----- modifiers ----- // + bool insert(const char* pDirectory); + bool insert(const std::string& pDirectory); bool insert(const sys::fs::Path& pDirectory); diff --git a/include/mcld/MC/SymbolCategory.h b/include/mcld/MC/SymbolCategory.h index 3aa16c5..700fba2 100644 --- a/include/mcld/MC/SymbolCategory.h +++ b/include/mcld/MC/SymbolCategory.h @@ -11,7 +11,7 @@ #ifdef ENABLE_UNITTEST #include <gtest.h> #endif -#include <mcld/ADT/TypeTraits.h> +#include <cstddef> #include <vector> namespace mcld @@ -45,7 +45,7 @@ public: SymbolCategory& changeCommonsToGlobal(); - SymbolCategory& changeLocalToTLS(const LDSymbol& pSymbol); + SymbolCategory& changeLocalToDynamic(const LDSymbol& pSymbol); // ----- access ----- // LDSymbol& at(size_t pPosition) @@ -63,18 +63,30 @@ public: // ----- observers ----- // size_t numOfSymbols() const; + size_t numOfFiles() const; + size_t numOfLocals() const; + size_t numOfLocalDyns() const; + size_t numOfCommons() const; + size_t numOfDynamics() const; + size_t numOfRegulars() const; bool empty() const; + bool emptyFiles() const; + bool emptyLocals() const; + bool emptyLocalDyns() const; + bool emptyCommons() const; + bool emptyDynamics() const; + bool emptyRegulars() const; // ----- iterators ----- // @@ -83,21 +95,31 @@ public: const_iterator begin() const; const_iterator end() const; + iterator fileBegin(); + iterator fileEnd(); + const_iterator fileBegin() const; + const_iterator fileEnd() const; + iterator localBegin(); iterator localEnd(); const_iterator localBegin() const; const_iterator localEnd() const; - iterator tlsBegin(); - iterator tlsEnd(); - const_iterator tlsBegin() const; - const_iterator tlsEnd() const; + iterator localDynBegin(); + iterator localDynEnd(); + const_iterator localDynBegin() const; + const_iterator localDynEnd() const; iterator commonBegin(); iterator commonEnd(); const_iterator commonBegin() const; const_iterator commonEnd() const; + iterator dynamicBegin(); + iterator dynamicEnd(); + const_iterator dynamicBegin() const; + const_iterator dynamicEnd() const; + iterator regularBegin(); iterator regularEnd(); const_iterator regularBegin() const; @@ -110,10 +132,10 @@ private: enum Type { File, Local, - TLS, + LocalDyn, Common, - Weak, - Global + Dynamic, + Regular }; public: @@ -147,18 +169,20 @@ private: { return (NULL == next); } static Type categorize(const ResolveInfo& pInfo); - }; private: + SymbolCategory& add(LDSymbol& pSymbol, Category::Type pTarget); + +private: OutputSymbols m_OutputSymbols; Category* m_pFile; Category* m_pLocal; - Category* m_pTLS; + Category* m_pLocalDyn; Category* m_pCommon; - Category* m_pWeak; - Category* m_pGlobal; + Category* m_pDynamic; + Category* m_pRegular; }; } // namespace of mcld diff --git a/include/mcld/Object/ObjectBuilder.h b/include/mcld/Object/ObjectBuilder.h index bfa4c6b..79f81a5 100644 --- a/include/mcld/Object/ObjectBuilder.h +++ b/include/mcld/Object/ObjectBuilder.h @@ -65,12 +65,16 @@ public: /// /// @see SectionMap /// @param [in] pInputSection The merged input section. - /// @return If the corresponding output sections is not defined, return false. - bool MergeSection(LDSection& pInputSection); + /// @return The merged output section. If the corresponding output sections + /// is not defined, return NULL. + LDSection* MergeSection(LDSection& pInputSection); /// MoveSectionData - move the fragment of pFrom to pTo section data. static bool MoveSectionData(SectionData& pFrom, SectionData& pTo); + /// UpdateSectionAlign - update alignment for input section + static void UpdateSectionAlign(LDSection& pTo, const LDSection& pFrom); + /// @} /// @name Fragment Methods /// @{ diff --git a/include/mcld/Object/ObjectLinker.h b/include/mcld/Object/ObjectLinker.h index 515bc58..999764f 100644 --- a/include/mcld/Object/ObjectLinker.h +++ b/include/mcld/Object/ObjectLinker.h @@ -44,12 +44,12 @@ class ObjectLinker { public: ObjectLinker(const LinkerConfig& pConfig, - Module& pModule, - IRBuilder& pBuilder, TargetLDBackend& pLDBackend); ~ObjectLinker(); + void setup(Module& pModule, IRBuilder& pBuilder); + /// initFragmentLinker - initialize FragmentLinker /// Connect all components in FragmentLinker bool initFragmentLinker(); @@ -72,6 +72,10 @@ public: /// mergeSections - put allinput sections into output sections bool mergeSections(); + /// allocateCommonSymobols - allocate fragments for common symbols to the + /// corresponding sections + bool allocateCommonSymbols(); + /// addStandardSymbols - shared object and executable files need some /// standard symbols /// @return if there are some input symbols with the same name to the @@ -84,9 +88,18 @@ public: /// target symbols, return false bool addTargetSymbols(); + /// addScriptSymbols - define symbols from the command line option or linker + /// scripts. + /// @return if there are some existing symbols with identical name to the + /// script symbols, return false. + bool addScriptSymbols(); + /// scanRelocations - scan all relocation entries by output symbols. bool scanRelocations(); + /// initStubs - initialize stub-related stuff. + bool initStubs(); + /// prelayout - help backend to do some modification before layout bool prelayout(); @@ -140,25 +153,15 @@ public: const BinaryReader* getBinaryReader () const { return m_pBinaryReader; } BinaryReader* getBinaryReader () { return m_pBinaryReader; } - const ObjectWriter* getObjectWriter () const { return m_pObjectWriter; } - ObjectWriter* getObjectWriter () { return m_pObjectWriter; } - - const DynObjWriter* getDynObjWriter () const { return m_pDynObjWriter; } - DynObjWriter* getDynObjWriter () { return m_pDynObjWriter; } - - const ExecWriter* getExecWriter () const { return m_pExecWriter; } - ExecWriter* getExecWriter () { return m_pExecWriter; } - - const BinaryWriter* getBinaryWriter () const { return m_pBinaryWriter; } - BinaryWriter* getBinaryWriter () { return m_pBinaryWriter; } + const ObjectWriter* getWriter () const { return m_pWriter; } + ObjectWriter* getWriter () { return m_pWriter; } private: const LinkerConfig& m_Config; - Module& m_Module; - - IRBuilder& m_Builder; - FragmentLinker* m_pLinker; + Module* m_pModule; + IRBuilder* m_pBuilder; + TargetLDBackend &m_LDBackend; // ----- readers and writers ----- // @@ -167,10 +170,7 @@ private: ArchiveReader* m_pArchiveReader; GroupReader* m_pGroupReader; BinaryReader* m_pBinaryReader; - ObjectWriter* m_pObjectWriter; - DynObjWriter* m_pDynObjWriter; - ExecWriter* m_pExecWriter; - BinaryWriter* m_pBinaryWriter; + ObjectWriter* m_pWriter; }; } // end namespace mcld diff --git a/include/mcld/Support/FileHandle.h b/include/mcld/Support/FileHandle.h index 3b4fe81..ce43e0f 100644 --- a/include/mcld/Support/FileHandle.h +++ b/include/mcld/Support/FileHandle.h @@ -35,6 +35,7 @@ public: BadBit = 1L << 0, // error due to the inappropriate operation EOFBit = 1L << 1, // reached End-Of-File FailBit = 1L << 2, // internal logic fail + DeputedBit = 1L << 3, // the file descriptor is delegated IOStateEnd = 1L << 16 }; @@ -120,14 +121,15 @@ public: bool isFailed() const; + bool isOwned() const; + bool isReadable() const; bool isWritable() const; bool isReadWrite() const; - int error() const - { return errno; } + int error() const { return errno; } private: sys::fs::Path m_Path; diff --git a/include/mcld/Support/MemoryArea.h b/include/mcld/Support/MemoryArea.h index a735f62..74297f3 100644 --- a/include/mcld/Support/MemoryArea.h +++ b/include/mcld/Support/MemoryArea.h @@ -110,7 +110,7 @@ private: size_t m_Length; }; - typedef std::map<Key, Space*, Key::Compare> SpaceMapType; + typedef std::multimap<Key, Space*, Key::Compare> SpaceMapType; private: SpaceMapType m_SpaceMap; diff --git a/include/mcld/Support/PathCache.h b/include/mcld/Support/PathCache.h index 89ec513..8da59e5 100644 --- a/include/mcld/Support/PathCache.h +++ b/include/mcld/Support/PathCache.h @@ -24,7 +24,7 @@ namespace fs { namespace { typedef HashEntry<llvm::StringRef, - mcld::sys::fs::Path*, + mcld::sys::fs::Path, StringCompare<llvm::StringRef> > HashEntryType; } // anonymous namespace diff --git a/include/mcld/Target/ELFDynamic.h b/include/mcld/Target/ELFDynamic.h index 7102226..62f534d 100644 --- a/include/mcld/Target/ELFDynamic.h +++ b/include/mcld/Target/ELFDynamic.h @@ -88,6 +88,43 @@ private: Pair m_Pair; }; +template<> +class Entry<64, true> : public EntryIF +{ +public: + typedef llvm::ELF::Elf64_Dyn Pair; + typedef llvm::ELF::Elf64_Sym Symbol; + typedef llvm::ELF::Elf64_Rel Rel; + typedef llvm::ELF::Elf64_Rela Rela; + +public: + inline Entry(); + + inline ~Entry(); + + Entry* clone() const + { return new Entry(); } + + size_t size() const + { return sizeof(Pair); } + + size_t symbolSize() const + { return sizeof(Symbol); } + + size_t relSize() const + { return sizeof(Rel); } + + size_t relaSize() const + { return sizeof(Rela); } + + inline void setValue(uint64_t pTag, uint64_t pValue); + + inline size_t emit(uint8_t* pAddress) const; + +private: + Pair m_Pair; +}; + #include "ELFDynamic.tcc" } // namespace of elf_dynamic diff --git a/include/mcld/Target/ELFDynamic.tcc b/include/mcld/Target/ELFDynamic.tcc index 8b04651..5d67be4 100644 --- a/include/mcld/Target/ELFDynamic.tcc +++ b/include/mcld/Target/ELFDynamic.tcc @@ -7,6 +7,8 @@ // //===----------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// +/// 32-bit dynamic entry Entry<32, true>::Entry() { m_Pair.d_tag = 0; @@ -31,3 +33,29 @@ size_t Entry<32, true>::emit(uint8_t* pAddress) const return sizeof(Pair); } +//===----------------------------------------------------------------------===// +/// 64-bit dynamic entry +Entry<64, true>::Entry() +{ + m_Pair.d_tag = 0; + m_Pair.d_un.d_val = 0; +} + +Entry<64, true>::~Entry() +{ +} + +void Entry<64, true>::setValue(uint64_t pTag, uint64_t pValue) +{ + m_Pair.d_tag = pTag; + m_Pair.d_un.d_val = pValue; +} + +size_t Entry<64, true>::emit(uint8_t* pAddress) const +{ + memcpy(reinterpret_cast<void*>(pAddress), + reinterpret_cast<const void*>(&m_Pair), + sizeof(Pair)); + return sizeof(Pair); +} + diff --git a/include/mcld/Target/GNUInfo.h b/include/mcld/Target/GNUInfo.h index f918431..86a29ba 100644 --- a/include/mcld/Target/GNUInfo.h +++ b/include/mcld/Target/GNUInfo.h @@ -38,6 +38,33 @@ public: /// ABIVersion - the value of e_ident[EI_ABIVRESION] uint8_t ABIVersion() const { return 0x0; } + /// defaultTextSegmentAddr - target should specify its own default start address + /// of the text segment. esp. for exec. + virtual uint64_t defaultTextSegmentAddr() const { return 0x0; } + + /// flags - the value of ElfXX_Ehdr::e_flags + virtual uint64_t flags() const = 0; + + /// entry - the symbol name of the entry point + virtual const char* entry() const { return "_start"; } + + /// dyld - the name of the default dynamic linker + /// target may override this function if needed. + /// @ref gnu ld, bfd/elf32-i386.c:521 + virtual const char* dyld() const { return "/usr/lib/libc.so.1"; } + + /// isDefaultExecStack - target should specify whether the stack is default + /// executable. If target favors another choice, please override this function + virtual bool isDefaultExecStack() const { return true; } + + /// commonPageSize - the common page size of the target machine, and we set it + /// to 4K here. If target favors the different size, please override this + virtual uint64_t commonPageSize() const { return 0x1000; } + + /// abiPageSize - the abi page size of the target machine, and we set it to 4K + /// here. If target favors the different size, please override this function + virtual uint64_t abiPageSize() const { return 0x1000; } + private: const llvm::Triple& m_Triple; }; diff --git a/include/mcld/Target/GNULDBackend.h b/include/mcld/Target/GNULDBackend.h index d20b8ac..dfcbd85 100644 --- a/include/mcld/Target/GNULDBackend.h +++ b/include/mcld/Target/GNULDBackend.h @@ -23,10 +23,7 @@ #include <mcld/LD/ELFObjectReader.h> #include <mcld/LD/ELFDynObjReader.h> #include <mcld/LD/ELFBinaryReader.h> -#include <mcld/LD/ELFDynObjWriter.h> -#include <mcld/LD/ELFExecWriter.h> #include <mcld/LD/ELFObjectWriter.h> -#include <mcld/LD/ELFBinaryWriter.h> #include <mcld/LD/ELFSegment.h> #include <mcld/LD/ELFSegmentFactory.h> #include <mcld/Target/ELFDynamic.h> @@ -41,7 +38,6 @@ class Module; class LinkerConfig; class IRBuilder; class Layout; -class EhFrame; class EhFrameHdr; class BranchIslandFactory; class StubFactory; @@ -64,10 +60,7 @@ public: ELFObjectReader* createObjectReader(IRBuilder& pBuilder); ELFDynObjReader* createDynObjReader(IRBuilder& pBuilder); ELFBinaryReader* createBinaryReader(IRBuilder& pBuilder); - ELFObjectWriter* createObjectWriter(); - ELFDynObjWriter* createDynObjWriter(); - ELFExecWriter* createExecWriter(); - ELFBinaryWriter* createBinaryWriter(); + ELFObjectWriter* createWriter(); // ----- output sections ----- // /// initStdSections - initialize standard sections of the output file. @@ -81,26 +74,26 @@ public: /// initStandardSymbols - initialize standard symbols. /// Some section symbols is undefined in input object, and linkers must set /// up its value. Take __init_array_begin for example. This symbol is an - /// undefined symbol in input objects. FragmentLinker must finalize its value + /// undefined symbol in input objects. ObjectLinker must finalize its value /// to the begin of the .init_array section, then relocation enties to /// __init_array_begin can be applied without emission of "undefined /// reference to `__init_array_begin'". - bool initStandardSymbols(FragmentLinker& pLinker, Module& pModule); + bool initStandardSymbols(IRBuilder& pBuilder, Module& pModule); /// finalizeSymbol - Linker checks pSymbol.reserved() if it's not zero, /// then it will ask backend to finalize the symbol value. /// @return ture - if backend set the symbol value sucessfully /// @return false - if backend do not recognize the symbol - bool finalizeSymbols(FragmentLinker& pLinker) { - return (finalizeStandardSymbols(pLinker) && - finalizeTargetSymbols(pLinker)); + bool finalizeSymbols() { + return (finalizeStandardSymbols() && + finalizeTargetSymbols()); } /// finalizeStandardSymbols - set the value of standard symbols - virtual bool finalizeStandardSymbols(FragmentLinker& pLinker); + virtual bool finalizeStandardSymbols(); /// finalizeTargetSymbols - set the value of target symbols - virtual bool finalizeTargetSymbols(FragmentLinker& pLinker) = 0; + virtual bool finalizeTargetSymbols() = 0; /// finalizeTLSSymbol - set the value of a TLS symbol virtual bool finalizeTLSSymbol(LDSymbol& pSymbol); @@ -110,56 +103,41 @@ public: const GNUInfo& getInfo() const { return *m_pInfo; } GNUInfo& getInfo() { return *m_pInfo; } - /// flags - the value of ElfXX_Ehdr::e_flags - virtual uint64_t flags() const = 0; + bool hasTextRel() const { return m_bHasTextRel; } - /// entry - the symbol name of the entry point - virtual const char* entry() const - { return "_start"; } - - /// dyld - the name of the default dynamic linker - /// target may override this function if needed. - /// @ref gnu ld, bfd/elf32-i386.c:521 - virtual const char* dyld() const - { return "/usr/lib/libc.so.1"; } - - /// defaultTextSegmentAddr - target should specify its own default start address - /// of the text segment. esp. for exec. - virtual uint64_t defaultTextSegmentAddr() const - { return 0x0; } - - bool hasTextRel() const - { return m_bHasTextRel; } - - bool hasStaticTLS() const - { return m_bHasStaticTLS; } + bool hasStaticTLS() const { return m_bHasStaticTLS; } /// segmentStartAddr - this function returns the start address of the segment - uint64_t segmentStartAddr(const FragmentLinker& pLinker) const; + uint64_t segmentStartAddr() const; /// partialScanRelocation - When doing partial linking, fix the relocation /// offset after section merge void partialScanRelocation(Relocation& pReloc, - FragmentLinker& pLinker, Module& pModule, const LDSection& pSection); /// sizeNamePools - compute the size of regular name pools /// In ELF executable files, regular name pools are .symtab, .strtab., /// .dynsym, .dynstr, and .hash - virtual void sizeNamePools(const Module& pModule, bool pIsStaticLink); + virtual void sizeNamePools(Module& pModule, bool pIsStaticLink); /// emitSectionData - emit target-dependent section data virtual uint64_t emitSectionData(const LDSection& pSection, MemoryRegion& pRegion) const = 0; /// emitRegNamePools - emit regular name pools - .symtab, .strtab - virtual void emitRegNamePools(const Module& pModule, - MemoryArea& pOutput); + virtual void emitRegNamePools(const Module& pModule, MemoryArea& pOutput); /// emitNamePools - emit dynamic name pools - .dyntab, .dynstr, .hash - virtual void emitDynNamePools(const Module& pModule, - MemoryArea& pOutput); + virtual void emitDynNamePools(Module& pModule, MemoryArea& pOutput); + + /// emitELFHashTab - emit .hash + virtual void emitELFHashTab(const Module::SymbolTable& pSymtab, + MemoryArea& pOutput); + + /// emitGNUHashTab - emit .gnu.hash + virtual void emitGNUHashTab(Module::SymbolTable& pSymtab, + MemoryArea& pOutput); /// sizeInterp - compute the size of program interpreter's name /// In ELF executables, this is the length of dynamic linker's path name @@ -191,48 +169,44 @@ public: /// numOfSegments - return the number of segments /// if the target favors other ways to emit program header, please override /// this function - virtual unsigned int numOfSegments() const - { return m_ELFSegmentTable.size(); } + size_t numOfSegments() const { return m_ELFSegmentTable.size(); } /// elfSegmentTable - return the reference of the elf segment table - ELFSegmentFactory& elfSegmentTable() - { return m_ELFSegmentTable; } + ELFSegmentFactory& elfSegmentTable() { return m_ELFSegmentTable; } /// elfSegmentTable - return the reference of the elf segment table - const ELFSegmentFactory& elfSegmentTable() const - { return m_ELFSegmentTable; } + const ELFSegmentFactory& elfSegmentTable() const { return m_ELFSegmentTable; } - /// commonPageSize - the common page size of the target machine, and we set it - /// to 4K here. If target favors the different size, please override this - /// function - virtual uint64_t commonPageSize() const; + /// commonPageSize - the common page size of the target machine + uint64_t commonPageSize() const; - /// abiPageSize - the abi page size of the target machine, and we set it to 4K - /// here. If target favors the different size, please override this function - virtual uint64_t abiPageSize() const; + /// abiPageSize - the abi page size of the target machine + uint64_t abiPageSize() const; /// getSymbolIdx - get the symbol index of ouput symbol table - size_t getSymbolIdx(LDSymbol* pSymbol) const; - - /// isDefaultExecStack - target should specify whether the stack is default - /// executable. If target favors another choice, please override this function - virtual bool isDefaultExecStack() const - { return true; } + size_t getSymbolIdx(const LDSymbol* pSymbol) const; /// allocateCommonSymbols - allocate common symbols in the corresponding /// sections. /// Different concrete target backend may overlap this function. virtual bool allocateCommonSymbols(Module& pModule); + /// updateSectionFlags - update pTo's flags when merging pFrom + /// update the output section flags based on input section flags. + virtual bool updateSectionFlags(LDSection& pTo, const LDSection& pFrom); + /// isSymbolPreemtible - whether the symbol can be preemted by other /// link unit /// @ref Google gold linker, symtab.h:551 bool isSymbolPreemptible(const ResolveInfo& pSym) const; + virtual ResolveInfo::Desc getSymDesc(uint16_t pShndx) const { + return ResolveInfo::Define; + } + /// symbolNeedsDynRel - return whether the symbol needs a dynamic relocation /// @ref Google gold linker, symtab.h:645 - bool symbolNeedsDynRel(const FragmentLinker& pLinker, - const ResolveInfo& pSym, + bool symbolNeedsDynRel(const ResolveInfo& pSym, bool pSymHasPLT, bool isAbsReloc) const; @@ -270,10 +244,17 @@ protected: uint64_t getSymbolShndx(const LDSymbol& pSymbol) const; + /// isTemporary - Whether pSymbol is a local label. + virtual bool isTemporary(const LDSymbol& pSymbol) const; + /// getHashBucketCount - calculate hash bucket count. /// @ref Google gold linker, dynobj.cc:791 static unsigned getHashBucketCount(unsigned pNumOfSymbols, bool pIsGNUStyle); + /// getGNUHashMaskbitslog2 - calculate the number of mask bits in log2 + /// @ref binutils gold, dynobj.cc:1165 + unsigned getGNUHashMaskbitslog2(unsigned pNumOfSymbols) const; + /// isDynamicSymbol /// @ref Google gold linker: symtab.cc:311 bool isDynamicSymbol(const LDSymbol& pSymbol); @@ -284,18 +265,15 @@ protected: /// symbolNeedsPLT - return whether the symbol needs a PLT entry /// @ref Google gold linker, symtab.h:596 - bool symbolNeedsPLT(const FragmentLinker& pLinker, - const ResolveInfo& pSym) const; + bool symbolNeedsPLT(const ResolveInfo& pSym) const; /// symbolNeedsCopyReloc - return whether the symbol needs a copy relocation - bool symbolNeedsCopyReloc(const FragmentLinker& pLinker, - const Relocation& pReloc, + bool symbolNeedsCopyReloc(const Relocation& pReloc, const ResolveInfo& pSym) const; /// symbolHasFinalValue - return true if the symbol's value can be decided at /// link time - bool symbolFinalValueIsKnown(const FragmentLinker& pLinker, - const ResolveInfo& pSym) const; + bool symbolFinalValueIsKnown(const ResolveInfo& pSym) const; /// emitSymbol32 - emit an ELF32 symbol void emitSymbol32(llvm::ELF::Elf32_Sym& pSym32, @@ -314,21 +292,19 @@ protected: /// checkAndSetHasTextRel - check pSection flag to set HasTextRel void checkAndSetHasTextRel(const LDSection& pSection); - void setHasStaticTLS(bool pVal = true) - { m_bHasStaticTLS = pVal; } + void setHasStaticTLS(bool pVal = true) { m_bHasStaticTLS = pVal; } private: /// createProgramHdrs - base on output sections to create the program headers - void createProgramHdrs(Module& pModule, const FragmentLinker& pLinker); + void createProgramHdrs(Module& pModule); /// doCreateProgramHdrs - backend can implement this function to create the /// target-dependent segments - virtual void doCreateProgramHdrs(Module& pModule, - const FragmentLinker& pLinker) = 0; + virtual void doCreateProgramHdrs(Module& pModule) = 0; /// setupProgramHdrs - set up the attributes of segments /// (i.e., offset, addresses, file/mem size, flag, and alignment) - void setupProgramHdrs(const FragmentLinker& pLinker); + void setupProgramHdrs(); /// getSegmentFlag - give a section flag and return the corresponding segment /// flag @@ -343,7 +319,7 @@ private: } /// setupGNUStackInfo - setup the section flag of .note.GNU-stack in output - void setupGNUStackInfo(Module& pModule, FragmentLinker& pLinker); + void setupGNUStackInfo(Module& pModule); /// setupRelro - setup the offset constraint of PT_RELRO void setupRelro(Module& pModule); @@ -356,28 +332,27 @@ private: uint64_t pStartOffset = -1U); /// setOutputSectionOffset - helper function to set output sections' address. - void setOutputSectionAddress(FragmentLinker& pLinker, - Module& pModule, + void setOutputSectionAddress(Module& pModule, Module::iterator pSectBegin, Module::iterator pSectEnd); /// layout - layout method - void layout(Module& pModule, FragmentLinker& pLinker); + void layout(Module& pModule); /// preLayout - Backend can do any needed modification before layout - void preLayout(Module& pModule, FragmentLinker& pLinker); + void preLayout(Module& pModule, IRBuilder& pBuilder); /// postLayout -Backend can do any needed modification after layout - void postLayout(Module& pModule, FragmentLinker& pLinker); + void postLayout(Module& pModule, IRBuilder& pBuilder); /// preLayout - Backend can do any needed modification before layout - virtual void doPreLayout(FragmentLinker& pLinker) = 0; + virtual void doPreLayout(IRBuilder& pBuilder) = 0; /// postLayout -Backend can do any needed modification after layout - virtual void doPostLayout(Module& pModule, FragmentLinker& pLinker) = 0; + virtual void doPostLayout(Module& pModule, IRBuilder& pLinker) = 0; /// postProcessing - Backend can do any needed modification in the final stage - void postProcessing(FragmentLinker& pLinker, MemoryArea& pOutput); + void postProcessing(MemoryArea& pOutput); /// dynamic - the dynamic section of the target machine. virtual ELFDynamic& dynamic() = 0; @@ -386,7 +361,7 @@ private: virtual const ELFDynamic& dynamic() const = 0; /// relax - the relaxation pass - bool relax(Module& pModule, FragmentLinker& pLinker); + bool relax(Module& pModule, IRBuilder& pBuilder); /// mayRelax - Backends should override this function if they need relaxation virtual bool mayRelax() { return false; } @@ -395,7 +370,7 @@ private: /// implementation. Return true if the output (e.g., .text) is "relaxed" /// (i.e. layout is changed), and set pFinished to true if everything is fit, /// otherwise set it to false. - virtual bool doRelax(Module& pModule, FragmentLinker& pLinker, bool& pFinished) + virtual bool doRelax(Module& pModule, IRBuilder& pBuilder, bool& pFinished) { return false; } /// getRelEntrySize - the size in BYTE of rel type relocation @@ -450,6 +425,14 @@ protected: { return (X==Y); } }; + // for gnu style hash table + struct DynsymCompare + { + bool needGNUHash(const LDSymbol& X) const; + + bool operator()(const LDSymbol* X, const LDSymbol* Y) const; + }; + struct SymPtrHash { size_t operator()(const LDSymbol* pKey) const @@ -488,9 +471,6 @@ protected: // map the LDSymbol to its index in the output symbol table HashTableType* m_pSymIndexMap; - /// m_pEhFrame - section .eh_frame - EhFrame* m_pEhFrame; - // section .eh_frame_hdr EhFrameHdr* m_pEhFrameHdr; diff --git a/include/mcld/Target/TargetLDBackend.h b/include/mcld/Target/TargetLDBackend.h index 10cf280..1690004 100644 --- a/include/mcld/Target/TargetLDBackend.h +++ b/include/mcld/Target/TargetLDBackend.h @@ -16,7 +16,6 @@ namespace mcld { class Module; class LinkerConfig; class IRBuilder; -class FragmentLinker; class Relocation; class RelocationFactory; class Relocator; @@ -56,13 +55,13 @@ public: virtual ~TargetLDBackend(); // ----- target dependent ----- // - virtual void initTargetSegments(FragmentLinker& pLinker) { } + virtual void initTargetSegments(IRBuilder& pBuilder) { } virtual void initTargetSections(Module& pModule, ObjectBuilder& pBuilder) { } - virtual void initTargetSymbols(FragmentLinker& pLinker) { } - virtual void initTargetRelocation(FragmentLinker& pLinker) { } - virtual bool initStandardSymbols(FragmentLinker& pLinker, Module& pModule) = 0; + virtual void initTargetSymbols(IRBuilder& pBuilder, Module& pModule) { } + virtual void initTargetRelocation(IRBuilder& pBuilder) { } + virtual bool initStandardSymbols(IRBuilder& pBuilder, Module& pModule) = 0; - virtual bool initRelocator(const FragmentLinker& pLinker) = 0; + virtual bool initRelocator() = 0; virtual Relocator* getRelocator() = 0; @@ -74,9 +73,9 @@ public: /// @param pInputSym - the input LDSymbol of relocation target symbol /// @param pSection - the section of relocation applying target virtual void scanRelocation(Relocation& pReloc, - FragmentLinker& pLinker, + IRBuilder& pBuilder, Module& pModule, - const LDSection& pSection) = 0; + LDSection& pSection) = 0; /// partialScanRelocation - When doing partial linking, backend can do any /// modification to relocation to fix the relocation offset after section @@ -85,7 +84,6 @@ public: /// @param pInputSym - the input LDSymbol of relocation target symbol /// @param pSection - the section of relocation applying target virtual void partialScanRelocation(Relocation& pReloc, - FragmentLinker& pLinker, Module& pModule, const LDSection& pSection) = 0; @@ -94,31 +92,21 @@ public: virtual ObjectReader* createObjectReader(IRBuilder&) = 0; virtual DynObjReader* createDynObjReader(IRBuilder&) = 0; virtual BinaryReader* createBinaryReader(IRBuilder&) = 0; - virtual ObjectWriter* createObjectWriter() = 0; - virtual DynObjWriter* createDynObjWriter() = 0; - virtual ExecWriter* createExecWriter() = 0; - virtual BinaryWriter* createBinaryWriter() = 0; + virtual ObjectWriter* createWriter() = 0; virtual bool initStdSections(ObjectBuilder& pBuilder) = 0; /// layout - layout method - virtual void layout(Module& pModule, FragmentLinker& pLinker) = 0; + virtual void layout(Module& pModule) = 0; /// preLayout - Backend can do any needed modification before layout - virtual void preLayout(Module& pModule, FragmentLinker& pLinker) = 0; + virtual void preLayout(Module& pModule, IRBuilder& pBuilder) = 0; - /// postLayout -Backend can do any needed modification after layout - virtual void postLayout(Module& pModule, FragmentLinker& pLinker) = 0; + /// postLayout - Backend can do any needed modification after layout + virtual void postLayout(Module& pModule, IRBuilder& pBuilder) = 0; /// postProcessing - Backend can do any needed modification in the final stage - virtual void postProcessing(FragmentLinker& pLinker, - MemoryArea& pOutput) = 0; - - /// the common page size of the target machine - virtual uint64_t commonPageSize() const = 0; - - /// the abi page size of the target machine - virtual uint64_t abiPageSize() const = 0; + virtual void postProcessing(MemoryArea& pOutput) = 0; /// section start offset in the output file virtual size_t sectionStartOffset() const = 0; @@ -129,14 +117,13 @@ public: /// sizeNamePools - compute the size of regular name pools /// In ELF executable files, regular name pools are .symtab, .strtab., /// .dynsym, .dynstr, and .hash - virtual void - sizeNamePools(const Module& pModule, bool pIsStaticLink) = 0; + virtual void sizeNamePools(Module& pModule, bool pIsStaticLink) = 0; /// finalizeSymbol - Linker checks pSymbol.reserved() if it's not zero, /// then it will ask backend to finalize the symbol value. /// @return ture - if backend set the symbol value sucessfully /// @return false - if backend do not recognize the symbol - virtual bool finalizeSymbols(FragmentLinker& pLinker) = 0; + virtual bool finalizeSymbols() = 0; /// finalizeTLSSymbol - Linker asks backend to set the symbol value when it /// meets a TLS symbol @@ -150,13 +137,17 @@ public: virtual bool mergeSection(Module& pModule, LDSection& pInputSection) { return true; } + /// updateSectionFlags - update pTo's flags when merging pFrom + /// update the output section flags based on input section flags. + /// FIXME: (Luba) I know ELF need to merge flags, but I'm not sure if + /// MachO and COFF also need this. + virtual bool updateSectionFlags(LDSection& pTo, const LDSection& pFrom) + { return true; } + /// readSection - read a target dependent section virtual bool readSection(Input& pInput, SectionData& pSD) { return true; } - /// dyld - the name of the default dynamic linker - virtual const char* dyld() const = 0; - /// sizeInterp - compute the size of program interpreter's name /// In ELF executables, this is the length of dynamic linker's path name virtual void sizeInterp() = 0; @@ -164,13 +155,13 @@ public: // ----- relaxation ----- // virtual bool initBRIslandFactory() = 0; virtual bool initStubFactory() = 0; - virtual bool initTargetStubs(FragmentLinker& pLinker) { return true; } + virtual bool initTargetStubs() { return true; } virtual BranchIslandFactory* getBRIslandFactory() = 0; virtual StubFactory* getStubFactory() = 0; /// relax - the relaxation pass - virtual bool relax(Module& pModule, FragmentLinker& pLinker) = 0; + virtual bool relax(Module& pModule, IRBuilder& pBuilder) = 0; /// mayRelax - return true if the backend needs to do relaxation virtual bool mayRelax() = 0; diff --git a/lib/CodeGen/MCLDTargetMachine.cpp b/lib/CodeGen/MCLDTargetMachine.cpp index 785ef1f..57da5b5 100644 --- a/lib/CodeGen/MCLDTargetMachine.cpp +++ b/lib/CodeGen/MCLDTargetMachine.cpp @@ -214,8 +214,6 @@ bool mcld::MCLDTargetMachine::addPassesToEmitFile(PassManagerBase &pPM, pOutput.formatted_os(), Context)) return true; - - pPM.add(createGCInfoDeleter()); // not in addPassesToMC break; } case CGFT_OBJFile: { @@ -227,8 +225,6 @@ bool mcld::MCLDTargetMachine::addPassesToEmitFile(PassManagerBase &pPM, pOutput.mem_os(), Context)) return true; - - pPM.add(createGCInfoDeleter()); // not in addPassesToMC break; } case CGFT_EXEFile: { diff --git a/lib/CodeGen/MCLinker.cpp b/lib/CodeGen/MCLinker.cpp index 6b7196b..3613a03 100644 --- a/lib/CodeGen/MCLinker.cpp +++ b/lib/CodeGen/MCLinker.cpp @@ -382,6 +382,7 @@ void MCLinker::initializeInputTree(IRBuilder& pBuilder) std::vector<InputAction*>::iterator action, actionEnd = actions.end(); for (action = actions.begin(); action != actionEnd; ++action) { (*action)->activate(pBuilder.getInputBuilder()); + delete *action; } if (pBuilder.getInputBuilder().isInGroup()) diff --git a/lib/Core/GeneralOptions.cpp b/lib/Core/GeneralOptions.cpp index d762237..f29ab1d 100644 --- a/lib/Core/GeneralOptions.cpp +++ b/lib/Core/GeneralOptions.cpp @@ -41,7 +41,6 @@ GeneralOptions::GeneralOptions() m_Bgroup(false), m_bPIE(false), m_bColor(true), - m_bAllowShlibUndefined(true), m_bCreateEhFrameHdr(false), m_bNMagic(false), m_bOMagic(false), @@ -50,8 +49,11 @@ GeneralOptions::GeneralOptions() m_bWarnSharedTextrel(false), m_bBinaryInput(false), m_bDefineCommon(false), - m_bFatalWarnings(false) -{ + m_bFatalWarnings(false), + m_bNewDTags(false), + m_bNoStdlib(false), + m_StripSymbols(KeepAllSymbols), + m_HashStyle(SystemV) { } GeneralOptions::~GeneralOptions() @@ -82,6 +84,11 @@ void GeneralOptions::setSysroot(const mcld::sys::fs::Path &pSysroot) m_SearchDirs.setSysRoot(pSysroot); } +bool GeneralOptions::hasSysroot() const +{ + return !sysroot().empty(); +} + void GeneralOptions::setSOName(const std::string& pName) { size_t pos = pName.find_last_of(sys::fs::separator); diff --git a/lib/Core/IRBuilder.cpp b/lib/Core/IRBuilder.cpp index 5472db0..549aa8d 100644 --- a/lib/Core/IRBuilder.cpp +++ b/lib/Core/IRBuilder.cpp @@ -83,7 +83,7 @@ LDFileFormat::Kind GetELFSectionKind(uint32_t pType, const char* pName) return LDFileFormat::MetaData; } -bool shouldForceLocal(const ResolveInfo& pInfo, const LinkerConfig& pConfig) +bool ShouldForceLocal(const ResolveInfo& pInfo, const LinkerConfig& pConfig) { // forced local symbol matches all rules: // 1. We are not doing incremental linking. @@ -333,7 +333,7 @@ EhFrame* IRBuilder::CreateEhFrame(LDSection& pSection) { assert(!pSection.hasEhFrame() && "pSection already has eh_frame."); - EhFrame* eh_frame = new EhFrame(pSection); + EhFrame* eh_frame = EhFrame::Create(pSection); pSection.setEhFrame(eh_frame); return eh_frame; } @@ -471,13 +471,14 @@ LDSymbol* IRBuilder::AddSymbol(Input& pInput, return input_sym; } case Input::DynObj: { - return addSymbolFromDynObj(name, pType, pDesc, pBind, pSize, pValue, pVis); + return addSymbolFromDynObj(pInput, name, pType, pDesc, pBind, pSize, pValue, pVis); } default: { return NULL; break; } } + return NULL; } LDSymbol* IRBuilder::addSymbolFromObject(const std::string& pName, @@ -564,7 +565,7 @@ LDSymbol* IRBuilder::addSymbolFromObject(const std::string& pName, // No matter the symbol is already in the output or not, add it if it // should be forcefully set local. - if (shouldForceLocal(*resolved_result.info, m_Config)) + if (ShouldForceLocal(*resolved_result.info, m_Config)) m_Module.getSymbolTable().forceLocal(*output_sym); else { // the symbol should not be forcefully local. @@ -572,8 +573,8 @@ LDSymbol* IRBuilder::addSymbolFromObject(const std::string& pName, } } else if (resolved_result.overriden) { - if (!shouldForceLocal(old_info, m_Config) || - !shouldForceLocal(*resolved_result.info, m_Config)) { + if (!ShouldForceLocal(old_info, m_Config) || + !ShouldForceLocal(*resolved_result.info, m_Config)) { // If the old info and the new info are both forcefully local, then // we should keep the output_sym in forcefully local category. Else, // we should re-sort the output_sym @@ -585,7 +586,8 @@ LDSymbol* IRBuilder::addSymbolFromObject(const std::string& pName, return input_sym; } -LDSymbol* IRBuilder::addSymbolFromDynObj(const std::string& pName, +LDSymbol* IRBuilder::addSymbolFromDynObj(Input& pInput, + const std::string& pName, ResolveInfo::Type pType, ResolveInfo::Desc pDesc, ResolveInfo::Binding pBinding, @@ -619,6 +621,9 @@ LDSymbol* IRBuilder::addSymbolFromDynObj(const std::string& pName, // the return ResolveInfo should not NULL assert(NULL != resolved_result.info); + if (resolved_result.overriden || !resolved_result.existent) + pInput.setNeeded(); + // create a LDSymbol for the input file. LDSymbol* input_sym = LDSymbol::Create(*resolved_result.info); input_sym->setFragmentRef(FragmentRef::Null()); @@ -638,7 +643,7 @@ LDSymbol* IRBuilder::addSymbolFromDynObj(const std::string& pName, // After symbol resolution, visibility is changed to the most restrict one. // If we are not doing incremental linking, then any symbol with hidden // or internal visibility is forcefully set as a local symbol. - if (shouldForceLocal(*resolved_result.info, m_Config)) { + if (ShouldForceLocal(*resolved_result.info, m_Config)) { m_Module.getSymbolTable().forceLocal(*output_sym); } } @@ -674,3 +679,190 @@ Relocation* IRBuilder::AddRelocation(LDSection& pSection, return relocation; } +/// AddSymbol - define an output symbol and override it immediately +template<> LDSymbol* +IRBuilder::AddSymbol<IRBuilder::Force, IRBuilder::Unresolve>( + const llvm::StringRef& pName, + ResolveInfo::Type pType, + ResolveInfo::Desc pDesc, + ResolveInfo::Binding pBinding, + ResolveInfo::SizeType pSize, + LDSymbol::ValueType pValue, + FragmentRef* pFragmentRef, + ResolveInfo::Visibility pVisibility) +{ + ResolveInfo* info = m_Module.getNamePool().findInfo(pName); + LDSymbol* output_sym = NULL; + if (NULL == info) { + // the symbol is not in the pool, create a new one. + // create a ResolveInfo + Resolver::Result result; + m_Module.getNamePool().insertSymbol(pName, false, pType, pDesc, + pBinding, pSize, pVisibility, + NULL, result); + assert(!result.existent); + + // create a output LDSymbol + output_sym = LDSymbol::Create(*result.info); + result.info->setSymPtr(output_sym); + + if (ShouldForceLocal(*result.info, m_Config)) + m_Module.getSymbolTable().forceLocal(*output_sym); + else + m_Module.getSymbolTable().add(*output_sym); + } + else { + // the symbol is already in the pool, override it + ResolveInfo old_info; + old_info.override(*info); + + info->setRegular(); + info->setType(pType); + info->setDesc(pDesc); + info->setBinding(pBinding); + info->setVisibility(pVisibility); + info->setIsSymbol(true); + info->setSize(pSize); + + output_sym = info->outSymbol(); + if (NULL != output_sym) + m_Module.getSymbolTable().arrange(*output_sym, old_info); + else { + // create a output LDSymbol + output_sym = LDSymbol::Create(*info); + info->setSymPtr(output_sym); + + m_Module.getSymbolTable().add(*output_sym); + } + } + + if (NULL != output_sym) { + output_sym->setFragmentRef(pFragmentRef); + output_sym->setValue(pValue); + } + + return output_sym; +} + +/// AddSymbol - define an output symbol and override it immediately +template<> LDSymbol* +IRBuilder::AddSymbol<IRBuilder::AsReferred, IRBuilder::Unresolve>( + const llvm::StringRef& pName, + ResolveInfo::Type pType, + ResolveInfo::Desc pDesc, + ResolveInfo::Binding pBinding, + ResolveInfo::SizeType pSize, + LDSymbol::ValueType pValue, + FragmentRef* pFragmentRef, + ResolveInfo::Visibility pVisibility) +{ + ResolveInfo* info = m_Module.getNamePool().findInfo(pName); + + if (NULL == info || !(info->isUndef() || info->isDyn())) { + // only undefined symbol and dynamic symbol can make a reference. + return NULL; + } + + // the symbol is already in the pool, override it + ResolveInfo old_info; + old_info.override(*info); + + info->setRegular(); + info->setType(pType); + info->setDesc(pDesc); + info->setBinding(pBinding); + info->setVisibility(pVisibility); + info->setIsSymbol(true); + info->setSize(pSize); + + LDSymbol* output_sym = info->outSymbol(); + if (NULL != output_sym) { + output_sym->setFragmentRef(pFragmentRef); + output_sym->setValue(pValue); + m_Module.getSymbolTable().arrange(*output_sym, old_info); + } + else { + // create a output LDSymbol + output_sym = LDSymbol::Create(*info); + info->setSymPtr(output_sym); + + m_Module.getSymbolTable().add(*output_sym); + } + + return output_sym; +} + +/// AddSymbol - define an output symbol and resolve it +/// immediately +template<> LDSymbol* +IRBuilder::AddSymbol<IRBuilder::Force, IRBuilder::Resolve>( + const llvm::StringRef& pName, + ResolveInfo::Type pType, + ResolveInfo::Desc pDesc, + ResolveInfo::Binding pBinding, + ResolveInfo::SizeType pSize, + LDSymbol::ValueType pValue, + FragmentRef* pFragmentRef, + ResolveInfo::Visibility pVisibility) +{ + // Result is <info, existent, override> + Resolver::Result result; + ResolveInfo old_info; + m_Module.getNamePool().insertSymbol(pName, false, pType, pDesc, pBinding, + pSize, pVisibility, + &old_info, result); + + LDSymbol* output_sym = result.info->outSymbol(); + bool has_output_sym = (NULL != output_sym); + + if (!result.existent || !has_output_sym) { + output_sym = LDSymbol::Create(*result.info); + result.info->setSymPtr(output_sym); + } + + if (result.overriden || !has_output_sym) { + output_sym->setFragmentRef(pFragmentRef); + output_sym->setValue(pValue); + } + + // After symbol resolution, the visibility is changed to the most restrict. + // arrange the output position + if (ShouldForceLocal(*result.info, m_Config)) + m_Module.getSymbolTable().forceLocal(*output_sym); + else if (has_output_sym) + m_Module.getSymbolTable().arrange(*output_sym, old_info); + else + m_Module.getSymbolTable().add(*output_sym); + + return output_sym; +} + +/// defineSymbol - define an output symbol and resolve it immediately. +template<> LDSymbol* +IRBuilder::AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>( + const llvm::StringRef& pName, + ResolveInfo::Type pType, + ResolveInfo::Desc pDesc, + ResolveInfo::Binding pBinding, + ResolveInfo::SizeType pSize, + LDSymbol::ValueType pValue, + FragmentRef* pFragmentRef, + ResolveInfo::Visibility pVisibility) +{ + ResolveInfo* info = m_Module.getNamePool().findInfo(pName); + + if (NULL == info || !(info->isUndef() || info->isDyn())) { + // only undefined symbol and dynamic symbol can make a reference. + return NULL; + } + + return AddSymbol<Force, Resolve>(pName, + pType, + pDesc, + pBinding, + pSize, + pValue, + pFragmentRef, + pVisibility); +} + diff --git a/lib/Core/Linker.cpp b/lib/Core/Linker.cpp index 9f6449e..d0c9b2e 100644 --- a/lib/Core/Linker.cpp +++ b/lib/Core/Linker.cpp @@ -32,7 +32,7 @@ using namespace mcld; Linker::Linker() - : m_pConfig(NULL), m_pModule(NULL), m_pIRBuilder(NULL), + : m_pConfig(NULL), m_pIRBuilder(NULL), m_pTarget(NULL), m_pBackend(NULL), m_pObjLinker(NULL) { } @@ -51,6 +51,9 @@ bool Linker::config(LinkerConfig& pConfig) if (!initBackend()) return false; + m_pObjLinker = new ObjectLinker(*m_pConfig, + *m_pBackend); + if (!initEmulator()) return false; @@ -62,13 +65,19 @@ bool Linker::config(LinkerConfig& pConfig) bool Linker::link(Module& pModule, IRBuilder& pBuilder) { + if (!resolve(pModule, pBuilder)) + return false; + + return layout(); +} + +bool Linker::resolve(Module& pModule, IRBuilder& pBuilder) +{ assert(NULL != m_pConfig); m_pIRBuilder = &pBuilder; - m_pObjLinker = new ObjectLinker(*m_pConfig, - pModule, - *m_pIRBuilder, - *m_pBackend); + assert(m_pObjLinker!=NULL); + m_pObjLinker->setup(pModule, pBuilder); // 2. - initialize FragmentLinker if (!m_pObjLinker->initFragmentLinker()) @@ -78,7 +87,13 @@ bool Linker::link(Module& pModule, IRBuilder& pBuilder) if (!m_pObjLinker->initStdSections()) return false; + if (!Diagnose()) + return false; + // 4. - normalize the input tree + // read out sections and symbol/string tables (from the files) and + // set them in Module. When reading out the symbol, resolve their symbols + // immediately and set their ResolveInfo (i.e., Symbol Resolution). m_pObjLinker->normalize(); if (m_pConfig->options().trace()) { @@ -112,39 +127,80 @@ bool Linker::link(Module& pModule, IRBuilder& pBuilder) } } - // 5. - check if we can do static linking and if we use split-stack. + // 5. - set up code position + if (LinkerConfig::DynObj == m_pConfig->codeGenType() || + m_pConfig->options().isPIE()) { + m_pConfig->setCodePosition(LinkerConfig::Independent); + } + else if (pModule.getLibraryList().empty()) { + // If the output is dependent on its loaded address, and it does not need + // to call outside functions, then we can treat the output static dependent + // and perform better optimizations. + m_pConfig->setCodePosition(LinkerConfig::StaticDependent); + } + else { + m_pConfig->setCodePosition(LinkerConfig::DynamicDependent); + } + if (!m_pObjLinker->linkable()) return Diagnose(); // 6. - read all relocation entries from input files + // For all relocation sections of each input file (in the tree), + // read out reloc entry info from the object file and accordingly + // initiate their reloc entries in SectOrRelocData of LDSection. m_pObjLinker->readRelocations(); // 7. - merge all sections + // Push sections into Module's SectionTable. + // Merge sections that have the same name. + // Maintain them as fragments in the section. if (!m_pObjLinker->mergeSections()) return false; - // 8. - add standard symbols and target-dependent symbols + // 8. - allocateCommonSymbols + // Allocate fragments for common symbols to the corresponding sections. + if (!m_pObjLinker->allocateCommonSymbols()) + return false; + return true; +} + +bool Linker::layout() +{ + assert(NULL != m_pConfig && NULL != m_pObjLinker); + + // 9. - add standard symbols, target-dependent symbols and script symbols // m_pObjLinker->addUndefSymbols(); if (!m_pObjLinker->addStandardSymbols() || - !m_pObjLinker->addTargetSymbols()) + !m_pObjLinker->addTargetSymbols() || + !m_pObjLinker->addScriptSymbols()) return false; - // 9. - scan all relocation entries by output symbols. + // 10. - scan all relocation entries by output symbols. + // reserve GOT space for layout. + // the space info is needed by pre-layout to compute the section size m_pObjLinker->scanRelocations(); - // 10.a - pre-layout + // 11.a - init relaxation stuff. + m_pObjLinker->initStubs(); + + // 11.b - pre-layout m_pObjLinker->prelayout(); - // 10.b - linear layout + // 11.c - linear layout + // Decide which sections will be left in. Sort the sections according to + // a given order. Then, create program header accordingly. + // Finally, set the offset for sections (@ref LDSection) + // according to the new order. m_pObjLinker->layout(); - // 10.c - post-layout (create segment, instruction relaxing) + // 11.d - post-layout (create segment, instruction relaxing) m_pObjLinker->postlayout(); - // 11. - finalize symbol value + // 12. - finalize symbol value m_pObjLinker->finalizeSymbolValue(); - // 12. - apply relocations + // 13. - apply relocations m_pObjLinker->relocation(); if (!Diagnose()) @@ -202,7 +258,6 @@ bool Linker::emit(int pFileDescriptor) bool Linker::reset() { m_pConfig = NULL; - m_pModule = NULL; m_pIRBuilder = NULL; m_pTarget = NULL; @@ -210,6 +265,7 @@ bool Linker::reset() // RelocData before deleting target backend. RelocData::Clear(); SectionData::Clear(); + EhFrame::Clear(); delete m_pBackend; m_pBackend = NULL; diff --git a/lib/Core/LinkerConfig.cpp b/lib/Core/LinkerConfig.cpp index cbdb7a7..63609fa 100644 --- a/lib/Core/LinkerConfig.cpp +++ b/lib/Core/LinkerConfig.cpp @@ -22,7 +22,8 @@ LinkerConfig::LinkerConfig() m_Targets(), m_Bitcode(), m_Attribute(), - m_CodeGenType(Unknown) + m_CodeGenType(Unknown), + m_CodePosition(DynamicDependent) { // FIXME: is here the right place to hold this? InitializeDiagnosticEngine(*this); @@ -34,7 +35,8 @@ LinkerConfig::LinkerConfig(const std::string& pTripleString) m_Targets(pTripleString), m_Bitcode(), m_Attribute(), - m_CodeGenType(Unknown) + m_CodeGenType(Unknown), + m_CodePosition(DynamicDependent) { // FIXME: is here the right place to hold this? InitializeDiagnosticEngine(*this); diff --git a/lib/Fragment/Android.mk b/lib/Fragment/Android.mk index 0da2051..6e875a8 100644 --- a/lib/Fragment/Android.mk +++ b/lib/Fragment/Android.mk @@ -2,6 +2,7 @@ LOCAL_PATH:= $(call my-dir) mcld_fragment_SRC_FILES := \ AlignFragment.cpp \ + FGNode.cpp \ FillFragment.cpp \ Fragment.cpp \ FragmentLinker.cpp \ diff --git a/lib/Fragment/FGNode.cpp b/lib/Fragment/FGNode.cpp new file mode 100644 index 0000000..92706ba --- /dev/null +++ b/lib/Fragment/FGNode.cpp @@ -0,0 +1,40 @@ +//===- FGNode.cpp ---------------------------------------------------------===// +// +// The MCLinker Project +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#include <mcld/Fragment/FGNode.h> + +using namespace mcld; + +//===----------------------------------------------------------------------===// +// FGNode +//===----------------------------------------------------------------------===// +FGNode::FGNode() + : m_Index(0x0) +{ +} + +FGNode::FGNode(uint32_t pIndex) + : m_Index(pIndex) +{ +} + +void FGNode::addFragment(Fragment* pFrag) +{ + m_Fragments.push_back(pFrag); +} + +void FGNode::addSignal(Signal pSignal) +{ + m_Signals.push_back(pSignal); +} + +void FGNode::addSlot(Slot pSlot) +{ + m_Slots.push_back(pSlot); +} + diff --git a/lib/Fragment/FragmentGraph.cpp b/lib/Fragment/FragmentGraph.cpp new file mode 100644 index 0000000..3140447 --- /dev/null +++ b/lib/Fragment/FragmentGraph.cpp @@ -0,0 +1,412 @@ +//===- FragmentGraph.cpp --------------------------------------------------===// +// +// The MCLinker Project +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#include <mcld/Fragment/FragmentGraph.h> +#include <mcld/Fragment/Fragment.h> +#include <mcld/Fragment/Relocation.h> +#include <mcld/LD/LDContext.h> +#include <mcld/LD/LDFileFormat.h> +#include <mcld/LD/LDSection.h> +#include <mcld/LD/LDSymbol.h> +#include <mcld/LD/SectionData.h> +#include <mcld/LD/RelocData.h> +#include <mcld/LinkerConfig.h> +#include <mcld/Module.h> +#include <mcld/Support/MsgHandling.h> + +#include <llvm/Support/Casting.h> +#include <llvm/Support/ELF.h> + +#include <iostream> + +using namespace mcld; + +//===----------------------------------------------------------------------===// +// non-member functions +//===----------------------------------------------------------------------===// +static int get_state(Fragment::Type pKind) +{ + switch(pKind) { + case Fragment::Alignment: + return 0; + case Fragment::Fillment: + case Fragment::Region: + return 1; + case Fragment::Null: + return 2; + default: + unreachable(diag::unexpected_frag_type) << pKind; + } + return 0; +} + +//===----------------------------------------------------------------------===// +// ReachMatrix +//===----------------------------------------------------------------------===// +FragmentGraph::ReachMatrix::ReachMatrix(size_t pSize) +{ + assert(pSize != 0); + m_Data.assign(pSize * pSize, 0x0); + m_N = pSize; +} + +uint32_t& FragmentGraph::ReachMatrix::at(uint32_t pX, uint32_t pY) +{ + return m_Data[pX * m_N + pY]; +} + +uint32_t FragmentGraph::ReachMatrix::at(uint32_t pX, uint32_t pY) const +{ + return m_Data[pX * m_N + pY]; +} + +//===----------------------------------------------------------------------===// +// FragmentGraph +//===----------------------------------------------------------------------===// +FragmentGraph::FragmentGraph() + : m_pMatrix(NULL), m_NumOfPNodes(0x0), m_NumOfRNodes(0x0), m_NumOfEdges(0x0) +{ + m_pPseudoNodeFactory = new NodeFactoryType(); + m_pRegularNodeFactory = new NodeFactoryType(); + m_pFragNodeMap = new FragHashTableType(256); + m_pSymNodeMap = new SymHashTableType(256); +} + +FragmentGraph::~FragmentGraph() +{ + delete m_pPseudoNodeFactory; + delete m_pRegularNodeFactory; + delete m_pFragNodeMap; +} + +FGNode* FragmentGraph::getNode(const Fragment& pFrag) +{ + FragHashTableType::iterator entry = m_pFragNodeMap->find(&pFrag); + if (entry == m_pFragNodeMap->end()) + return NULL; + return entry.getEntry()->value(); +} + +const FGNode* FragmentGraph::getNode(const Fragment& pFrag) const +{ + FragHashTableType::iterator entry = m_pFragNodeMap->find(&pFrag); + if (entry == m_pFragNodeMap->end()) + return NULL; + return entry.getEntry()->value(); +} + +FGNode* FragmentGraph::getNode(const ResolveInfo& pSym) +{ + SymHashTableType::iterator entry = m_pSymNodeMap->find(&pSym); + if (entry == m_pSymNodeMap->end()) + return NULL; + return entry.getEntry()->value(); +} + +const FGNode* FragmentGraph::getNode(const ResolveInfo& pSym) const +{ + SymHashTableType::iterator entry = m_pSymNodeMap->find(&pSym); + if (entry == m_pSymNodeMap->end()) + return NULL; + return entry.getEntry()->value(); +} + +FGNode* FragmentGraph::producePseudoNode() +{ + FGNode* result = m_pPseudoNodeFactory->allocate(); + new (result) FGNode(m_NumOfPNodes + m_NumOfRNodes); + ++m_NumOfPNodes; + return result; +} + +FGNode* FragmentGraph::produceRegularNode() +{ + FGNode* result = m_pRegularNodeFactory->allocate(); + new (result) FGNode(m_NumOfPNodes + m_NumOfRNodes); + ++m_NumOfRNodes; + return result; +} + +bool FragmentGraph::setNodeSlots(Module& pModule) +{ + // symbols are the slots of nodes, push the symbols into the corresponding + // nodes. + + // Traverse all defined symbols, including global and local symbols, to add + // symbols into the corresponding nodes + Module::SymbolTable& sym_tab = pModule.getSymbolTable(); + SymbolCategory::iterator sym_it, sym_end = sym_tab.end(); + for (sym_it = sym_tab.begin(); sym_it != sym_end; ++sym_it) { + // only the defined symbols with FragmnentRef can form a slot. The defined + // symbol with no FragmentRef such as ABS symbol should be skipped + LDSymbol* sym = *sym_it; + if (!sym->resolveInfo()->isDefine() || + !sym->hasFragRef()) + continue; + + // FIXME: judge by getNode() is NULL or not + LDFileFormat::Kind sect_kind = + sym->fragRef()->frag()->getParent()->getSection().kind(); + if (sect_kind != LDFileFormat::Regular && + sect_kind != LDFileFormat::BSS) + continue; + + FGNode* node = getNode(*sym->fragRef()->frag()); + assert(NULL != node); + node->addSlot(sym->resolveInfo()); + } + + return true; +} + +bool FragmentGraph::createRegularEdges(Module& pModule) +{ + // The reference between nodes are presented by the relocations. Set the + // reachability matrix to present the connection + + // Traverse all input relocations to set connection + Module::obj_iterator input, inEnd = pModule.obj_end(); + for (input = pModule.obj_begin(); input != inEnd; ++input) { + LDContext::sect_iterator rs, rsEnd = (*input)->context()->relocSectEnd(); + for (rs = (*input)->context()->relocSectBegin(); rs != rsEnd; ++rs) { + // bypass the discarded relocations + // 1. its section kind is changed to Ignore. (The target section is a + // discarded group section.) + // 2. it has no reloc data. (All symbols in the input relocs are in the + // discarded group sections) + if (LDFileFormat::Ignore == (*rs)->kind() || !(*rs)->hasRelocData()) + continue; + RelocData::iterator reloc_it, rEnd = (*rs)->getRelocData()->end(); + for (reloc_it = (*rs)->getRelocData()->begin(); reloc_it != rEnd; + ++reloc_it) { + Relocation* reloc = llvm::cast<Relocation>(reloc_it); + ResolveInfo* sym = reloc->symInfo(); + // only the target symbols defined in the input fragments can make the + // connection + if (NULL == sym) + continue; + if (!sym->isDefine() || !sym->outSymbol()->hasFragRef()) + continue; + + // only the relocation target places which defined in the concerned + // sections can make the connection + // FIXME: judge by getNode() is NULL or not + LDFileFormat::Kind sect_kind = + reloc->targetRef().frag()->getParent()->getSection().kind(); + if (sect_kind != LDFileFormat::Regular && + sect_kind != LDFileFormat::BSS) + continue; + + // only the target symbols defined in the concerned sections can make + // the connection + // FIXME: judge by getNode() is NULL or not + sect_kind = + sym->outSymbol()->fragRef()->frag()->getParent()->getSection().kind(); + if (sect_kind != LDFileFormat::Regular && + sect_kind != LDFileFormat::BSS) + continue; + + connect(reloc, sym); + } + } + } + return true; +} + +bool FragmentGraph::createPseudoEdges(Module& pModule) +{ + // the pseudo edges are the edges from pseudo nodes to regular nodes, which + // present the reference from out-side world when building shared library + + // Traverse all pseudo relocations in the pseudo nodes to set the connection + node_iterator node_it, node_end = m_pPseudoNodeFactory->end(); + for (node_it = m_pPseudoNodeFactory->begin(); node_it != node_end; ++node_it) { + FGNode& node = *node_it; + FGNode::signal_iterator sig_it, sig_end = node.signal_end(); + for (sig_it = node.signal_begin(); sig_it != sig_end; ++sig_it) { + connect(node, (*sig_it)->symInfo()); + } + } + return true; +} + +bool FragmentGraph::connect(Signal pSignal, Slot pSlot) +{ + FGNode* from = getNode(*pSignal->targetRef().frag()); + assert(NULL != from); + + FGNode* to = getNode(*pSlot->outSymbol()->fragRef()->frag()); + assert(NULL != to); + + // maintain edge counter + if (0 == m_pMatrix->at(from->getIndex(), to->getIndex())) + ++m_NumOfEdges; + ++m_pMatrix->at(from->getIndex(), to->getIndex()); + return true; +} + +bool FragmentGraph::connect(FGNode& pFrom, Slot pSlot) +{ + FGNode* to = getNode(*pSlot->outSymbol()->fragRef()->frag()); + assert(NULL != to); + + // maintain edge counter + if (0 == m_pMatrix->at(pFrom.getIndex(), to->getIndex())) + ++m_NumOfEdges; + ++m_pMatrix->at(pFrom.getIndex(), to->getIndex()); + return true; +} + +bool FragmentGraph::createPseudoNodes(Module& pModule) +{ + // when generating shared library, we need to create pseudo node for every + // global defined symbols to present the fan-in of a regular node. + + // Traverse all global defined symbols to build the pseudo nodes. + Module::SymbolTable& sym_tab = pModule.getSymbolTable(); + SymbolCategory::iterator sym_it, sym_end = sym_tab.dynamicEnd(); + for (sym_it = sym_tab.dynamicBegin(); sym_it != sym_end; ++sym_it) { + ResolveInfo* sym = (*sym_it)->resolveInfo(); + if (!sym->isDefine() || !sym->outSymbol()->hasFragRef()) + continue; + FGNode* node = producePseudoNode(); + // create the pseudo relocation to present the fan-out of the pseudo node + Relocation* reloc = Relocation::Create(); + reloc->setSymInfo(sym); + + // set the signal of the pseudo node + node->addSignal(reloc); + + // maintain the map for symbol to pseudo node + SymHashTableType::entry_type* entry = 0; + bool exist = false; + entry = m_pSymNodeMap->insert(sym, exist); + entry->setValue(node); + + } + return true; +} + +bool FragmentGraph::createRegularNodes(Module& pModule) +{ + // Traverse all sections to build the Nodes. We build nodes only for Regular, + // and BSS + Module::iterator sect_it, sect_end = pModule.end(); + for (sect_it = pModule.begin(); sect_it != sect_end; ++sect_it) { + LDSection* section = *sect_it; + SectionData* sect_data = NULL; + + if (LDFileFormat::Regular != section->kind() && + LDFileFormat::BSS != section->kind()) + continue; + + sect_data = section->getSectionData(); + if (NULL == sect_data) + continue; + + // Traverse all fragments in the sections, create Nodes and push the + // fragments into Nodes. Each Region or Fillment fragment belongs to a + // unique Node. The corresponding Align fragments and Null fragments belong + // to the same Node as the Region or Fillment fragment. + SectionData::iterator frag_it = sect_data->begin(); + SectionData::iterator frag_end = sect_data->end(); + if (frag_it == frag_end) + continue; + + int cur_stat = 0; + int last_stat = 0; + // FIXME: + // To prevent some cases that we add the redundant NULL or Align fragments + // and lead a Region/Fillment fragment has more than one NULL or Align + // fragment. We should put all of them into the same Node. + static int stat_matrix[3][3] = {{0, 1, 1}, + {0, 1, 1}, + {0, 0, 0}}; + + FragHashTableType::entry_type* entry = 0; + bool exist = false; + + FGNode* node = produceRegularNode(); + Fragment* frag = NULL; + + frag = &(*frag_it); + cur_stat = get_state(frag->getKind()); + + node->addFragment(frag); + // maintain the fragment to Node map + entry = m_pFragNodeMap->insert(frag, exist); + entry->setValue(node); + ++frag_it; + + while (frag_it != frag_end) { + last_stat = cur_stat; + frag = &(*frag_it); + + cur_stat = get_state(frag->getKind()); + + if (stat_matrix[cur_stat][last_stat]) { + node = produceRegularNode(); + } + node->addFragment(frag); + // maintain the fragment to Node map + entry = m_pFragNodeMap->insert(frag, exist); + entry->setValue(node); + + ++frag_it; + } + } + return true; +} + +void FragmentGraph::initMatrix() +{ + m_pMatrix = new ReachMatrix(m_NumOfPNodes + m_NumOfRNodes); +} + +bool FragmentGraph::getEdges(FGNode& pNode, EdgeListType& pEdges) +{ + // Traverse all regular nodes to find the connection to pNode + node_iterator it, itEnd = m_pRegularNodeFactory->end(); + for (it = m_pRegularNodeFactory->begin(); it != itEnd; ++it) { + FGNode& node_to = *it; + uint32_t weight = m_pMatrix->at(pNode.getIndex(), node_to.getIndex()); + if (weight > 0) { + // build an Edge + pEdges.push_back(FGEdge(pNode, node_to, weight)); + } + } + + return true; +} + +bool FragmentGraph::construct(const LinkerConfig& pConfig, Module& pModule) +{ + // create nodes - traverse all fragments to create the regular nodes, and + // then traverse all global defined symbols to create pseudo nodes + if (!createRegularNodes(pModule)) + return false; + if (!createPseudoNodes(pModule)) + return false; + + // after all nodes created, we know the number of the nodes and then can + // create the reachability matrix + initMatrix(); + + // set slots - traverse all symbols to set the slots of regular nodes + if(!setNodeSlots(pModule)) + return false; + + // connect edges - traverse all relocations to set the edges + if(!createRegularEdges(pModule)) + return false; + if(!createPseudoEdges(pModule)) + return false; + + return true; +} + diff --git a/lib/Fragment/FragmentLinker.cpp b/lib/Fragment/FragmentLinker.cpp index 0398834..dae7b00 100644 --- a/lib/Fragment/FragmentLinker.cpp +++ b/lib/Fragment/FragmentLinker.cpp @@ -52,194 +52,6 @@ FragmentLinker::~FragmentLinker() { } -//===----------------------------------------------------------------------===// -// Symbol Operations -//===----------------------------------------------------------------------===// -/// defineSymbolForcefully - define an output symbol and override it immediately -LDSymbol* FragmentLinker::defineSymbolForcefully(const llvm::StringRef& pName, - bool pIsDyn, - ResolveInfo::Type pType, - ResolveInfo::Desc pDesc, - ResolveInfo::Binding pBinding, - ResolveInfo::SizeType pSize, - LDSymbol::ValueType pValue, - FragmentRef* pFragmentRef, - ResolveInfo::Visibility pVisibility) -{ - ResolveInfo* info = m_Module.getNamePool().findInfo(pName); - LDSymbol* output_sym = NULL; - if (NULL == info) { - // the symbol is not in the pool, create a new one. - // create a ResolveInfo - Resolver::Result result; - m_Module.getNamePool().insertSymbol(pName, pIsDyn, pType, pDesc, - pBinding, pSize, pVisibility, - NULL, result); - assert(!result.existent); - - // create a output LDSymbol - output_sym = LDSymbol::Create(*result.info); - result.info->setSymPtr(output_sym); - - if (shouldForceLocal(*result.info)) - m_Module.getSymbolTable().forceLocal(*output_sym); - else - m_Module.getSymbolTable().add(*output_sym); - } - else { - // the symbol is already in the pool, override it - ResolveInfo old_info; - old_info.override(*info); - - info->setSource(pIsDyn); - info->setType(pType); - info->setDesc(pDesc); - info->setBinding(pBinding); - info->setVisibility(pVisibility); - info->setIsSymbol(true); - info->setSize(pSize); - - output_sym = info->outSymbol(); - if (NULL != output_sym) - m_Module.getSymbolTable().arrange(*output_sym, old_info); - else { - // create a output LDSymbol - output_sym = LDSymbol::Create(*info); - info->setSymPtr(output_sym); - - m_Module.getSymbolTable().add(*output_sym); - } - } - - if (NULL != output_sym) { - output_sym->setFragmentRef(pFragmentRef); - output_sym->setValue(pValue); - } - - return output_sym; -} - -/// defineSymbolAsRefered - define an output symbol and override it immediately -LDSymbol* FragmentLinker::defineSymbolAsRefered(const llvm::StringRef& pName, - bool pIsDyn, - ResolveInfo::Type pType, - ResolveInfo::Desc pDesc, - ResolveInfo::Binding pBinding, - ResolveInfo::SizeType pSize, - LDSymbol::ValueType pValue, - FragmentRef* pFragmentRef, - ResolveInfo::Visibility pVisibility) -{ - ResolveInfo* info = m_Module.getNamePool().findInfo(pName); - - if (NULL == info || !(info->isUndef() || info->isDyn())) { - // only undefined symbol and dynamic symbol can make a reference. - return NULL; - } - - // the symbol is already in the pool, override it - ResolveInfo old_info; - old_info.override(*info); - - info->setSource(pIsDyn); - info->setType(pType); - info->setDesc(pDesc); - info->setBinding(pBinding); - info->setVisibility(pVisibility); - info->setIsSymbol(true); - info->setSize(pSize); - - LDSymbol* output_sym = info->outSymbol(); - if (NULL != output_sym) { - output_sym->setFragmentRef(pFragmentRef); - output_sym->setValue(pValue); - m_Module.getSymbolTable().arrange(*output_sym, old_info); - } - else { - // create a output LDSymbol - output_sym = LDSymbol::Create(*info); - info->setSymPtr(output_sym); - - m_Module.getSymbolTable().add(*output_sym); - } - - return output_sym; -} - -/// defineAndResolveSymbolForcefully - define an output symbol and resolve it -/// immediately -LDSymbol* FragmentLinker::defineAndResolveSymbolForcefully(const llvm::StringRef& pName, - bool pIsDyn, - ResolveInfo::Type pType, - ResolveInfo::Desc pDesc, - ResolveInfo::Binding pBinding, - ResolveInfo::SizeType pSize, - LDSymbol::ValueType pValue, - FragmentRef* pFragmentRef, - ResolveInfo::Visibility pVisibility) -{ - // Result is <info, existent, override> - Resolver::Result result; - ResolveInfo old_info; - m_Module.getNamePool().insertSymbol(pName, pIsDyn, pType, pDesc, pBinding, - pSize, pVisibility, - &old_info, result); - - LDSymbol* output_sym = result.info->outSymbol(); - bool has_output_sym = (NULL != output_sym); - - if (!result.existent || !has_output_sym) { - output_sym = LDSymbol::Create(*result.info); - result.info->setSymPtr(output_sym); - } - - if (result.overriden || !has_output_sym) { - output_sym->setFragmentRef(pFragmentRef); - output_sym->setValue(pValue); - } - - // After symbol resolution, the visibility is changed to the most restrict. - // arrange the output position - if (shouldForceLocal(*result.info)) - m_Module.getSymbolTable().forceLocal(*output_sym); - else if (has_output_sym) - m_Module.getSymbolTable().arrange(*output_sym, old_info); - else - m_Module.getSymbolTable().add(*output_sym); - - return output_sym; -} - -/// defineAndResolveSymbolAsRefered - define an output symbol and resolve it -/// immediately. -LDSymbol* FragmentLinker::defineAndResolveSymbolAsRefered(const llvm::StringRef& pName, - bool pIsDyn, - ResolveInfo::Type pType, - ResolveInfo::Desc pDesc, - ResolveInfo::Binding pBinding, - ResolveInfo::SizeType pSize, - LDSymbol::ValueType pValue, - FragmentRef* pFragmentRef, - ResolveInfo::Visibility pVisibility) -{ - ResolveInfo* info = m_Module.getNamePool().findInfo(pName); - - if (NULL == info || !(info->isUndef() || info->isDyn())) { - // only undefined symbol and dynamic symbol can make a reference. - return NULL; - } - - return defineAndResolveSymbolForcefully(pName, - pIsDyn, - pType, - pDesc, - pBinding, - pSize, - pValue, - pFragmentRef, - pVisibility); -} - bool FragmentLinker::finalizeSymbols() { Module::sym_iterator symbol, symEnd = m_Module.sym_end(); @@ -270,24 +82,7 @@ bool FragmentLinker::finalizeSymbols() } } - // finialize target-dependent symbols - return m_Backend.finalizeSymbols(*this); -} - -bool FragmentLinker::shouldForceLocal(const ResolveInfo& pInfo) const -{ - // forced local symbol matches all rules: - // 1. We are not doing incremental linking. - // 2. The symbol is with Hidden or Internal visibility. - // 3. The symbol should be global or weak. Otherwise, local symbol is local. - // 4. The symbol is defined or common - if (LinkerConfig::Object != m_Config.codeGenType() && - (pInfo.visibility() == ResolveInfo::Hidden || - pInfo.visibility() == ResolveInfo::Internal) && - (pInfo.isGlobal() || pInfo.isWeak()) && - (pInfo.isDefine() || pInfo.isCommon())) - return true; - return false; + return true; } //===----------------------------------------------------------------------===// @@ -426,15 +221,25 @@ void FragmentLinker::partialSyncRelocationResult(MemoryArea& pOutput) void FragmentLinker::writeRelocationResult(Relocation& pReloc, uint8_t* pOutput) { // get output file offset - size_t out_offset = pReloc.targetRef().frag()->getParent()->getSection().offset() + - pReloc.targetRef().getOutputOffset(); + size_t out_offset = + pReloc.targetRef().frag()->getParent()->getSection().offset() + + pReloc.targetRef().getOutputOffset(); uint8_t* target_addr = pOutput + out_offset; // byte swapping if target and host has different endian, and then write back if(llvm::sys::isLittleEndianHost() != m_Config.targets().isLittleEndian()) { uint64_t tmp_data = 0; - switch(m_Config.targets().bitclass()) { + switch(pReloc.size(*m_Backend.getRelocator())) { + case 8u: + std::memcpy(target_addr, &pReloc.target(), 1); + break; + + case 16u: + tmp_data = mcld::bswap16(pReloc.target()); + std::memcpy(target_addr, &tmp_data, 2); + break; + case 32u: tmp_data = mcld::bswap32(pReloc.target()); std::memcpy(target_addr, &tmp_data, 4); @@ -450,33 +255,7 @@ void FragmentLinker::writeRelocationResult(Relocation& pReloc, uint8_t* pOutput) } } else - std::memcpy(target_addr, &pReloc.target(), m_Config.targets().bitclass()/8); -} - -/// isOutputPIC - return whether the output is position-independent -bool FragmentLinker::isOutputPIC() const -{ - return checkIsOutputPIC(); -} - -/// isStaticLink - return whether we're doing static link -bool FragmentLinker::isStaticLink() const -{ - return checkIsStaticLink(); -} - -bool FragmentLinker::checkIsOutputPIC() const -{ - if (LinkerConfig::DynObj == m_Config.codeGenType() || - m_Config.options().isPIE()) - return true; - return false; -} - -bool FragmentLinker::checkIsStaticLink() const -{ - if (m_Module.getLibraryList().empty() && !isOutputPIC()) - return true; - return false; + std::memcpy(target_addr, &pReloc.target(), + pReloc.size(*m_Backend.getRelocator())/8); } diff --git a/lib/Fragment/Relocation.cpp b/lib/Fragment/Relocation.cpp index 293b1c9..fd042ea 100644 --- a/lib/Fragment/Relocation.cpp +++ b/lib/Fragment/Relocation.cpp @@ -143,10 +143,9 @@ void Relocation::setSymInfo(ResolveInfo* pSym) m_pSymInfo = pSym; } -size_t Relocation::size() const +Relocation::Size Relocation::size(Relocator& pRelocator) const { - // TODO: the size of Relocation fragment is handled by backend - return 0; + return pRelocator.getSize(m_Type); } void Relocation::updateAddend() diff --git a/lib/LD/Android.mk b/lib/LD/Android.mk index 53c1f10..edba1b0 100644 --- a/lib/LD/Android.mk +++ b/lib/LD/Android.mk @@ -7,7 +7,6 @@ LOCAL_PATH:= $(call my-dir) mcld_ld_SRC_FILES := \ Archive.cpp \ ArchiveReader.cpp \ - BinaryWriter.cpp \ BranchIsland.cpp \ BranchIslandFactory.cpp \ DWARFLineInfo.cpp \ @@ -17,27 +16,24 @@ mcld_ld_SRC_FILES := \ DiagnosticLineInfo.cpp \ DiagnosticPrinter.cpp \ DynObjReader.cpp \ - DynObjWriter.cpp \ ELFBinaryReader.cpp \ - ELFBinaryWriter.cpp \ ELFSegment.cpp \ ELFSegmentFactory.cpp \ EhFrame.cpp \ EhFrameHdr.cpp \ EhFrameReader.cpp \ - ExecWriter.cpp \ GroupReader.cpp \ LDContext.cpp \ LDFileFormat.cpp \ LDReader.cpp \ LDSection.cpp \ LDSymbol.cpp \ - LDWriter.cpp \ MsgHandler.cpp \ NamePool.cpp \ ObjectWriter.cpp \ RelocData.cpp \ RelocationFactory.cpp \ + Relocator.cpp \ ResolveInfo.cpp \ Resolver.cpp \ SectionData.cpp \ @@ -80,14 +76,12 @@ mcld_ld_variant_SRC_FILES := \ GNUArchiveReader.cpp \ ELFDynObjFileFormat.cpp \ ELFDynObjReader.cpp \ - ELFDynObjWriter.cpp \ ELFExecFileFormat.cpp \ - ELFExecWriter.cpp \ ELFFileFormat.cpp \ ELFObjectReader.cpp \ ELFObjectWriter.cpp \ ELFReader.cpp \ - ELFWriter.cpp + ELFReaderIf.cpp # For the host # ===================================================== diff --git a/lib/LD/Archive.cpp b/lib/LD/Archive.cpp index be82922..ee2edea 100644 --- a/lib/LD/Archive.cpp +++ b/lib/LD/Archive.cpp @@ -129,7 +129,10 @@ bool Archive::addArchiveMember(const llvm::StringRef& pName, ArchiveMemberEntryType* entry = m_ArchiveMemberMap.insert(pName, exist); if (!exist) { ArchiveMember& ar = entry->value(); - ar.file = *pLastPos; + if (pLastPos == m_pInputTree->root()) + ar.file = &m_ArchiveFile; + else + ar.file = *pLastPos; ar.lastPos = pLastPos; ar.move = pMove; } diff --git a/lib/LD/BinaryWriter.cpp b/lib/LD/BinaryWriter.cpp deleted file mode 100644 index 00dd169..0000000 --- a/lib/LD/BinaryWriter.cpp +++ /dev/null @@ -1,24 +0,0 @@ -//===- BinaryWriter.cpp ---------------------------------------------------===// -// -// The MCLinker Project -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -#include <mcld/LD/BinaryWriter.h> -#include <mcld/MC/MCLDInput.h> -#include <mcld/Target/GNULDBackend.h> - -using namespace mcld; - -//========================== -// BinaryWriter -BinaryWriter::BinaryWriter(GNULDBackend& pBackend) -{ -} - -BinaryWriter::~BinaryWriter() -{ -} - diff --git a/lib/LD/DiagnosticEngine.cpp b/lib/LD/DiagnosticEngine.cpp index c2e52d7..ac51080 100644 --- a/lib/LD/DiagnosticEngine.cpp +++ b/lib/LD/DiagnosticEngine.cpp @@ -30,6 +30,9 @@ DiagnosticEngine::~DiagnosticEngine() delete m_pPrinter; delete m_pInfoMap; + + // FIXME: design the destructive relation of LineInfo. + delete m_pLineInfo; } void DiagnosticEngine::reset(const LinkerConfig& pConfig) diff --git a/lib/LD/DiagnosticInfos.cpp b/lib/LD/DiagnosticInfos.cpp index 130fd9a..280e178 100644 --- a/lib/LD/DiagnosticInfos.cpp +++ b/lib/LD/DiagnosticInfos.cpp @@ -130,12 +130,17 @@ bool DiagnosticInfos::process(DiagnosticEngine& pEngine) const severity = DiagnosticEngine::Ignore; break; case LinkerConfig::DynObj: - if (m_Config.options().isNoUndefined() || !m_Config.options().isAllowShlibUndefined()) + if (m_Config.options().isNoUndefined()) severity = DiagnosticEngine::Error; else severity = DiagnosticEngine::Ignore; break; case LinkerConfig::Exec: + if (m_Config.options().isNoUndefined() || m_Config.isCodeStatic()) + severity = DiagnosticEngine::Error; + else + severity = DiagnosticEngine::Ignore; + break; default: severity = DiagnosticEngine::Error; break; diff --git a/lib/LD/DynObjWriter.cpp b/lib/LD/DynObjWriter.cpp deleted file mode 100644 index 6f031ff..0000000 --- a/lib/LD/DynObjWriter.cpp +++ /dev/null @@ -1,16 +0,0 @@ -//===- DynObjWriter.cpp ---------------------------------------------------===// -// -// The MCLinker Project -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -#include "mcld/LD/DynObjWriter.h" -#include "mcld/Target/TargetLDBackend.h" -#include "mcld/MC/MCLDInput.h" - -using namespace mcld; - -//========================== -// DynObjWriter diff --git a/lib/LD/ELFBinaryReader.cpp b/lib/LD/ELFBinaryReader.cpp index c291544..f818286 100644 --- a/lib/LD/ELFBinaryReader.cpp +++ b/lib/LD/ELFBinaryReader.cpp @@ -16,6 +16,8 @@ #include <llvm/Support/ELF.h> +#include <cctype> + using namespace mcld; //===----------------------------------------------------------------------===// @@ -83,9 +85,16 @@ bool ELFBinaryReader::readBinary(Input& pInput) 0x0, data_sect); + std::string mangled_name = pInput.path().filename().string(); + for (std::string::iterator it = mangled_name.begin(), + ie = mangled_name.end(); it != ie; ++it) { + if (isalnum(*it) == 0) + *it = '_'; + } + // symbol: _start m_Builder.AddSymbol(pInput, - "_binary_" + pInput.path().filename().string() + "_start", + "_binary_" + mangled_name + "_start", ResolveInfo::NoType, ResolveInfo::Define, ResolveInfo::Global, @@ -95,7 +104,7 @@ bool ELFBinaryReader::readBinary(Input& pInput) // symbol: _end m_Builder.AddSymbol(pInput, - "_binary_" + pInput.path().filename().string() + "_end", + "_binary_" + mangled_name + "_end", ResolveInfo::NoType, ResolveInfo::Define, ResolveInfo::Global, @@ -105,7 +114,7 @@ bool ELFBinaryReader::readBinary(Input& pInput) // symbol: _size m_Builder.AddSymbol(pInput, - "_binary_" + pInput.path().filename().string() + "_size", + "_binary_" + mangled_name + "_size", ResolveInfo::NoType, ResolveInfo::Define, ResolveInfo::Global, diff --git a/lib/LD/ELFBinaryWriter.cpp b/lib/LD/ELFBinaryWriter.cpp deleted file mode 100644 index 28ef553..0000000 --- a/lib/LD/ELFBinaryWriter.cpp +++ /dev/null @@ -1,110 +0,0 @@ -//===- ELFBinaryWriter.cpp ------------------------------------------------===// -// -// The MCLinker Project -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -#include <mcld/LD/ELFBinaryWriter.h> - -#include <mcld/Module.h> -#include <mcld/Target/GNULDBackend.h> -#include <mcld/Fragment/FragmentLinker.h> -#include <mcld/Support/MemoryArea.h> -#include <mcld/LD/ELFSegmentFactory.h> -#include <mcld/LD/ELFSegment.h> - -#include <llvm/Support/system_error.h> -using namespace llvm; -using namespace mcld; - -//===----------------------------------------------------------------------===// -// ELFBinaryWriter -//===----------------------------------------------------------------------===// -ELFBinaryWriter::ELFBinaryWriter(GNULDBackend& pBackend, - const LinkerConfig& pConfig) - : BinaryWriter(pBackend), ELFWriter(pBackend), m_Config(pConfig) { -} - -ELFBinaryWriter::~ELFBinaryWriter() -{ -} - -llvm::error_code ELFBinaryWriter::writeBinary(Module& pModule, - MemoryArea& pOutput) -{ - // Write out regular ELF sections - for (ELFSegmentFactory::iterator seg = target().elfSegmentTable().begin(), - segEnd = target().elfSegmentTable().end(); seg != segEnd; ++seg) { - if (llvm::ELF::PT_LOAD != (*seg).type()) - continue; - - for (ELFSegment::sect_iterator sect = (*seg).begin(), - sectEnd = (*seg).end(); sect != sectEnd; ++sect) { - MemoryRegion* region = NULL; - // request output region - switch((*sect)->kind()) { - case LDFileFormat::Note: - if ((*sect)->getSectionData() == NULL) - continue; - // Fall through - case LDFileFormat::Regular: - case LDFileFormat::Relocation: - case LDFileFormat::Target: - case LDFileFormat::Debug: - case LDFileFormat::GCCExceptTable: - case LDFileFormat::EhFrame: { - region = pOutput.request((*sect)->offset(), (*sect)->size()); - if (NULL == region) { - llvm::report_fatal_error(llvm::Twine("cannot get enough memory region for output section `") + - llvm::Twine((*sect)->name()) + - llvm::Twine("'.\n")); - } - break; - } - case LDFileFormat::Null: - case LDFileFormat::NamePool: - case LDFileFormat::BSS: - case LDFileFormat::MetaData: - case LDFileFormat::Version: - case LDFileFormat::EhFrameHdr: - case LDFileFormat::StackNote: - // ignore these sections - continue; - default: { - llvm::errs() << "WARNING: unsupported section kind: " - << (*sect)->kind() - << " of section " - << (*sect)->name() - << ".\n"; - continue; - } - } - - // write out sections with data - switch((*sect)->kind()) { - case LDFileFormat::Regular: - case LDFileFormat::Debug: - case LDFileFormat::GCCExceptTable: - case LDFileFormat::Note: - case LDFileFormat::EhFrame: { - // FIXME: if optimization of exception handling sections is enabled, - // then we should emit these sections by the other way. - emitSectionData(**sect, *region); - break; - } - case LDFileFormat::Relocation: - emitRelocation(m_Config, **sect, *region); - break; - case LDFileFormat::Target: - target().emitSectionData(**sect, *region); - break; - default: - continue; - } - } // end of section for loop - } // end of segment for loop - return llvm::make_error_code(llvm::errc::success); -} - diff --git a/lib/LD/ELFDynObjFileFormat.cpp b/lib/LD/ELFDynObjFileFormat.cpp index 9ccf967..e89f48b 100644 --- a/lib/LD/ELFDynObjFileFormat.cpp +++ b/lib/LD/ELFDynObjFileFormat.cpp @@ -52,12 +52,12 @@ void ELFDynObjFileFormat::initObjectFormat(ObjectBuilder& pBuilder, llvm::ELF::SHT_RELA, llvm::ELF::SHF_ALLOC, pBitClass / 8); - f_pRelDyn = pBuilder.CreateSection(".rel.dyn", + f_pRelDyn = pBuilder.CreateSection(".rel.dyn", LDFileFormat::Relocation, llvm::ELF::SHT_REL, llvm::ELF::SHF_ALLOC, pBitClass / 8); - f_pRelPlt = pBuilder.CreateSection(".rel.plt", + f_pRelPlt = pBuilder.CreateSection(".rel.plt", LDFileFormat::Relocation, llvm::ELF::SHT_REL, llvm::ELF::SHF_ALLOC, @@ -77,10 +77,15 @@ void ELFDynObjFileFormat::initObjectFormat(ObjectBuilder& pBuilder, llvm::ELF::SHT_PROGBITS, llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE, pBitClass / 8); - f_pEhFrameHdr = pBuilder.CreateSection(".eh_frame_hdr", - LDFileFormat::EhFrameHdr, - llvm::ELF::SHT_PROGBITS, - llvm::ELF::SHF_ALLOC, - 0x4); + f_pEhFrameHdr = pBuilder.CreateSection(".eh_frame_hdr", + LDFileFormat::EhFrameHdr, + llvm::ELF::SHT_PROGBITS, + llvm::ELF::SHF_ALLOC, + 0x4); + f_pGNUHashTab = pBuilder.CreateSection(".gnu.hash", + LDFileFormat::NamePool, + llvm::ELF::SHT_GNU_HASH, + llvm::ELF::SHF_ALLOC, + pBitClass / 8); } diff --git a/lib/LD/ELFDynObjReader.cpp b/lib/LD/ELFDynObjReader.cpp index e52e863..4f8c7ba 100644 --- a/lib/LD/ELFDynObjReader.cpp +++ b/lib/LD/ELFDynObjReader.cpp @@ -34,6 +34,8 @@ ELFDynObjReader::ELFDynObjReader(GNULDBackend& pBackend, m_Builder(pBuilder) { if (pConfig.targets().is32Bits() && pConfig.targets().isLittleEndian()) m_pELFReader = new ELFReader<32, true>(pBackend); + else if (pConfig.targets().is64Bits() && pConfig.targets().isLittleEndian()) + m_pELFReader = new ELFReader<64, true>(pBackend); } ELFDynObjReader::~ELFDynObjReader() diff --git a/lib/LD/ELFDynObjWriter.cpp b/lib/LD/ELFDynObjWriter.cpp deleted file mode 100644 index 2e903ce..0000000 --- a/lib/LD/ELFDynObjWriter.cpp +++ /dev/null @@ -1,144 +0,0 @@ -//===- ELFDynObjWriter.cpp ------------------------------------------------===// -// -// The MCLinker Project -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -#include <mcld/LD/ELFDynObjWriter.h> - -#include <mcld/Module.h> -#include <mcld/LinkerConfig.h> -#include <mcld/LD/LDSymbol.h> -#include <mcld/Target/GNULDBackend.h> -#include <mcld/MC/MCLDInput.h> -#include <mcld/Support/MemoryArea.h> - -#include <llvm/Support/ELF.h> - -#include <vector> - -using namespace llvm; -using namespace mcld; - -//===----------------------------------------------------------------------===// -// ELFDynObjWriter -//===----------------------------------------------------------------------===// -ELFDynObjWriter::ELFDynObjWriter(GNULDBackend& pBackend, - const LinkerConfig& pConfig) - : DynObjWriter(pBackend), ELFWriter(pBackend), - m_Config(pConfig) { - -} - -ELFDynObjWriter::~ELFDynObjWriter() -{ -} - -llvm::error_code ELFDynObjWriter::writeDynObj(Module& pModule, - MemoryArea& pOutput) -{ - target().emitInterp(pOutput); - - // Write out name pool sections: .dynsym, .dynstr, .hash - target().emitDynNamePools(pModule, pOutput); - - // Write out name pool sections: .symtab, .strtab - target().emitRegNamePools(pModule, pOutput); - - // Write out regular ELF sections - Module::iterator sect, sectEnd = pModule.end(); - for (sect = pModule.begin(); sect != sectEnd; ++sect) { - MemoryRegion* region = NULL; - // request output region - switch((*sect)->kind()) { - case LDFileFormat::Note: - if ((*sect)->getSectionData() == NULL) - continue; - // Fall through - case LDFileFormat::Regular: - case LDFileFormat::Relocation: - case LDFileFormat::Target: - case LDFileFormat::Debug: - case LDFileFormat::GCCExceptTable: - case LDFileFormat::EhFrame: { - region = pOutput.request((*sect)->offset(), (*sect)->size()); - if (NULL == region) { - llvm::report_fatal_error(llvm::Twine("cannot get enough memory region for output section ") + - llvm::Twine((*sect)->name()) + - llvm::Twine(".\n")); - } - break; - } - case LDFileFormat::Null: - case LDFileFormat::NamePool: - case LDFileFormat::BSS: - case LDFileFormat::MetaData: - case LDFileFormat::Version: - case LDFileFormat::EhFrameHdr: - case LDFileFormat::StackNote: - // ignore these sections - continue; - default: { - llvm::errs() << "WARNING: unsupported section kind: " - << (*sect)->kind() - << " of section " - << (*sect)->name() - << ".\n"; - continue; - } - } - - // write out sections with data - switch((*sect)->kind()) { - case LDFileFormat::Regular: - case LDFileFormat::Debug: - case LDFileFormat::GCCExceptTable: - case LDFileFormat::Note: - case LDFileFormat::EhFrame: { - // FIXME: if optimization of exception handling sections is enabled, - // then we should emit these sections by the other way. - emitSectionData(**sect, *region); - break; - } - case LDFileFormat::Relocation: - emitRelocation(m_Config, **sect, *region); - break; - case LDFileFormat::Target: - target().emitSectionData(**sect, *region); - break; - default: - continue; - } - - } // end of for loop - - emitELFShStrTab(target().getOutputFormat()->getShStrTab(), - pModule, - pOutput); - - if (m_Config.targets().is32Bits()) { - // Write out ELF header - // Write out section header table - writeELF32Header(m_Config, pModule, pOutput); - - emitELF32ProgramHeader(pOutput); - - emitELF32SectionHeader(pModule, m_Config, pOutput); - } - else if (m_Config.targets().is64Bits()) { - // Write out ELF header - // Write out section header table - writeELF64Header(m_Config, pModule, pOutput); - - emitELF64ProgramHeader(pOutput); - - emitELF64SectionHeader(pModule, m_Config, pOutput); - } - else - return make_error_code(errc::not_supported); - pOutput.clear(); - return llvm::make_error_code(llvm::errc::success); -} - diff --git a/lib/LD/ELFExecFileFormat.cpp b/lib/LD/ELFExecFileFormat.cpp index a05c058..6a81f72 100644 --- a/lib/LD/ELFExecFileFormat.cpp +++ b/lib/LD/ELFExecFileFormat.cpp @@ -53,12 +53,12 @@ void ELFExecFileFormat::initObjectFormat(ObjectBuilder& pBuilder, llvm::ELF::SHT_RELA, llvm::ELF::SHF_ALLOC, pBitClass / 8); - f_pRelDyn = pBuilder.CreateSection(".rel.dyn", + f_pRelDyn = pBuilder.CreateSection(".rel.dyn", LDFileFormat::Relocation, llvm::ELF::SHT_REL, llvm::ELF::SHF_ALLOC, pBitClass / 8); - f_pRelPlt = pBuilder.CreateSection(".rel.plt", + f_pRelPlt = pBuilder.CreateSection(".rel.plt", LDFileFormat::Relocation, llvm::ELF::SHT_REL, llvm::ELF::SHF_ALLOC, @@ -83,4 +83,9 @@ void ELFExecFileFormat::initObjectFormat(ObjectBuilder& pBuilder, llvm::ELF::SHT_PROGBITS, llvm::ELF::SHF_ALLOC, 0x4); + f_pGNUHashTab = pBuilder.CreateSection(".gnu.hash", + LDFileFormat::NamePool, + llvm::ELF::SHT_GNU_HASH, + llvm::ELF::SHF_ALLOC, + pBitClass / 8); } diff --git a/lib/LD/ELFExecWriter.cpp b/lib/LD/ELFExecWriter.cpp deleted file mode 100644 index a9af584..0000000 --- a/lib/LD/ELFExecWriter.cpp +++ /dev/null @@ -1,144 +0,0 @@ -//===- ELFExecWriter.cpp --------------------------------------------------===// -// -// The MCLinker Project -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -#include <mcld/LD/ELFExecWriter.h> - -#include <mcld/Module.h> -#include <mcld/LinkerConfig.h> -#include <mcld/LD/LDSymbol.h> -#include <mcld/Target/GNULDBackend.h> -#include <mcld/Support/MemoryArea.h> - -#include <llvm/Support/ELF.h> -#include <vector> - -using namespace llvm; -using namespace mcld; - - -//===----------------------------------------------------------------------===// -// ELFExecWriter -//===----------------------------------------------------------------------===// -ELFExecWriter::ELFExecWriter(GNULDBackend& pBackend, - const LinkerConfig& pConfig) - : ExecWriter(pBackend), ELFWriter(pBackend), - m_Config(pConfig) { - -} - -ELFExecWriter::~ELFExecWriter() -{ -} - -llvm::error_code ELFExecWriter::writeExecutable(Module& pModule, - MemoryArea& pOutput) -{ - // write out the interpreter section: .interp - target().emitInterp(pOutput); - - // Write out name pool sections: .dynsym, .dynstr, .hash - target().emitDynNamePools(pModule, pOutput); - - // Write out name pool sections: .symtab, .strtab - target().emitRegNamePools(pModule, pOutput); - - // Write out regular ELF sections - Module::iterator sect, sectEnd = pModule.end(); - for (sect = pModule.begin(); sect != sectEnd; ++sect) { - MemoryRegion* region = NULL; - // request output region - switch((*sect)->kind()) { - case LDFileFormat::Note: - if ((*sect)->getSectionData() == NULL) - continue; - // Fall through - case LDFileFormat::Regular: - case LDFileFormat::Relocation: - case LDFileFormat::Target: - case LDFileFormat::Debug: - case LDFileFormat::GCCExceptTable: - case LDFileFormat::EhFrame: { - region = pOutput.request((*sect)->offset(), (*sect)->size()); - if (NULL == region) { - llvm::report_fatal_error(llvm::Twine("cannot get enough memory region for output section `") + - llvm::Twine((*sect)->name()) + - llvm::Twine("'.\n")); - } - break; - } - case LDFileFormat::Null: - case LDFileFormat::NamePool: - case LDFileFormat::BSS: - case LDFileFormat::MetaData: - case LDFileFormat::Version: - case LDFileFormat::EhFrameHdr: - case LDFileFormat::StackNote: - // ignore these sections - continue; - default: { - llvm::errs() << "WARNING: unsupported section kind: " - << (*sect)->kind() - << " of section " - << (*sect)->name() - << ".\n"; - continue; - } - } - - // write out sections with data - switch((*sect)->kind()) { - case LDFileFormat::Regular: - case LDFileFormat::Debug: - case LDFileFormat::GCCExceptTable: - case LDFileFormat::Note: - case LDFileFormat::EhFrame: { - // FIXME: if optimization of exception handling sections is enabled, - // then we should emit these sections by the other way. - emitSectionData(**sect, *region); - break; - } - case LDFileFormat::Relocation: - emitRelocation(m_Config, **sect, *region); - break; - case LDFileFormat::Target: - target().emitSectionData(**sect, *region); - break; - default: - continue; - } - } // end of for loop - - emitELFShStrTab(target().getOutputFormat()->getShStrTab(), - pModule, - pOutput); - - if (m_Config.targets().is32Bits()) { - // Write out ELF header - // Write out section header table - writeELF32Header(m_Config, pModule, pOutput); - - emitELF32ProgramHeader(pOutput); - - emitELF32SectionHeader(pModule, m_Config, pOutput); - } - else if (m_Config.targets().is64Bits()) { - // Write out ELF header - // Write out section header table - writeELF64Header(m_Config, pModule, pOutput); - - emitELF64ProgramHeader(pOutput); - - emitELF64SectionHeader(pModule, m_Config, pOutput); - } - else - return make_error_code(errc::not_supported); - - pOutput.clear(); - return llvm::make_error_code(llvm::errc::success); -} - diff --git a/lib/LD/ELFFileFormat.cpp b/lib/LD/ELFFileFormat.cpp index b4792b5..067f48c 100644 --- a/lib/LD/ELFFileFormat.cpp +++ b/lib/LD/ELFFileFormat.cpp @@ -59,7 +59,8 @@ ELFFileFormat::ELFFileFormat() f_pStabStr(NULL), f_pStack(NULL), f_pStackNote(NULL), - f_pDataRelRoLocal(NULL) { + f_pDataRelRoLocal(NULL), + f_pGNUHashTab(NULL) { } diff --git a/lib/LD/ELFObjectReader.cpp b/lib/LD/ELFObjectReader.cpp index a87b5b8..b26bb1f 100644 --- a/lib/LD/ELFObjectReader.cpp +++ b/lib/LD/ELFObjectReader.cpp @@ -42,6 +42,9 @@ ELFObjectReader::ELFObjectReader(GNULDBackend& pBackend, if (pConfig.targets().is32Bits() && pConfig.targets().isLittleEndian()) { m_pELFReader = new ELFReader<32, true>(pBackend); } + else if (pConfig.targets().is64Bits() && pConfig.targets().isLittleEndian()) { + m_pELFReader = new ELFReader<64, true>(pBackend); + } m_pEhFrameReader = new EhFrameReader(); } diff --git a/lib/LD/ELFObjectWriter.cpp b/lib/LD/ELFObjectWriter.cpp index e9b7b99..f31b9fb 100644 --- a/lib/LD/ELFObjectWriter.cpp +++ b/lib/LD/ELFObjectWriter.cpp @@ -12,10 +12,29 @@ #include <mcld/LinkerConfig.h> #include <mcld/Target/GNULDBackend.h> #include <mcld/Support/MemoryArea.h> +#include <mcld/Support/MemoryRegion.h> +#include <mcld/Support/MsgHandling.h> +#include <mcld/ADT/SizeTraits.h> +#include <mcld/Fragment/FragmentLinker.h> +#include <mcld/Fragment/AlignFragment.h> +#include <mcld/Fragment/FillFragment.h> +#include <mcld/Fragment/RegionFragment.h> +#include <mcld/Fragment/Stub.h> +#include <mcld/Fragment/NullFragment.h> +#include <mcld/LD/LDSection.h> +#include <mcld/LD/SectionData.h> +#include <mcld/LD/ELFSegment.h> +#include <mcld/LD/ELFSegmentFactory.h> +#include <mcld/LD/RelocData.h> +#include <mcld/LD/EhFrame.h> +#include <llvm/Support/ErrorHandling.h> #include <llvm/Support/system_error.h> +#include <llvm/Support/ELF.h> +#include <llvm/Support/Casting.h> using namespace llvm; +using namespace llvm::ELF; using namespace mcld; //===----------------------------------------------------------------------===// @@ -23,112 +42,622 @@ using namespace mcld; //===----------------------------------------------------------------------===// ELFObjectWriter::ELFObjectWriter(GNULDBackend& pBackend, const LinkerConfig& pConfig) - : ObjectWriter(pBackend), ELFWriter(pBackend), - m_Config(pConfig) { + : ObjectWriter(), m_Backend(pBackend), m_Config(pConfig) +{ } ELFObjectWriter::~ELFObjectWriter() { } +void ELFObjectWriter::writeSection(MemoryArea& pOutput, LDSection *section) +{ + MemoryRegion* region; + // Request output region + switch (section->kind()) { + case LDFileFormat::Note: + if (section->getSectionData() == NULL) + return; + // Fall through + case LDFileFormat::Regular: + case LDFileFormat::Relocation: + case LDFileFormat::Target: + case LDFileFormat::Debug: + case LDFileFormat::GCCExceptTable: + case LDFileFormat::EhFrame: { + region = pOutput.request(section->offset(), section->size()); + if (NULL == region) { + llvm::report_fatal_error(llvm::Twine("cannot get enough memory region for output section `") + + llvm::Twine(section->name()) + + llvm::Twine("'.\n")); + } + break; + } + case LDFileFormat::Null: + case LDFileFormat::NamePool: + case LDFileFormat::BSS: + case LDFileFormat::MetaData: + case LDFileFormat::Version: + case LDFileFormat::EhFrameHdr: + case LDFileFormat::StackNote: + // Ignore these sections + return; + default: + llvm::errs() << "WARNING: unsupported section kind: " + << section->kind() + << " of section " + << section->name() + << ".\n"; + return; + } + + // Write out sections with data + switch(section->kind()) { + case LDFileFormat::GCCExceptTable: + case LDFileFormat::EhFrame: + case LDFileFormat::Regular: + case LDFileFormat::Debug: + case LDFileFormat::Note: + // FIXME: if optimization of exception handling sections is enabled, + // then we should emit these sections by the other way. + emitSectionData(*section, *region); + break; + case LDFileFormat::Relocation: + emitRelocation(m_Config, *section, *region); + break; + case LDFileFormat::Target: + target().emitSectionData(*section, *region); + break; + default: + llvm_unreachable("invalid section kind"); + } +} + llvm::error_code ELFObjectWriter::writeObject(Module& pModule, MemoryArea& pOutput) { - // Write out name pool sections: .symtab, .strtab - target().emitRegNamePools(pModule, pOutput); - - // Write out regular ELF sections - Module::iterator sect, sectEnd = pModule.end(); - for (sect = pModule.begin(); sect != sectEnd; ++sect) { - MemoryRegion* region = NULL; - // request output region - switch((*sect)->kind()) { - case LDFileFormat::Note: - if ((*sect)->getSectionData() == NULL) - continue; - // Fall through - case LDFileFormat::Regular: - case LDFileFormat::Relocation: - case LDFileFormat::Target: - case LDFileFormat::Debug: - case LDFileFormat::GCCExceptTable: - case LDFileFormat::EhFrame: { - region = pOutput.request((*sect)->offset(), (*sect)->size()); - if (NULL == region) { - llvm::report_fatal_error(llvm::Twine("cannot get enough memory region for output section `") + - llvm::Twine((*sect)->name()) + - llvm::Twine("'.\n")); - } - break; - } - case LDFileFormat::Null: - case LDFileFormat::NamePool: - case LDFileFormat::BSS: - case LDFileFormat::MetaData: - case LDFileFormat::Version: - case LDFileFormat::EhFrameHdr: - case LDFileFormat::StackNote: - // ignore these sections - continue; - default: { - llvm::errs() << "WARNING: unsupported section kind: " - << (*sect)->kind() - << " of section " - << (*sect)->name() - << ".\n"; - continue; + bool is_dynobj = m_Config.codeGenType() == LinkerConfig::DynObj; + bool is_exec = m_Config.codeGenType() == LinkerConfig::Exec; + bool is_binary = m_Config.codeGenType() == LinkerConfig::Binary; + bool is_object = m_Config.codeGenType() == LinkerConfig::Object; + + assert(is_dynobj || is_exec || is_binary || is_object); + + if (is_dynobj || is_exec) { + // Write out the interpreter section: .interp + target().emitInterp(pOutput); + + // Write out name pool sections: .dynsym, .dynstr, .hash + target().emitDynNamePools(pModule, pOutput); + } + + if (is_object || is_dynobj || is_exec) { + // Write out name pool sections: .symtab, .strtab + target().emitRegNamePools(pModule, pOutput); + } + + if (is_binary) { + // Iterate over the loadable segments and write the corresponding sections + ELFSegmentFactory::iterator seg, segEnd = target().elfSegmentTable().end(); + + for (seg = target().elfSegmentTable().begin(); seg != segEnd; ++seg) { + if (llvm::ELF::PT_LOAD == (*seg).type()) { + ELFSegment::sect_iterator sect, sectEnd = (*seg).end(); + for (sect = (*seg).begin(); sect != sectEnd; ++sect) + writeSection(pOutput, *sect); } } + } else { + // Write out regular ELF sections + Module::iterator sect, sectEnd = pModule.end(); + for (sect = pModule.begin(); sect != sectEnd; ++sect) + writeSection(pOutput, *sect); - // write out sections with data - switch((*sect)->kind()) { - case LDFileFormat::Regular: - case LDFileFormat::Debug: - case LDFileFormat::GCCExceptTable: - case LDFileFormat::Note: - case LDFileFormat::EhFrame: { - // FIXME: if optimization of exception handling sections is enabled, - // then we should emit these sections by the other way. - emitSectionData(**sect, *region); - break; + emitShStrTab(target().getOutputFormat()->getShStrTab(), pModule, pOutput); + + if (m_Config.targets().is32Bits()) { + // Write out ELF header + // Write out section header table + writeELFHeader<32>(m_Config, pModule, pOutput); + if (is_dynobj || is_exec) + emitProgramHeader<32>(pOutput); + + emitSectionHeader<32>(pModule, m_Config, pOutput); + } + else if (m_Config.targets().is64Bits()) { + // Write out ELF header + // Write out section header table + writeELFHeader<64>(m_Config, pModule, pOutput); + if (is_dynobj || is_exec) + emitProgramHeader<64>(pOutput); + + emitSectionHeader<64>(pModule, m_Config, pOutput); + } + else + return make_error_code(errc::not_supported); + } + + pOutput.clear(); + return llvm::make_error_code(llvm::errc::success); +} + +// writeELFHeader - emit ElfXX_Ehdr +template<size_t SIZE> +void ELFObjectWriter::writeELFHeader(const LinkerConfig& pConfig, + const Module& pModule, + MemoryArea& pOutput) const +{ + typedef typename ELFSizeTraits<SIZE>::Ehdr ElfXX_Ehdr; + typedef typename ELFSizeTraits<SIZE>::Shdr ElfXX_Shdr; + typedef typename ELFSizeTraits<SIZE>::Phdr ElfXX_Phdr; + + // ELF header must start from 0x0 + MemoryRegion *region = pOutput.request(0, sizeof(ElfXX_Ehdr)); + ElfXX_Ehdr* header = (ElfXX_Ehdr*)region->start(); + + memcpy(header->e_ident, ElfMagic, EI_MAG3+1); + + header->e_ident[EI_CLASS] = (SIZE == 32) ? ELFCLASS32 : ELFCLASS64; + header->e_ident[EI_DATA] = pConfig.targets().isLittleEndian()? + ELFDATA2LSB : ELFDATA2MSB; + header->e_ident[EI_VERSION] = target().getInfo().ELFVersion(); + header->e_ident[EI_OSABI] = target().getInfo().OSABI(); + header->e_ident[EI_ABIVERSION] = target().getInfo().ABIVersion(); + + // FIXME: add processor-specific and core file types. + switch(pConfig.codeGenType()) { + case LinkerConfig::Object: + header->e_type = ET_REL; + break; + case LinkerConfig::DynObj: + header->e_type = ET_DYN; + break; + case LinkerConfig::Exec: + header->e_type = ET_EXEC; + break; + default: + llvm::errs() << "unspported output file type: " << pConfig.codeGenType() << ".\n"; + header->e_type = ET_NONE; + } + header->e_machine = target().getInfo().machine(); + header->e_version = header->e_ident[EI_VERSION]; + header->e_entry = getEntryPoint(pConfig, pModule); + + if (LinkerConfig::Object != pConfig.codeGenType()) + header->e_phoff = sizeof(ElfXX_Ehdr); + else + header->e_phoff = 0x0; + + header->e_shoff = getLastStartOffset<SIZE>(pModule); + header->e_flags = target().getInfo().flags(); + header->e_ehsize = sizeof(ElfXX_Ehdr); + header->e_phentsize = sizeof(ElfXX_Phdr); + header->e_phnum = target().numOfSegments(); + header->e_shentsize = sizeof(ElfXX_Shdr); + header->e_shnum = pModule.size(); + header->e_shstrndx = pModule.getSection(".shstrtab")->index(); +} + +/// getEntryPoint +uint64_t ELFObjectWriter::getEntryPoint(const LinkerConfig& pConfig, + const Module& pModule) const +{ + llvm::StringRef entry_name; + if (pConfig.options().hasEntry()) + entry_name = pConfig.options().entry(); + else + entry_name = target().getInfo().entry(); + + uint64_t result = 0x0; + + bool issue_warning = (pConfig.options().hasEntry() && + LinkerConfig::Object != pConfig.codeGenType() && + LinkerConfig::DynObj != pConfig.codeGenType()); + + const LDSymbol* entry_symbol = pModule.getNamePool().findSymbol(entry_name); + + // found the symbol + if (NULL != entry_symbol) { + if (entry_symbol->desc() != ResolveInfo::Define && issue_warning) { + llvm::errs() << "WARNING: entry symbol '" + << entry_symbol->name() + << "' exists but is not defined.\n"; + } + result = entry_symbol->value(); + } + // not in the symbol pool + else { + // We should parse entry as a number. + // @ref GNU ld manual, Options -e. e.g., -e 0x1000. + char* endptr; + result = strtoull(entry_name.data(), &endptr, 0); + if (*endptr != '\0') { + if (issue_warning) { + llvm::errs() << "cannot find entry symbol '" + << entry_name.data() + << "'.\n"; } - case LDFileFormat::Relocation: - emitRelocation(m_Config, **sect, *region); - break; - case LDFileFormat::Target: - target().emitSectionData(**sect, *region); - break; - default: - continue; + result = 0x0; } - } // end of for loop + } + return result; +} - emitELFShStrTab(target().getOutputFormat()->getShStrTab(), - pModule, - pOutput); +// emitSectionHeader - emit ElfXX_Shdr +template<size_t SIZE> +void ELFObjectWriter::emitSectionHeader(const Module& pModule, + const LinkerConfig& pConfig, + MemoryArea& pOutput) const +{ + typedef typename ELFSizeTraits<SIZE>::Shdr ElfXX_Shdr; - if (m_Config.targets().is32Bits()) { - // Write out ELF header - // Write out section header table - writeELF32Header(m_Config, - pModule, - pOutput); + // emit section header + unsigned int sectNum = pModule.size(); + unsigned int header_size = sizeof(ElfXX_Shdr) * sectNum; + MemoryRegion* region = pOutput.request(getLastStartOffset<SIZE>(pModule), + header_size); + ElfXX_Shdr* shdr = (ElfXX_Shdr*)region->start(); - emitELF32SectionHeader(pModule, m_Config, pOutput); + // Iterate the SectionTable in LDContext + unsigned int sectIdx = 0; + unsigned int shstridx = 0; // NULL section has empty name + for (; sectIdx < sectNum; ++sectIdx) { + const LDSection *ld_sect = pModule.getSectionTable().at(sectIdx); + shdr[sectIdx].sh_name = shstridx; + shdr[sectIdx].sh_type = ld_sect->type(); + shdr[sectIdx].sh_flags = ld_sect->flag(); + shdr[sectIdx].sh_addr = ld_sect->addr(); + shdr[sectIdx].sh_offset = ld_sect->offset(); + shdr[sectIdx].sh_size = ld_sect->size(); + shdr[sectIdx].sh_addralign = ld_sect->align(); + shdr[sectIdx].sh_entsize = getSectEntrySize<SIZE>(*ld_sect); + shdr[sectIdx].sh_link = getSectLink(*ld_sect, pConfig); + shdr[sectIdx].sh_info = getSectInfo(*ld_sect); + + // adjust strshidx + shstridx += ld_sect->name().size() + 1; } - else if (m_Config.targets().is64Bits()) { - // Write out ELF header - // Write out section header table - writeELF64Header(m_Config, - pModule, - pOutput); +} + +// emitProgramHeader - emit ElfXX_Phdr +template<size_t SIZE> +void ELFObjectWriter::emitProgramHeader(MemoryArea& pOutput) const +{ + typedef typename ELFSizeTraits<SIZE>::Ehdr ElfXX_Ehdr; + typedef typename ELFSizeTraits<SIZE>::Phdr ElfXX_Phdr; + + uint64_t start_offset, phdr_size; - emitELF64SectionHeader(pModule, m_Config, pOutput); + start_offset = sizeof(ElfXX_Ehdr); + phdr_size = sizeof(ElfXX_Phdr); + // Program header must start directly after ELF header + MemoryRegion *region = pOutput.request(start_offset, + target().numOfSegments() * phdr_size); + + ElfXX_Phdr* phdr = (ElfXX_Phdr*)region->start(); + + // Iterate the elf segment table in GNULDBackend + size_t index = 0; + ELFSegmentFactory::const_iterator seg = target().elfSegmentTable().begin(), + segEnd = target().elfSegmentTable().end(); + for (; seg != segEnd; ++seg, ++index) { + phdr[index].p_type = (*seg).type(); + phdr[index].p_flags = (*seg).flag(); + phdr[index].p_offset = (*seg).offset(); + phdr[index].p_vaddr = (*seg).vaddr(); + phdr[index].p_paddr = (*seg).paddr(); + phdr[index].p_filesz = (*seg).filesz(); + phdr[index].p_memsz = (*seg).memsz(); + phdr[index].p_align = (*seg).align(); } - else - return make_error_code(errc::not_supported); +} - pOutput.clear(); - return llvm::make_error_code(llvm::errc::success); +/// emitShStrTab - emit section string table +void +ELFObjectWriter::emitShStrTab(const LDSection& pShStrTab, + const Module& pModule, + MemoryArea& pOutput) +{ + // write out data + MemoryRegion* region = pOutput.request(pShStrTab.offset(), pShStrTab.size()); + unsigned char* data = region->start(); + size_t shstrsize = 0; + Module::const_iterator section, sectEnd = pModule.end(); + for (section = pModule.begin(); section != sectEnd; ++section) { + strcpy((char*)(data + shstrsize), (*section)->name().data()); + shstrsize += (*section)->name().size() + 1; + } +} + +/// emitSectionData +void +ELFObjectWriter::emitSectionData(const LDSection& pSection, + MemoryRegion& pRegion) const +{ + const SectionData* sd = NULL; + switch (pSection.kind()) { + case LDFileFormat::Relocation: + assert(pSection.hasRelocData()); + return; + case LDFileFormat::EhFrame: + assert(pSection.hasEhFrame()); + sd = &pSection.getEhFrame()->getSectionData(); + break; + default: + assert(pSection.hasSectionData()); + sd = pSection.getSectionData(); + break; + } + emitSectionData(*sd, pRegion); +} + +/// emitRelocation +void ELFObjectWriter::emitRelocation(const LinkerConfig& pConfig, + const LDSection& pSection, + MemoryRegion& pRegion) const +{ + const RelocData* sect_data = pSection.getRelocData(); + assert(NULL != sect_data && "SectionData is NULL in emitRelocation!"); + + if (pSection.type() == SHT_REL) { + if (pConfig.targets().is32Bits()) + emitRel<32>(pConfig, *sect_data, pRegion); + else if (pConfig.targets().is64Bits()) + emitRel<64>(pConfig, *sect_data, pRegion); + else { + fatal(diag::unsupported_bitclass) << pConfig.targets().triple().str() + << pConfig.targets().bitclass(); + } + } else if (pSection.type() == SHT_RELA) { + if (pConfig.targets().is32Bits()) + emitRela<32>(pConfig, *sect_data, pRegion); + else if (pConfig.targets().is64Bits()) + emitRela<64>(pConfig, *sect_data, pRegion); + else { + fatal(diag::unsupported_bitclass) << pConfig.targets().triple().str() + << pConfig.targets().bitclass(); + } + } else + llvm::report_fatal_error("unsupported relocation section type!"); +} + + +// emitRel - emit ElfXX_Rel +template<size_t SIZE> +void ELFObjectWriter::emitRel(const LinkerConfig& pConfig, + const RelocData& pRelocData, + MemoryRegion& pRegion) const +{ + typedef typename ELFSizeTraits<SIZE>::Rel ElfXX_Rel; + typedef typename ELFSizeTraits<SIZE>::Addr ElfXX_Addr; + typedef typename ELFSizeTraits<SIZE>::Word ElfXX_Word; + + ElfXX_Rel* rel = reinterpret_cast<ElfXX_Rel*>(pRegion.start()); + + const Relocation* relocation = 0; + const FragmentRef* frag_ref = 0; + + for (RelocData::const_iterator it = pRelocData.begin(), + ie = pRelocData.end(); it != ie; ++it, ++rel) { + + relocation = &(llvm::cast<Relocation>(*it)); + frag_ref = &(relocation->targetRef()); + + if(LinkerConfig::DynObj == pConfig.codeGenType() || + LinkerConfig::Exec == pConfig.codeGenType()) { + rel->r_offset = static_cast<ElfXX_Addr>( + frag_ref->frag()->getParent()->getSection().addr() + + frag_ref->getOutputOffset()); + } + else { + rel->r_offset = static_cast<ElfXX_Addr>(frag_ref->getOutputOffset()); + } + ElfXX_Word Index; + if( relocation->symInfo() == NULL ) + Index = 0; + else + Index = static_cast<ElfXX_Word>( + target().getSymbolIdx(relocation->symInfo()->outSymbol())); + + rel->setSymbolAndType(Index, relocation->type()); + } +} + +// emitRela - emit ElfXX_Rela +template<size_t SIZE> +void ELFObjectWriter::emitRela(const LinkerConfig& pConfig, + const RelocData& pRelocData, + MemoryRegion& pRegion) const +{ + typedef typename ELFSizeTraits<SIZE>::Rela ElfXX_Rela; + typedef typename ELFSizeTraits<SIZE>::Addr ElfXX_Addr; + typedef typename ELFSizeTraits<SIZE>::Word ElfXX_Word; + + ElfXX_Rela* rel = reinterpret_cast<ElfXX_Rela*>(pRegion.start()); + + const Relocation* relocation = 0; + const FragmentRef* frag_ref = 0; + + for (RelocData::const_iterator it = pRelocData.begin(), + ie = pRelocData.end(); it != ie; ++it, ++rel) { + + relocation = &(llvm::cast<Relocation>(*it)); + frag_ref = &(relocation->targetRef()); + + if(LinkerConfig::DynObj == pConfig.codeGenType() || + LinkerConfig::Exec == pConfig.codeGenType()) { + rel->r_offset = static_cast<ElfXX_Addr>( + frag_ref->frag()->getParent()->getSection().addr() + + frag_ref->getOutputOffset()); + } + else { + rel->r_offset = static_cast<ElfXX_Addr>(frag_ref->getOutputOffset()); + } + + ElfXX_Word Index; + if( relocation->symInfo() == NULL ) + Index = 0; + else + Index = static_cast<ElfXX_Word>( + target().getSymbolIdx(relocation->symInfo()->outSymbol())); + + rel->setSymbolAndType(Index, relocation->type()); + rel->r_addend = relocation->addend(); + } +} + + +/// getSectEntrySize - compute ElfXX_Shdr::sh_entsize +template<size_t SIZE> +uint64_t ELFObjectWriter::getSectEntrySize(const LDSection& pSection) const +{ + typedef typename ELFSizeTraits<SIZE>::Word ElfXX_Word; + typedef typename ELFSizeTraits<SIZE>::Sym ElfXX_Sym; + typedef typename ELFSizeTraits<SIZE>::Rel ElfXX_Rel; + typedef typename ELFSizeTraits<SIZE>::Rela ElfXX_Rela; + typedef typename ELFSizeTraits<SIZE>::Dyn ElfXX_Dyn; + + if (llvm::ELF::SHT_DYNSYM == pSection.type() || + llvm::ELF::SHT_SYMTAB == pSection.type()) + return sizeof(ElfXX_Sym); + if (llvm::ELF::SHT_REL == pSection.type()) + return sizeof(ElfXX_Rel); + if (llvm::ELF::SHT_RELA == pSection.type()) + return sizeof(ElfXX_Rela); + if (llvm::ELF::SHT_HASH == pSection.type() || + llvm::ELF::SHT_GNU_HASH == pSection.type()) + return sizeof(ElfXX_Word); + if (llvm::ELF::SHT_DYNAMIC == pSection.type()) + return sizeof(ElfXX_Dyn); + return 0x0; +} + +/// getSectLink - compute ElfXX_Shdr::sh_link +uint64_t ELFObjectWriter::getSectLink(const LDSection& pSection, + const LinkerConfig& pConfig) const +{ + if (llvm::ELF::SHT_SYMTAB == pSection.type()) + return target().getOutputFormat()->getStrTab().index(); + if (llvm::ELF::SHT_DYNSYM == pSection.type()) + return target().getOutputFormat()->getDynStrTab().index(); + if (llvm::ELF::SHT_DYNAMIC == pSection.type()) + return target().getOutputFormat()->getDynStrTab().index(); + if (llvm::ELF::SHT_HASH == pSection.type() || + llvm::ELF::SHT_GNU_HASH == pSection.type()) + return target().getOutputFormat()->getDynSymTab().index(); + if (llvm::ELF::SHT_REL == pSection.type() || + llvm::ELF::SHT_RELA == pSection.type()) { + if (LinkerConfig::Object == pConfig.codeGenType()) + return target().getOutputFormat()->getSymTab().index(); + else + return target().getOutputFormat()->getDynSymTab().index(); + } + // FIXME: currently we link ARM_EXIDX section to output text section here + if (llvm::ELF::SHT_ARM_EXIDX == pSection.type()) + return target().getOutputFormat()->getText().index(); + return llvm::ELF::SHN_UNDEF; +} + +/// getSectInfo - compute ElfXX_Shdr::sh_info +uint64_t ELFObjectWriter::getSectInfo(const LDSection& pSection) const +{ + if (llvm::ELF::SHT_SYMTAB == pSection.type() || + llvm::ELF::SHT_DYNSYM == pSection.type()) + return pSection.getInfo(); + + if (llvm::ELF::SHT_REL == pSection.type() || + llvm::ELF::SHT_RELA == pSection.type()) { + const LDSection* info_link = pSection.getLink(); + if (NULL != info_link) + return info_link->index(); + } + + return 0x0; +} + +/// getLastStartOffset +template<> +uint64_t ELFObjectWriter::getLastStartOffset<32>(const Module& pModule) const +{ + const LDSection* lastSect = pModule.back(); + assert(lastSect != NULL); + return Align<32>(lastSect->offset() + lastSect->size()); +} + +/// getLastStartOffset +template<> +uint64_t ELFObjectWriter::getLastStartOffset<64>(const Module& pModule) const +{ + const LDSection* lastSect = pModule.back(); + assert(lastSect != NULL); + return Align<64>(lastSect->offset() + lastSect->size()); +} + +/// emitSectionData +void ELFObjectWriter::emitSectionData(const SectionData& pSD, + MemoryRegion& pRegion) const +{ + SectionData::const_iterator fragIter, fragEnd = pSD.end(); + size_t cur_offset = 0; + for (fragIter = pSD.begin(); fragIter != fragEnd; ++fragIter) { + size_t size = fragIter->size(); + switch(fragIter->getKind()) { + case Fragment::Region: { + const RegionFragment& region_frag = llvm::cast<RegionFragment>(*fragIter); + const uint8_t* from = region_frag.getRegion().start(); + memcpy(pRegion.getBuffer(cur_offset), from, size); + break; + } + case Fragment::Alignment: { + // TODO: emit values with different sizes (> 1 byte), and emit nops + const AlignFragment& align_frag = llvm::cast<AlignFragment>(*fragIter); + uint64_t count = size / align_frag.getValueSize(); + switch (align_frag.getValueSize()) { + case 1u: + std::memset(pRegion.getBuffer(cur_offset), + align_frag.getValue(), + count); + break; + default: + llvm::report_fatal_error("unsupported value size for align fragment emission yet.\n"); + break; + } + break; + } + case Fragment::Fillment: { + const FillFragment& fill_frag = llvm::cast<FillFragment>(*fragIter); + if (0 == size || + 0 == fill_frag.getValueSize() || + 0 == fill_frag.size()) { + // ignore virtual fillment + break; + } + + uint64_t num_tiles = fill_frag.size() / fill_frag.getValueSize(); + for (uint64_t i = 0; i != num_tiles; ++i) { + std::memset(pRegion.getBuffer(cur_offset), + fill_frag.getValue(), + fill_frag.getValueSize()); + } + break; + } + case Fragment::Stub: { + const Stub& stub_frag = llvm::cast<Stub>(*fragIter); + memcpy(pRegion.getBuffer(cur_offset), stub_frag.getContent(), size); + break; + } + case Fragment::Null: { + assert(0x0 == size); + break; + } + case Fragment::Target: + llvm::report_fatal_error("Target fragment should not be in a regular section.\n"); + break; + default: + llvm::report_fatal_error("invalid fragment should not be in a regular section.\n"); + break; + } + cur_offset += size; + } } diff --git a/lib/LD/ELFReader.cpp b/lib/LD/ELFReader.cpp index 84ad17b..4057ac8 100644 --- a/lib/LD/ELFReader.cpp +++ b/lib/LD/ELFReader.cpp @@ -13,7 +13,6 @@ #include <mcld/LD/EhFrame.h> #include <mcld/LD/SectionData.h> #include <mcld/Target/GNULDBackend.h> -#include <mcld/Support/MemoryArea.h> #include <mcld/Support/MemoryRegion.h> #include <mcld/Support/MsgHandling.h> #include <mcld/Object/ObjectBuilder.h> @@ -25,138 +24,9 @@ #include <llvm/Support/ELF.h> #include <llvm/Support/Host.h> -using namespace mcld; - -//===----------------------------------------------------------------------===// -// ELFReaderIF -//===----------------------------------------------------------------------===// -/// getSymType -ResolveInfo::Type ELFReaderIF::getSymType(uint8_t pInfo, uint16_t pShndx) const -{ - ResolveInfo::Type result = static_cast<ResolveInfo::Type>(pInfo & 0xF); - if (llvm::ELF::SHN_ABS == pShndx && ResolveInfo::Section == result) { - // In Mips, __gp_disp is a special section symbol. Its name comes from - // .strtab, not .shstrtab. However, it is unique. Only it is also a ABS - // symbol. So here is a tricky to identify __gp_disp and convert it to - // Object symbol. - return ResolveInfo::Object; - } - - return result; -} - -/// getSymDesc -ResolveInfo::Desc ELFReaderIF::getSymDesc(uint16_t pShndx, const Input& pInput) const -{ - if (pShndx == llvm::ELF::SHN_UNDEF) - return ResolveInfo::Undefined; - - if (pShndx < llvm::ELF::SHN_LORESERVE) { - // an ELF symbol defined in a section which we are not including - // must be treated as an Undefined. - // @ref Google gold linker: symtab.cc: 1086 - if (NULL == pInput.context()->getSection(pShndx) || - LDFileFormat::Ignore == pInput.context()->getSection(pShndx)->kind()) - return ResolveInfo::Undefined; - return ResolveInfo::Define; - } - - if (pShndx == llvm::ELF::SHN_ABS) - return ResolveInfo::Define; - - if (pShndx == llvm::ELF::SHN_COMMON) - return ResolveInfo::Common; - - // FIXME: ELF weak alias should be ResolveInfo::Indirect - return ResolveInfo::NoneDesc; -} - -/// getSymBinding -ResolveInfo::Binding -ELFReaderIF::getSymBinding(uint8_t pBinding, uint16_t pShndx, uint8_t pVis) const -{ - - // TODO: - // if --just-symbols option is enabled, the symbol must covert to Absolute - - switch(pBinding) { - case llvm::ELF::STB_LOCAL: - return ResolveInfo::Local; - case llvm::ELF::STB_GLOBAL: - return ResolveInfo::Global; - case llvm::ELF::STB_WEAK: - return ResolveInfo::Weak; - } - - if (pShndx == llvm::ELF::SHN_ABS) - return ResolveInfo::Absolute; - - return ResolveInfo::NoneBinding; -} - -/// getSymFragmentRef -FragmentRef* -ELFReaderIF::getSymFragmentRef(Input& pInput, - uint16_t pShndx, - uint32_t pOffset) const -{ - - if (Input::DynObj == pInput.type()) - return FragmentRef::Null(); - - if (pShndx == llvm::ELF::SHN_UNDEF) - return FragmentRef::Null(); - - if (pShndx >= llvm::ELF::SHN_LORESERVE) // including ABS and COMMON - return FragmentRef::Null(); +#include <iostream> - LDSection* sect_hdr = pInput.context()->getSection(pShndx); - - if (NULL == sect_hdr) - unreachable(diag::unreachable_invalid_section_idx) << pShndx - << pInput.path().native(); - - if (LDFileFormat::Ignore == sect_hdr->kind()) - return FragmentRef::Null(); - - if (LDFileFormat::Group == sect_hdr->kind()) - return FragmentRef::Null(); - - return FragmentRef::Create(*sect_hdr, pOffset); -} - -/// getSymVisibility -ResolveInfo::Visibility -ELFReaderIF::getSymVisibility(uint8_t pVis) const -{ - return static_cast<ResolveInfo::Visibility>(pVis); -} - -/// getSymValue - get the section offset of the symbol. -uint64_t ELFReaderIF::getSymValue(uint64_t pValue, - uint16_t pShndx, - const Input& pInput) const -{ - if (Input::Object == pInput.type()) { - // In relocatable files, st_value holds alignment constraints for a symbol - // whose section index is SHN_COMMON - if (pShndx == llvm::ELF::SHN_COMMON || pShndx == llvm::ELF::SHN_ABS) { - return pValue; - } - - // In relocatable files, st_value holds a section offset for a defined symbol. - // TODO: - // if --just-symbols option are enabled, convert the value from section offset - // to virtual address by adding input section's virtual address. - // The section's virtual address in relocatable files is normally zero, but - // people can use link script to change it. - return pValue; - } - - // In executable and shared object files, st_value holds a virtual address. - // the virtual address is useless during linking. - return 0x0; -} +using namespace mcld; //===----------------------------------------------------------------------===// // ELFReader<32, true> @@ -413,8 +283,8 @@ ELFReader<32, true>::readSectionHeaders(Input& pInput, void* pELFHeader) const uint32_t shoff = 0x0; uint16_t shentsize = 0x0; - uint16_t shnum = 0x0; - uint16_t shstrtab = 0x0; + uint32_t shnum = 0x0; + uint32_t shstrtab = 0x0; if (llvm::sys::isLittleEndianHost()) { shoff = ehdr->e_shoff; @@ -433,11 +303,8 @@ ELFReader<32, true>::readSectionHeaders(Input& pInput, void* pELFHeader) const if (0x0 == shoff) return true; - MemoryRegion* shdr_region = pInput.memArea()->request( - pInput.fileOffset() + shoff, shnum*shentsize); - llvm::ELF::Elf32_Shdr* shdrTab = - reinterpret_cast<llvm::ELF::Elf32_Shdr*>(shdr_region->start()); - + llvm::ELF::Elf32_Shdr *shdr = NULL; + MemoryRegion* shdr_region = NULL; uint32_t sh_name = 0x0; uint32_t sh_type = 0x0; uint32_t sh_flags = 0x0; @@ -447,8 +314,37 @@ ELFReader<32, true>::readSectionHeaders(Input& pInput, void* pELFHeader) const uint32_t sh_info = 0x0; uint32_t sh_addralign = 0x0; + // if shnum and shstrtab overflow, the actual values are in the 1st shdr + if (shnum == llvm::ELF::SHN_UNDEF || shstrtab == llvm::ELF::SHN_XINDEX) { + shdr_region = pInput.memArea()->request(pInput.fileOffset() + shoff, + shentsize); + shdr = reinterpret_cast<llvm::ELF::Elf32_Shdr*>(shdr_region->start()); + + if (llvm::sys::isLittleEndianHost()) { + sh_size = shdr->sh_size; + sh_link = shdr->sh_link; + } + else { + sh_size = mcld::bswap32(shdr->sh_size); + sh_link = mcld::bswap32(shdr->sh_link); + } + pInput.memArea()->release(shdr_region); + + if (shnum == llvm::ELF::SHN_UNDEF) + shnum = sh_size; + if (shstrtab == llvm::ELF::SHN_XINDEX) + shstrtab = sh_link; + + shoff += shentsize; + } + + shdr_region = pInput.memArea()->request(pInput.fileOffset() + shoff, + shnum * shentsize); + llvm::ELF::Elf32_Shdr * shdrTab = + reinterpret_cast<llvm::ELF::Elf32_Shdr*>(shdr_region->start()); + // get .shstrtab first - llvm::ELF::Elf32_Shdr* shdr = &shdrTab[shstrtab]; + shdr = &shdrTab[shstrtab]; if (llvm::sys::isLittleEndianHost()) { sh_offset = shdr->sh_offset; sh_size = shdr->sh_size; @@ -641,3 +537,512 @@ bool ELFReader<32, true>::readDynamic(Input& pInput) const return true; } +//===----------------------------------------------------------------------===// +// ELFReader<64, true> +//===----------------------------------------------------------------------===// +/// constructor +ELFReader<64, true>::ELFReader(GNULDBackend& pBackend) + : ELFReaderIF(pBackend) { +} + +/// destructor +ELFReader<64, true>::~ELFReader() +{ +} + +/// isELF - is this a ELF file +bool ELFReader<64, true>::isELF(void* pELFHeader) const +{ + llvm::ELF::Elf64_Ehdr* hdr = + reinterpret_cast<llvm::ELF::Elf64_Ehdr*>(pELFHeader); + if (0 == memcmp(llvm::ELF::ElfMagic, hdr, 4)) + return true; + return false; +} + +/// readRegularSection - read a regular section and create fragments. +bool +ELFReader<64, true>::readRegularSection(Input& pInput, SectionData& pSD) const +{ + uint64_t offset = pInput.fileOffset() + pSD.getSection().offset(); + uint64_t size = pSD.getSection().size(); + + Fragment* frag = IRBuilder::CreateRegion(pInput, offset, size); + ObjectBuilder::AppendFragment(*frag, pSD); + return true; +} + +/// readSymbols - read ELF symbols and create LDSymbol +bool ELFReader<64, true>::readSymbols(Input& pInput, + IRBuilder& pBuilder, + const MemoryRegion& pRegion, + const char* pStrTab) const +{ + // get number of symbols + size_t entsize = pRegion.size()/sizeof(llvm::ELF::Elf64_Sym); + const llvm::ELF::Elf64_Sym* symtab = + reinterpret_cast<const llvm::ELF::Elf64_Sym*>(pRegion.start()); + + uint32_t st_name = 0x0; + uint64_t st_value = 0x0; + uint64_t st_size = 0x0; + uint8_t st_info = 0x0; + uint8_t st_other = 0x0; + uint16_t st_shndx = 0x0; + + // skip the first NULL symbol + pInput.context()->addSymbol(LDSymbol::Null()); + + for (size_t idx = 1; idx < entsize; ++idx) { + st_info = symtab[idx].st_info; + st_other = symtab[idx].st_other; + + if (llvm::sys::isLittleEndianHost()) { + st_name = symtab[idx].st_name; + st_value = symtab[idx].st_value; + st_size = symtab[idx].st_size; + st_shndx = symtab[idx].st_shndx; + } + else { + st_name = mcld::bswap32(symtab[idx].st_name); + st_value = mcld::bswap64(symtab[idx].st_value); + st_size = mcld::bswap64(symtab[idx].st_size); + st_shndx = mcld::bswap16(symtab[idx].st_shndx); + } + + // If the section should not be included, set the st_shndx SHN_UNDEF + // - A section in interrelated groups are not included. + if (pInput.type() == Input::Object && + st_shndx < llvm::ELF::SHN_LORESERVE && + st_shndx != llvm::ELF::SHN_UNDEF) { + if (NULL == pInput.context()->getSection(st_shndx)) + st_shndx = llvm::ELF::SHN_UNDEF; + } + + // get ld_type + ResolveInfo::Type ld_type = getSymType(st_info, st_shndx); + + // get ld_desc + ResolveInfo::Desc ld_desc = getSymDesc(st_shndx, pInput); + + // get ld_binding + ResolveInfo::Binding ld_binding = getSymBinding((st_info >> 4), st_shndx, st_other); + + // get ld_value - ld_value must be section relative. + uint64_t ld_value = getSymValue(st_value, st_shndx, pInput); + + // get ld_vis + ResolveInfo::Visibility ld_vis = getSymVisibility(st_other); + + // get section + LDSection* section = NULL; + if (st_shndx < llvm::ELF::SHN_LORESERVE) // including ABS and COMMON + section = pInput.context()->getSection(st_shndx); + + // get ld_name + std::string ld_name; + if (ResolveInfo::Section == ld_type) { + // Section symbol's st_name is the section index. + assert(NULL != section && "get a invalid section"); + ld_name = section->name(); + } + else { + ld_name = std::string(pStrTab + st_name); + } + + pBuilder.AddSymbol(pInput, + ld_name, + ld_type, + ld_desc, + ld_binding, + st_size, + ld_value, + section, ld_vis); + } // end of for loop + return true; +} + +//===----------------------------------------------------------------------===// +// ELFReader::read relocations - read ELF rela and rel, and create Relocation +//===----------------------------------------------------------------------===// +/// ELFReader::readRela - read ELF rela and create Relocation +bool ELFReader<64, true>::readRela(Input& pInput, + LDSection& pSection, + const MemoryRegion& pRegion) const +{ + // get the number of rela + size_t entsize = pRegion.size() / sizeof(llvm::ELF::Elf64_Rela); + const llvm::ELF::Elf64_Rela* relaTab = + reinterpret_cast<const llvm::ELF::Elf64_Rela*>(pRegion.start()); + + for (size_t idx=0; idx < entsize; ++idx) { + uint64_t r_offset = 0x0; + uint64_t r_info = 0x0; + int64_t r_addend = 0; + if (llvm::sys::isLittleEndianHost()) { + r_offset = relaTab[idx].r_offset; + r_info = relaTab[idx].r_info; + r_addend = relaTab[idx].r_addend; + } + else { + r_offset = mcld::bswap64(relaTab[idx].r_offset); + r_info = mcld::bswap64(relaTab[idx].r_info); + r_addend = mcld::bswap64(relaTab[idx].r_addend); + } + + uint32_t r_type = static_cast<uint32_t>(r_info); + uint32_t r_sym = (r_info >> 32); + LDSymbol* symbol = pInput.context()->getSymbol(r_sym); + if (NULL == symbol) { + fatal(diag::err_cannot_read_symbol) << r_sym << pInput.path(); + } + + IRBuilder::AddRelocation(pSection, r_type, *symbol, r_offset, r_addend); + } // end of for + return true; +} + +/// readRel - read ELF rel and create Relocation +bool ELFReader<64, true>::readRel(Input& pInput, + LDSection& pSection, + const MemoryRegion& pRegion) const +{ + // get the number of rel + size_t entsize = pRegion.size() / sizeof(llvm::ELF::Elf64_Rel); + const llvm::ELF::Elf64_Rel* relTab = + reinterpret_cast<const llvm::ELF::Elf64_Rel*>(pRegion.start()); + + for (size_t idx=0; idx < entsize; ++idx) { + uint64_t r_offset = 0x0; + uint64_t r_info = 0x0; + if (llvm::sys::isLittleEndianHost()) { + r_offset = relTab[idx].r_offset; + r_info = relTab[idx].r_info; + } + else { + r_offset = mcld::bswap64(relTab[idx].r_offset); + r_info = mcld::bswap64(relTab[idx].r_info); + } + + uint32_t r_type = static_cast<uint32_t>(r_info); + uint32_t r_sym = (r_info >> 32); + + LDSymbol* symbol = pInput.context()->getSymbol(r_sym); + if (NULL == symbol) { + fatal(diag::err_cannot_read_symbol) << r_sym << pInput.path(); + } + + IRBuilder::AddRelocation(pSection, r_type, *symbol, r_offset); + } // end of for + return true; +} + +/// isMyEndian - is this ELF file in the same endian to me? +bool ELFReader<64, true>::isMyEndian(void* pELFHeader) const +{ + llvm::ELF::Elf64_Ehdr* hdr = + reinterpret_cast<llvm::ELF::Elf64_Ehdr*>(pELFHeader); + + return (hdr->e_ident[llvm::ELF::EI_DATA] == llvm::ELF::ELFDATA2LSB); +} + +/// isMyMachine - is this ELF file generated for the same machine. +bool ELFReader<64, true>::isMyMachine(void* pELFHeader) const +{ + llvm::ELF::Elf64_Ehdr* hdr = + reinterpret_cast<llvm::ELF::Elf64_Ehdr*>(pELFHeader); + + if (llvm::sys::isLittleEndianHost()) + return (hdr->e_machine == target().getInfo().machine()); + return (mcld::bswap16(hdr->e_machine) == target().getInfo().machine()); +} + +/// fileType - return the file type +Input::Type ELFReader<64, true>::fileType(void* pELFHeader) const +{ + llvm::ELF::Elf64_Ehdr* hdr = + reinterpret_cast<llvm::ELF::Elf64_Ehdr*>(pELFHeader); + uint32_t type = 0x0; + if (llvm::sys::isLittleEndianHost()) + type = hdr->e_type; + else + type = mcld::bswap16(hdr->e_type); + + switch(type) { + case llvm::ELF::ET_REL: + return Input::Object; + case llvm::ELF::ET_EXEC: + return Input::Exec; + case llvm::ELF::ET_DYN: + return Input::DynObj; + case llvm::ELF::ET_CORE: + return Input::CoreFile; + case llvm::ELF::ET_NONE: + default: + return Input::Unknown; + } +} + +/// readSectionHeaders - read ELF section header table and create LDSections +bool +ELFReader<64, true>::readSectionHeaders(Input& pInput, void* pELFHeader) const +{ + llvm::ELF::Elf64_Ehdr* ehdr = + reinterpret_cast<llvm::ELF::Elf64_Ehdr*>(pELFHeader); + + uint64_t shoff = 0x0; + uint16_t shentsize = 0x0; + uint32_t shnum = 0x0; + uint32_t shstrtab = 0x0; + + if (llvm::sys::isLittleEndianHost()) { + shoff = ehdr->e_shoff; + shentsize = ehdr->e_shentsize; + shnum = ehdr->e_shnum; + shstrtab = ehdr->e_shstrndx; + } + else { + shoff = mcld::bswap64(ehdr->e_shoff); + shentsize = mcld::bswap16(ehdr->e_shentsize); + shnum = mcld::bswap16(ehdr->e_shnum); + shstrtab = mcld::bswap16(ehdr->e_shstrndx); + } + + // If the file has no section header table, e_shoff holds zero. + if (0x0 == shoff) + return true; + + llvm::ELF::Elf64_Shdr *shdr = NULL; + MemoryRegion* shdr_region = NULL; + uint32_t sh_name = 0x0; + uint32_t sh_type = 0x0; + uint64_t sh_flags = 0x0; + uint64_t sh_offset = 0x0; + uint64_t sh_size = 0x0; + uint32_t sh_link = 0x0; + uint32_t sh_info = 0x0; + uint64_t sh_addralign = 0x0; + + // if shnum and shstrtab overflow, the actual values are in the 1st shdr + if (shnum == llvm::ELF::SHN_UNDEF || shstrtab == llvm::ELF::SHN_XINDEX) { + shdr_region = pInput.memArea()->request(pInput.fileOffset() + shoff, + shentsize); + shdr = reinterpret_cast<llvm::ELF::Elf64_Shdr*>(shdr_region->start()); + + if (llvm::sys::isLittleEndianHost()) { + sh_size = shdr->sh_size; + sh_link = shdr->sh_link; + } + else { + sh_size = mcld::bswap64(shdr->sh_size); + sh_link = mcld::bswap32(shdr->sh_link); + } + pInput.memArea()->release(shdr_region); + + if (shnum == llvm::ELF::SHN_UNDEF) + shnum = sh_size; + if (shstrtab == llvm::ELF::SHN_XINDEX) + shstrtab = sh_link; + + shoff += shentsize; + } + + shdr_region = pInput.memArea()->request(pInput.fileOffset() + shoff, + shnum * shentsize); + llvm::ELF::Elf64_Shdr * shdrTab = + reinterpret_cast<llvm::ELF::Elf64_Shdr*>(shdr_region->start()); + + // get .shstrtab first + shdr = &shdrTab[shstrtab]; + if (llvm::sys::isLittleEndianHost()) { + sh_offset = shdr->sh_offset; + sh_size = shdr->sh_size; + } + else { + sh_offset = mcld::bswap64(shdr->sh_offset); + sh_size = mcld::bswap64(shdr->sh_size); + } + + MemoryRegion* sect_name_region = pInput.memArea()->request( + pInput.fileOffset() + sh_offset, sh_size); + const char* sect_name = + reinterpret_cast<const char*>(sect_name_region->start()); + + LinkInfoList link_info_list; + + // create all LDSections, including first NULL section. + for (size_t idx = 0; idx < shnum; ++idx) { + if (llvm::sys::isLittleEndianHost()) { + sh_name = shdrTab[idx].sh_name; + sh_type = shdrTab[idx].sh_type; + sh_flags = shdrTab[idx].sh_flags; + sh_offset = shdrTab[idx].sh_offset; + sh_size = shdrTab[idx].sh_size; + sh_link = shdrTab[idx].sh_link; + sh_info = shdrTab[idx].sh_info; + sh_addralign = shdrTab[idx].sh_addralign; + } + else { + sh_name = mcld::bswap32(shdrTab[idx].sh_name); + sh_type = mcld::bswap32(shdrTab[idx].sh_type); + sh_flags = mcld::bswap64(shdrTab[idx].sh_flags); + sh_offset = mcld::bswap64(shdrTab[idx].sh_offset); + sh_size = mcld::bswap64(shdrTab[idx].sh_size); + sh_link = mcld::bswap32(shdrTab[idx].sh_link); + sh_info = mcld::bswap32(shdrTab[idx].sh_info); + sh_addralign = mcld::bswap64(shdrTab[idx].sh_addralign); + } + + LDSection* section = IRBuilder::CreateELFHeader(pInput, + sect_name+sh_name, + sh_type, + sh_flags, + sh_addralign); + section->setSize(sh_size); + section->setOffset(sh_offset); + section->setInfo(sh_info); + + if (sh_link != 0x0 || sh_info != 0x0) { + LinkInfo link_info = { section, sh_link, sh_info }; + link_info_list.push_back(link_info); + } + } // end of for + + // set up InfoLink + LinkInfoList::iterator info, infoEnd = link_info_list.end(); + for (info = link_info_list.begin(); info != infoEnd; ++info) { + if (LDFileFormat::NamePool == info->section->kind() || + LDFileFormat::Group == info->section->kind() || + LDFileFormat::Note == info->section->kind()) { + info->section->setLink(pInput.context()->getSection(info->sh_link)); + continue; + } + if (LDFileFormat::Relocation == info->section->kind()) { + info->section->setLink(pInput.context()->getSection(info->sh_info)); + continue; + } + } + + pInput.memArea()->release(shdr_region); + pInput.memArea()->release(sect_name_region); + + return true; +} + +/// readSignature - read a symbol from the given Input and index in symtab +/// This is used to get the signature of a group section. +ResolveInfo* ELFReader<64, true>::readSignature(Input& pInput, + LDSection& pSymTab, + uint32_t pSymIdx) const +{ + LDSection* symtab = &pSymTab; + LDSection* strtab = symtab->getLink(); + assert(NULL != symtab && NULL != strtab); + + uint64_t offset = pInput.fileOffset() + symtab->offset() + + sizeof(llvm::ELF::Elf64_Sym) * pSymIdx; + MemoryRegion* symbol_region = + pInput.memArea()->request(offset, sizeof(llvm::ELF::Elf64_Sym)); + llvm::ELF::Elf64_Sym* entry = + reinterpret_cast<llvm::ELF::Elf64_Sym*>(symbol_region->start()); + + uint32_t st_name = 0x0; + uint8_t st_info = 0x0; + uint8_t st_other = 0x0; + uint16_t st_shndx = 0x0; + st_info = entry->st_info; + st_other = entry->st_other; + if (llvm::sys::isLittleEndianHost()) { + st_name = entry->st_name; + st_shndx = entry->st_shndx; + } + else { + st_name = mcld::bswap32(entry->st_name); + st_shndx = mcld::bswap16(entry->st_shndx); + } + + MemoryRegion* strtab_region = pInput.memArea()->request( + pInput.fileOffset() + strtab->offset(), strtab->size()); + + // get ld_name + llvm::StringRef ld_name( + reinterpret_cast<char*>(strtab_region->start() + st_name)); + + ResolveInfo* result = ResolveInfo::Create(ld_name); + result->setSource(pInput.type() == Input::DynObj); + result->setType(static_cast<ResolveInfo::Type>(st_info & 0xF)); + result->setDesc(getSymDesc(st_shndx, pInput)); + result->setBinding(getSymBinding((st_info >> 4), st_shndx, st_other)); + result->setVisibility(getSymVisibility(st_other)); + + // release regions + pInput.memArea()->release(symbol_region); + pInput.memArea()->release(strtab_region); + + return result; +} + +/// readDynamic - read ELF .dynamic in input dynobj +bool ELFReader<64, true>::readDynamic(Input& pInput) const +{ + assert(pInput.type() == Input::DynObj); + const LDSection* dynamic_sect = pInput.context()->getSection(".dynamic"); + if (NULL == dynamic_sect) { + fatal(diag::err_cannot_read_section) << ".dynamic"; + } + const LDSection* dynstr_sect = dynamic_sect->getLink(); + if (NULL == dynstr_sect) { + fatal(diag::err_cannot_read_section) << ".dynstr"; + } + + MemoryRegion* dynamic_region = pInput.memArea()->request( + pInput.fileOffset() + dynamic_sect->offset(), dynamic_sect->size()); + + MemoryRegion* dynstr_region = pInput.memArea()->request( + pInput.fileOffset() + dynstr_sect->offset(), dynstr_sect->size()); + + assert(NULL != dynamic_region && NULL != dynstr_region); + + const llvm::ELF::Elf64_Dyn* dynamic = + (llvm::ELF::Elf64_Dyn*) dynamic_region->start(); + const char* dynstr = (const char*) dynstr_region->start(); + bool hasSOName = false; + size_t numOfEntries = dynamic_sect->size() / sizeof(llvm::ELF::Elf64_Dyn); + + for (size_t idx = 0; idx < numOfEntries; ++idx) { + + llvm::ELF::Elf64_Sxword d_tag = 0x0; + llvm::ELF::Elf64_Xword d_val = 0x0; + + if (llvm::sys::isLittleEndianHost()) { + d_tag = dynamic[idx].d_tag; + d_val = dynamic[idx].d_un.d_val; + } else { + d_tag = mcld::bswap64(dynamic[idx].d_tag); + d_val = mcld::bswap64(dynamic[idx].d_un.d_val); + } + + switch (d_tag) { + case llvm::ELF::DT_SONAME: + assert(d_val < dynstr_sect->size()); + pInput.setName(sys::fs::Path(dynstr + d_val).filename().native()); + hasSOName = true; + break; + case llvm::ELF::DT_NEEDED: + // TODO: + break; + case llvm::ELF::DT_NULL: + default: + break; + } + } + + // if there is no SONAME in .dynamic, then set it from input path + if (!hasSOName) + pInput.setName(pInput.path().filename().native()); + + pInput.memArea()->release(dynamic_region); + pInput.memArea()->release(dynstr_region); + return true; +} + diff --git a/lib/LD/ELFReaderIf.cpp b/lib/LD/ELFReaderIf.cpp new file mode 100644 index 0000000..9625d85 --- /dev/null +++ b/lib/LD/ELFReaderIf.cpp @@ -0,0 +1,164 @@ +//===- ELFReader.cpp ------------------------------------------------------===// +// +// The MCLinker Project +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#include <mcld/LD/ELFReaderIf.h> + +#include <mcld/IRBuilder.h> +#include <mcld/Fragment/FillFragment.h> +#include <mcld/LD/EhFrame.h> +#include <mcld/LD/SectionData.h> +#include <mcld/Target/GNULDBackend.h> +//#include <mcld/Support/MemoryArea.h> +//#include <mcld/Support/MemoryRegion.h> +//#include <mcld/Support/MsgHandling.h> +//#include <mcld/Object/ObjectBuilder.h> + +#include <cstring> + +#include <llvm/ADT/StringRef.h> +#include <llvm/ADT/Twine.h> +#include <llvm/Support/ELF.h> +#include <llvm/Support/Host.h> + +using namespace mcld; + +//===----------------------------------------------------------------------===// +// ELFReaderIF +//===----------------------------------------------------------------------===// +/// getSymType +ResolveInfo::Type ELFReaderIF::getSymType(uint8_t pInfo, uint16_t pShndx) const +{ + ResolveInfo::Type result = static_cast<ResolveInfo::Type>(pInfo & 0xF); + if (llvm::ELF::SHN_ABS == pShndx && ResolveInfo::Section == result) { + // In Mips, __gp_disp is a special section symbol. Its name comes from + // .strtab, not .shstrtab. However, it is unique. Only it is also a ABS + // symbol. So here is a tricky to identify __gp_disp and convert it to + // Object symbol. + return ResolveInfo::Object; + } + + return result; +} + +/// getSymDesc +ResolveInfo::Desc ELFReaderIF::getSymDesc(uint16_t pShndx, const Input& pInput) const +{ + if (pShndx == llvm::ELF::SHN_UNDEF) + return ResolveInfo::Undefined; + + if (pShndx < llvm::ELF::SHN_LORESERVE) { + // an ELF symbol defined in a section which we are not including + // must be treated as an Undefined. + // @ref Google gold linker: symtab.cc: 1086 + if (NULL == pInput.context()->getSection(pShndx) || + LDFileFormat::Ignore == pInput.context()->getSection(pShndx)->kind()) + return ResolveInfo::Undefined; + return ResolveInfo::Define; + } + + if (pShndx == llvm::ELF::SHN_ABS) + return ResolveInfo::Define; + + if (pShndx == llvm::ELF::SHN_COMMON) + return ResolveInfo::Common; + + if (pShndx >= llvm::ELF::SHN_LOPROC && + pShndx <= llvm::ELF::SHN_HIPROC) + return target().getSymDesc(pShndx); + + // FIXME: ELF weak alias should be ResolveInfo::Indirect + return ResolveInfo::NoneDesc; +} + +/// getSymBinding +ResolveInfo::Binding +ELFReaderIF::getSymBinding(uint8_t pBinding, uint16_t pShndx, uint8_t pVis) const +{ + + // TODO: + // if --just-symbols option is enabled, the symbol must covert to Absolute + + switch(pBinding) { + case llvm::ELF::STB_LOCAL: + return ResolveInfo::Local; + case llvm::ELF::STB_GLOBAL: + return ResolveInfo::Global; + case llvm::ELF::STB_WEAK: + return ResolveInfo::Weak; + } + + if (pShndx == llvm::ELF::SHN_ABS) + return ResolveInfo::Absolute; + + return ResolveInfo::NoneBinding; +} + +/// getSymFragmentRef +FragmentRef* +ELFReaderIF::getSymFragmentRef(Input& pInput, + uint16_t pShndx, + uint32_t pOffset) const +{ + + if (Input::DynObj == pInput.type()) + return FragmentRef::Null(); + + if (pShndx == llvm::ELF::SHN_UNDEF) + return FragmentRef::Null(); + + if (pShndx >= llvm::ELF::SHN_LORESERVE) // including ABS and COMMON + return FragmentRef::Null(); + + LDSection* sect_hdr = pInput.context()->getSection(pShndx); + + if (NULL == sect_hdr) + unreachable(diag::unreachable_invalid_section_idx) << pShndx + << pInput.path().native(); + + if (LDFileFormat::Ignore == sect_hdr->kind()) + return FragmentRef::Null(); + + if (LDFileFormat::Group == sect_hdr->kind()) + return FragmentRef::Null(); + + return FragmentRef::Create(*sect_hdr, pOffset); +} + +/// getSymVisibility +ResolveInfo::Visibility +ELFReaderIF::getSymVisibility(uint8_t pVis) const +{ + return static_cast<ResolveInfo::Visibility>(pVis); +} + +/// getSymValue - get the section offset of the symbol. +uint64_t ELFReaderIF::getSymValue(uint64_t pValue, + uint16_t pShndx, + const Input& pInput) const +{ + if (Input::Object == pInput.type()) { + // In relocatable files, st_value holds alignment constraints for a symbol + // whose section index is SHN_COMMON + if (pShndx == llvm::ELF::SHN_COMMON || pShndx == llvm::ELF::SHN_ABS) { + return pValue; + } + + // In relocatable files, st_value holds a section offset for a defined symbol. + // TODO: + // if --just-symbols option are enabled, convert the value from section offset + // to virtual address by adding input section's virtual address. + // The section's virtual address in relocatable files is normally zero, but + // people can use link script to change it. + return pValue; + } + + // In executable and shared object files, st_value holds a virtual address. + // the virtual address is useless during linking. + return 0x0; +} + diff --git a/lib/LD/ELFWriter.cpp b/lib/LD/ELFWriter.cpp deleted file mode 100644 index a37e654..0000000 --- a/lib/LD/ELFWriter.cpp +++ /dev/null @@ -1,600 +0,0 @@ -//===- ELFWriter.cpp ------------------------------------------------------===// -// -// The MCLinker Project -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include <cstdlib> -#include <cstring> - -#include <llvm/Support/ELF.h> -#include <llvm/Support/Casting.h> - -#include <mcld/LinkerConfig.h> -#include <mcld/Module.h> -#include <mcld/ADT/SizeTraits.h> -#include <mcld/Fragment/FragmentLinker.h> -#include <mcld/Fragment/AlignFragment.h> -#include <mcld/Fragment/FillFragment.h> -#include <mcld/Fragment/RegionFragment.h> -#include <mcld/Fragment/Stub.h> -#include <mcld/Fragment/NullFragment.h> -#include <mcld/LD/ELFWriter.h> -#include <mcld/LD/LDSymbol.h> -#include <mcld/LD/LDSection.h> -#include <mcld/LD/SectionData.h> -#include <mcld/LD/ELFSegment.h> -#include <mcld/LD/ELFSegmentFactory.h> -#include <mcld/LD/RelocData.h> -#include <mcld/LD/EhFrame.h> -#include <mcld/Target/GNULDBackend.h> -#include <mcld/Support/MemoryArea.h> -#include <mcld/Support/MemoryRegion.h> - -using namespace llvm::ELF; -using namespace mcld; - -/// writeELF32Header - write ELF header -void ELFWriter::writeELF32Header(const LinkerConfig& pConfig, - const Module& pModule, - MemoryArea& pOutput) const -{ - // ELF header must start from 0x0 - MemoryRegion *region = pOutput.request(0, sizeof(Elf32_Ehdr)); - Elf32_Ehdr* header = (Elf32_Ehdr*)region->start(); - - memcpy(header->e_ident, ElfMagic, EI_MAG3+1); - - header->e_ident[EI_CLASS] = ELFCLASS32; - header->e_ident[EI_DATA] = pConfig.targets().isLittleEndian()? - ELFDATA2LSB : ELFDATA2MSB; - header->e_ident[EI_VERSION] = target().getInfo().ELFVersion(); - header->e_ident[EI_OSABI] = target().getInfo().OSABI(); - header->e_ident[EI_ABIVERSION] = target().getInfo().ABIVersion(); - - // FIXME: add processor-specific and core file types. - switch(pConfig.codeGenType()) { - case LinkerConfig::Object: - header->e_type = ET_REL; - break; - case LinkerConfig::DynObj: - header->e_type = ET_DYN; - break; - case LinkerConfig::Exec: - header->e_type = ET_EXEC; - break; - default: - llvm::errs() << "unspported output file type: " << pConfig.codeGenType() << ".\n"; - header->e_type = ET_NONE; - } - header->e_machine = target().getInfo().machine(); - header->e_version = header->e_ident[EI_VERSION]; - header->e_entry = getEntryPoint(pConfig, pModule); - - if (LinkerConfig::Object != pConfig.codeGenType()) - header->e_phoff = sizeof(Elf32_Ehdr); - else - header->e_phoff = 0x0; - - header->e_shoff = getELF32LastStartOffset(pModule); - header->e_flags = target().flags(); - header->e_ehsize = sizeof(Elf32_Ehdr); - header->e_phentsize = sizeof(Elf32_Phdr); - header->e_phnum = target().numOfSegments(); - header->e_shentsize = sizeof(Elf32_Shdr); - header->e_shnum = pModule.size(); - header->e_shstrndx = pModule.getSection(".shstrtab")->index(); -} - -/// writeELF64Header - write ELF header -void ELFWriter::writeELF64Header(const LinkerConfig& pConfig, - const Module& pModule, - MemoryArea& pOutput) const -{ - // ELF header must start from 0x0 - MemoryRegion *region = pOutput.request(0, sizeof(Elf64_Ehdr)); - Elf64_Ehdr* header = (Elf64_Ehdr*)region->start(); - - memcpy(header->e_ident, ElfMagic, EI_MAG3+1); - - header->e_ident[EI_CLASS] = ELFCLASS64; - header->e_ident[EI_DATA] = pConfig.targets().isLittleEndian()? - ELFDATA2LSB : ELFDATA2MSB; - header->e_ident[EI_VERSION] = target().getInfo().ELFVersion(); - header->e_ident[EI_OSABI] = target().getInfo().OSABI(); - header->e_ident[EI_ABIVERSION] = target().getInfo().ABIVersion(); - - // FIXME: add processor-specific and core file types. - switch(pConfig.codeGenType()) { - case LinkerConfig::Object: - header->e_type = ET_REL; - break; - case LinkerConfig::DynObj: - header->e_type = ET_DYN; - break; - case LinkerConfig::Exec: - header->e_type = ET_EXEC; - break; - default: - llvm::errs() << "unspported output file type: " << pConfig.codeGenType() << ".\n"; - header->e_type = ET_NONE; - } - header->e_machine = target().getInfo().machine(); - header->e_version = header->e_ident[EI_VERSION]; - header->e_entry = getEntryPoint(pConfig, pModule); - - if (LinkerConfig::Object != pConfig.codeGenType()) - header->e_phoff = sizeof(Elf64_Ehdr); - else - header->e_phoff = 0x0; - - header->e_shoff = getELF64LastStartOffset(pModule); - header->e_flags = target().flags(); - header->e_ehsize = sizeof(Elf64_Ehdr); - header->e_phentsize = sizeof(Elf64_Phdr); - header->e_phnum = target().numOfSegments(); - header->e_shentsize = sizeof(Elf64_Shdr); - header->e_shnum = pModule.size(); - header->e_shstrndx = pModule.getSection(".shstrtab")->index(); -} - -/// getEntryPoint -uint64_t ELFWriter::getEntryPoint(const LinkerConfig& pConfig, - const Module& pModule) const -{ - - llvm::StringRef entry_name; - if (pConfig.options().hasEntry()) - entry_name = pConfig.options().entry(); - else - entry_name = target().entry(); - - uint64_t result = 0x0; - - bool issue_warning = (pConfig.options().hasEntry() && - LinkerConfig::Object != pConfig.codeGenType() && - LinkerConfig::DynObj != pConfig.codeGenType()); - - const LDSymbol* entry_symbol = pModule.getNamePool().findSymbol(entry_name); - - // found the symbol - if (NULL != entry_symbol) { - if (entry_symbol->desc() != ResolveInfo::Define && issue_warning) { - llvm::errs() << "WARNING: entry symbol '" - << entry_symbol->name() - << "' exists but is not defined.\n"; - } - result = entry_symbol->value(); - } - // not in the symbol pool - else { - // We should parse entry as a number. - // @ref GNU ld manual, Options -e. e.g., -e 0x1000. - char* endptr; - result = strtoull(entry_name.data(), &endptr, 0); - if (*endptr != '\0') { - if (issue_warning) { - llvm::errs() << "cannot find entry symbol '" - << entry_name.data() - << "'.\n"; - } - result = 0x0; - } - } - return result; -} - -/// emitELF32SectionHeader - emit Elf32_Shdr -void -ELFWriter::emitELF32SectionHeader(const Module& pModule, - const LinkerConfig& pConfig, - MemoryArea& pOutput) const -{ - // emit section header - unsigned int sectNum = pModule.size(); - unsigned int header_size = sizeof(Elf32_Shdr) * sectNum; - MemoryRegion* region = pOutput.request(getELF32LastStartOffset(pModule), header_size); - Elf32_Shdr* shdr = (Elf32_Shdr*)region->start(); - - // Iterate the SectionTable in LDContext - unsigned int sectIdx = 0; - unsigned int shstridx = 0; // NULL section has empty name - for (; sectIdx < sectNum; ++sectIdx) { - const LDSection *ld_sect = pModule.getSectionTable().at(sectIdx); - shdr[sectIdx].sh_name = shstridx; - shdr[sectIdx].sh_type = ld_sect->type(); - shdr[sectIdx].sh_flags = ld_sect->flag(); - shdr[sectIdx].sh_addr = ld_sect->addr(); - shdr[sectIdx].sh_offset = ld_sect->offset(); - shdr[sectIdx].sh_size = ld_sect->size(); - shdr[sectIdx].sh_addralign = ld_sect->align(); - shdr[sectIdx].sh_entsize = getELF32SectEntrySize(*ld_sect); - shdr[sectIdx].sh_link = getSectLink(*ld_sect, pConfig); - shdr[sectIdx].sh_info = getSectInfo(*ld_sect); - - // adjust strshidx - shstridx += ld_sect->name().size() + 1; - } -} - -/// emitELF64SectionHeader - emit Elf64_Shdr -void -ELFWriter::emitELF64SectionHeader(const Module& pModule, - const LinkerConfig& pConfig, - MemoryArea& pOutput) const -{ - // emit section header - unsigned int sectNum = pModule.size(); - unsigned int header_size = sizeof(Elf64_Shdr) * sectNum; - MemoryRegion* region = pOutput.request(getELF64LastStartOffset(pModule), - header_size); - Elf64_Shdr* shdr = (Elf64_Shdr*)region->start(); - - // Iterate the SectionTable in LDContext - unsigned int sectIdx = 0; - unsigned int shstridx = 0; // NULL section has empty name - for (; sectIdx < sectNum; ++sectIdx) { - const LDSection *ld_sect = pModule.getSectionTable().at(sectIdx); - shdr[sectIdx].sh_name = shstridx; - shdr[sectIdx].sh_type = ld_sect->type(); - shdr[sectIdx].sh_flags = ld_sect->flag(); - shdr[sectIdx].sh_addr = ld_sect->addr(); - shdr[sectIdx].sh_offset = ld_sect->offset(); - shdr[sectIdx].sh_size = ld_sect->size(); - shdr[sectIdx].sh_addralign = ld_sect->align(); - shdr[sectIdx].sh_entsize = getELF64SectEntrySize(*ld_sect); - shdr[sectIdx].sh_link = getSectLink(*ld_sect, pConfig); - shdr[sectIdx].sh_info = getSectInfo(*ld_sect); - - // adjust strshidx - shstridx += ld_sect->name().size() + 1; - } -} - - -/// emitELF32ProgramHeader - emit Elf32_Phdr -void ELFWriter::emitELF32ProgramHeader(MemoryArea& pOutput) const -{ - uint64_t start_offset, phdr_size; - - start_offset = sizeof(Elf32_Ehdr); - phdr_size = sizeof(Elf32_Phdr); - // Program header must start directly after ELF header - MemoryRegion *region = pOutput.request(start_offset, - target().numOfSegments() * phdr_size); - - Elf32_Phdr* phdr = (Elf32_Phdr*)region->start(); - - // Iterate the elf segment table in GNULDBackend - size_t index = 0; - ELFSegmentFactory::const_iterator seg = target().elfSegmentTable().begin(), - segEnd = target().elfSegmentTable().end(); - for (; seg != segEnd; ++seg, ++index) { - phdr[index].p_type = (*seg).type(); - phdr[index].p_flags = (*seg).flag(); - phdr[index].p_offset = (*seg).offset(); - phdr[index].p_vaddr = (*seg).vaddr(); - phdr[index].p_paddr = (*seg).paddr(); - phdr[index].p_filesz = (*seg).filesz(); - phdr[index].p_memsz = (*seg).memsz(); - phdr[index].p_align = (*seg).align(); - } -} - -/// emitELF64ProgramHeader - emit ElfR64Phdr -void ELFWriter::emitELF64ProgramHeader(MemoryArea& pOutput) const -{ - uint64_t start_offset, phdr_size; - - start_offset = sizeof(Elf64_Ehdr); - phdr_size = sizeof(Elf64_Phdr); - // Program header must start directly after ELF header - MemoryRegion *region = pOutput.request(start_offset, - target().numOfSegments() * phdr_size); - Elf64_Phdr* phdr = (Elf64_Phdr*)region->start(); - - // Iterate the elf segment table in GNULDBackend - size_t index = 0; - ELFSegmentFactory::const_iterator seg = target().elfSegmentTable().begin(), - segEnd = target().elfSegmentTable().end(); - for (; seg != segEnd; ++seg, ++index) { - phdr[index].p_type = (*seg).type(); - phdr[index].p_flags = (*seg).flag(); - phdr[index].p_offset = (*seg).offset(); - phdr[index].p_vaddr = (*seg).vaddr(); - phdr[index].p_paddr = (*seg).paddr(); - phdr[index].p_filesz = (*seg).filesz(); - phdr[index].p_memsz = (*seg).memsz(); - phdr[index].p_align = (*seg).align(); - } -} - -/// emitELFShStrTab - emit section string table -void -ELFWriter::emitELFShStrTab(const LDSection& pShStrTab, const Module& pModule, - MemoryArea& pOutput) -{ - // write out data - MemoryRegion* region = pOutput.request(pShStrTab.offset(), pShStrTab.size()); - unsigned char* data = region->start(); - size_t shstrsize = 0; - Module::const_iterator section, sectEnd = pModule.end(); - for (section = pModule.begin(); section != sectEnd; ++section) { - strcpy((char*)(data + shstrsize), (*section)->name().data()); - shstrsize += (*section)->name().size() + 1; - } -} - -/// emitSectionData -void -ELFWriter::emitSectionData(const LDSection& pSection, - MemoryRegion& pRegion) const -{ - const SectionData* sd = NULL; - switch (pSection.kind()) { - case LDFileFormat::Relocation: - return; - case LDFileFormat::EhFrame: - sd = &pSection.getEhFrame()->getSectionData(); - break; - default: - sd = pSection.getSectionData(); - break; - } - emitSectionData(*sd, pRegion); -} - -/// emitRelocation -void ELFWriter::emitRelocation(const LinkerConfig& pConfig, - const LDSection& pSection, - MemoryRegion& pRegion) const -{ - const RelocData* sect_data = pSection.getRelocData(); - assert(NULL != sect_data && "SectionData is NULL in emitRelocation!"); - - if (pSection.type() == SHT_REL) - emitRel(pConfig, *sect_data, pRegion); - else if (pSection.type() == SHT_RELA) - emitRela(pConfig, *sect_data, pRegion); - else - llvm::report_fatal_error("unsupported relocation section type!"); -} - - -/// emitRel -void ELFWriter::emitRel(const LinkerConfig& pConfig, - const RelocData& pRelocData, - MemoryRegion& pRegion) const -{ - Elf32_Rel* rel = reinterpret_cast<Elf32_Rel*>(pRegion.start()); - - Relocation* relocation = 0; - FragmentRef* frag_ref = 0; - - for (RelocData::const_iterator it = pRelocData.begin(), - ie = pRelocData.end(); it != ie; ++it, ++rel) { - - relocation = &(llvm::cast<Relocation>(*it)); - frag_ref = &(relocation->targetRef()); - - if(LinkerConfig::DynObj == pConfig.codeGenType() || - LinkerConfig::Exec == pConfig.codeGenType()) { - rel->r_offset = static_cast<Elf32_Addr>( - frag_ref->frag()->getParent()->getSection().addr() + - frag_ref->getOutputOffset()); - } - else { - rel->r_offset = static_cast<Elf32_Addr>(frag_ref->getOutputOffset()); - } - Elf32_Word Index; - if( relocation->symInfo() == NULL ) - Index = 0; - else - Index = static_cast<Elf32_Word>( - f_Backend.getSymbolIdx(relocation->symInfo()->outSymbol())); - - rel->setSymbolAndType(Index, relocation->type()); - } -} - -/// emitRela -void ELFWriter::emitRela(const LinkerConfig& pConfig, - const RelocData& pRelocData, - MemoryRegion& pRegion) const -{ - Elf32_Rela* rel = reinterpret_cast<Elf32_Rela*>(pRegion.start()); - - Relocation* relocation = 0; - FragmentRef* frag_ref = 0; - - for (RelocData::const_iterator it = pRelocData.begin(), - ie = pRelocData.end(); it != ie; ++it, ++rel) { - - relocation = &(llvm::cast<Relocation>(*it)); - frag_ref = &(relocation->targetRef()); - - if(LinkerConfig::DynObj == pConfig.codeGenType() || - LinkerConfig::Exec == pConfig.codeGenType()) { - rel->r_offset = static_cast<Elf32_Addr>( - frag_ref->frag()->getParent()->getSection().addr() + - frag_ref->getOutputOffset()); - } - else { - rel->r_offset = static_cast<Elf32_Addr>(frag_ref->getOutputOffset()); - } - - Elf32_Word Index; - if( relocation->symInfo() == NULL ) - Index = 0; - else - Index = static_cast<Elf32_Word>( - f_Backend.getSymbolIdx(relocation->symInfo()->outSymbol())); - - rel->setSymbolAndType(Index, relocation->type()); - rel->r_addend = relocation->addend(); - } -} - -/// getELF32SectEntrySize - compute Elf32_Shdr::sh_entsize -uint64_t ELFWriter::getELF32SectEntrySize(const LDSection& pSection) const -{ - if (llvm::ELF::SHT_DYNSYM == pSection.type() || - llvm::ELF::SHT_SYMTAB == pSection.type()) - return sizeof(llvm::ELF::Elf32_Sym); - if (llvm::ELF::SHT_REL == pSection.type()) - return sizeof(llvm::ELF::Elf32_Rel); - if (llvm::ELF::SHT_RELA == pSection.type()) - return sizeof(llvm::ELF::Elf32_Rela); - if (llvm::ELF::SHT_HASH == pSection.type()) - return sizeof(llvm::ELF::Elf32_Word); - if (llvm::ELF::SHT_DYNAMIC == pSection.type()) - return sizeof(llvm::ELF::Elf32_Dyn); - return 0x0; -} - -/// getELF64SectEntrySize - compute Elf64_Shdr::sh_entsize -uint64_t ELFWriter::getELF64SectEntrySize(const LDSection& pSection) const -{ - if (llvm::ELF::SHT_DYNSYM == pSection.type() || - llvm::ELF::SHT_SYMTAB == pSection.type()) - return sizeof(llvm::ELF::Elf64_Sym); - if (llvm::ELF::SHT_REL == pSection.type()) - return sizeof(llvm::ELF::Elf64_Rel); - if (llvm::ELF::SHT_RELA == pSection.type()) - return sizeof(llvm::ELF::Elf64_Rela); - if (llvm::ELF::SHT_HASH == pSection.type()) - return sizeof(llvm::ELF::Elf64_Word); - if (llvm::ELF::SHT_DYNAMIC == pSection.type()) - return sizeof(llvm::ELF::Elf64_Dyn); - return 0x0; -} - -/// getSectLink - compute ElfXX_Shdr::sh_link -uint64_t ELFWriter::getSectLink(const LDSection& pSection, - const LinkerConfig& pConfig) const -{ - if (llvm::ELF::SHT_SYMTAB == pSection.type()) - return target().getOutputFormat()->getStrTab().index(); - if (llvm::ELF::SHT_DYNSYM == pSection.type()) - return target().getOutputFormat()->getDynStrTab().index(); - if (llvm::ELF::SHT_DYNAMIC == pSection.type()) - return target().getOutputFormat()->getDynStrTab().index(); - if (llvm::ELF::SHT_HASH == pSection.type()) - return target().getOutputFormat()->getDynSymTab().index(); - if (llvm::ELF::SHT_REL == pSection.type() || - llvm::ELF::SHT_RELA == pSection.type()) { - if (LinkerConfig::Object == pConfig.codeGenType()) - return target().getOutputFormat()->getSymTab().index(); - else - return target().getOutputFormat()->getDynSymTab().index(); - } - // FIXME: currently we link ARM_EXIDX section to output text section here - if (llvm::ELF::SHT_ARM_EXIDX == pSection.type()) - return target().getOutputFormat()->getText().index(); - return llvm::ELF::SHN_UNDEF; -} - -/// getSectInfo - compute ElfXX_Shdr::sh_info -uint64_t ELFWriter::getSectInfo(const LDSection& pSection) const -{ - if (llvm::ELF::SHT_SYMTAB == pSection.type() || - llvm::ELF::SHT_DYNSYM == pSection.type()) - return pSection.getInfo(); - - if (llvm::ELF::SHT_REL == pSection.type() || - llvm::ELF::SHT_RELA == pSection.type()) { - const LDSection* info_link = pSection.getLink(); - if (NULL != info_link) - return info_link->index(); - } - - return 0x0; -} - -/// getELF32LastStartOffset -uint64_t ELFWriter::getELF32LastStartOffset(const Module& pModule) const -{ - const LDSection* lastSect = pModule.back(); - assert(lastSect != NULL); - return Align<32>(lastSect->offset() + lastSect->size()); -} - -/// getELF64LastStartOffset -uint64_t ELFWriter::getELF64LastStartOffset(const Module& pModule) const -{ - const LDSection* lastSect = pModule.back(); - assert(lastSect != NULL); - return Align<64>(lastSect->offset() + lastSect->size()); -} - -/// emitSectionData -void -ELFWriter::emitSectionData(const SectionData& pSD, MemoryRegion& pRegion) const -{ - SectionData::const_iterator fragIter, fragEnd = pSD.end(); - size_t cur_offset = 0; - for (fragIter = pSD.begin(); fragIter != fragEnd; ++fragIter) { - size_t size = fragIter->size(); - switch(fragIter->getKind()) { - case Fragment::Region: { - const RegionFragment& region_frag = llvm::cast<RegionFragment>(*fragIter); - const uint8_t* from = region_frag.getRegion().start(); - memcpy(pRegion.getBuffer(cur_offset), from, size); - break; - } - case Fragment::Alignment: { - // TODO: emit values with different sizes (> 1 byte), and emit nops - AlignFragment& align_frag = llvm::cast<AlignFragment>(*fragIter); - uint64_t count = size / align_frag.getValueSize(); - switch (align_frag.getValueSize()) { - case 1u: - std::memset(pRegion.getBuffer(cur_offset), - align_frag.getValue(), - count); - break; - default: - llvm::report_fatal_error("unsupported value size for align fragment emission yet.\n"); - break; - } - break; - } - case Fragment::Fillment: { - FillFragment& fill_frag = llvm::cast<FillFragment>(*fragIter); - if (0 == size || - 0 == fill_frag.getValueSize() || - 0 == fill_frag.size()) { - // ignore virtual fillment - break; - } - - uint64_t num_tiles = fill_frag.size() / fill_frag.getValueSize(); - for (uint64_t i = 0; i != num_tiles; ++i) { - std::memset(pRegion.getBuffer(cur_offset), - fill_frag.getValue(), - fill_frag.getValueSize()); - } - break; - } - case Fragment::Stub: { - Stub& stub_frag = llvm::cast<Stub>(*fragIter); - memcpy(pRegion.getBuffer(cur_offset), stub_frag.getContent(), size); - break; - } - case Fragment::Null: { - assert(0x0 == size); - break; - } - case Fragment::Target: - llvm::report_fatal_error("Target fragment should not be in a regular section.\n"); - break; - default: - llvm::report_fatal_error("invalid fragment should not be in a regular section.\n"); - break; - } - cur_offset += size; - } -} - diff --git a/lib/LD/EhFrame.cpp b/lib/LD/EhFrame.cpp index df61c24..9d49630 100644 --- a/lib/LD/EhFrame.cpp +++ b/lib/LD/EhFrame.cpp @@ -9,11 +9,18 @@ #include <mcld/LD/EhFrame.h> #include <mcld/LD/LDSection.h> #include <mcld/LD/SectionData.h> -#include <mcld/Support/MemoryRegion.h> #include <mcld/Object/ObjectBuilder.h> +#include <mcld/Support/MemoryRegion.h> +#include <mcld/Support/GCFactory.h> + +#include <llvm/Support/ManagedStatic.h> using namespace mcld; +typedef GCFactory<EhFrame, MCLD_SECTIONS_PER_INPUT> EhFrameFactory; + +static llvm::ManagedStatic<EhFrameFactory> g_EhFrameFactory; + //===----------------------------------------------------------------------===// // EhFrame::CIE //===----------------------------------------------------------------------===// @@ -35,8 +42,12 @@ EhFrame::FDE::FDE(MemoryRegion& pRegion, //===----------------------------------------------------------------------===// // EhFrame //===----------------------------------------------------------------------===// +EhFrame::EhFrame() + : m_pSection(NULL), m_pSectionData(NULL) { +} + EhFrame::EhFrame(LDSection& pSection) - : m_Section(pSection), + : m_pSection(&pSection), m_pSectionData(NULL) { m_pSectionData = SectionData::Create(pSection); } @@ -47,6 +58,37 @@ EhFrame::~EhFrame() // will delete the fragments and we do not need to handle with it. } +EhFrame* EhFrame::Create(LDSection& pSection) +{ + EhFrame* result = g_EhFrameFactory->allocate(); + new (result) EhFrame(pSection); + return result; +} + +void EhFrame::Destroy(EhFrame*& pSection) +{ + pSection->~EhFrame(); + g_EhFrameFactory->deallocate(pSection); + pSection = NULL; +} + +void EhFrame::Clear() +{ + g_EhFrameFactory->clear(); +} + +const LDSection& EhFrame::getSection() const +{ + assert(NULL != m_pSection); + return *m_pSection; +} + +LDSection& EhFrame::getSection() +{ + assert(NULL != m_pSection); + return *m_pSection; +} + void EhFrame::addFragment(RegionFragment& pFrag) { uint32_t offset = 0; diff --git a/lib/LD/EhFrameHdr.cpp b/lib/LD/EhFrameHdr.cpp index 4c0d59c..a00d785 100644 --- a/lib/LD/EhFrameHdr.cpp +++ b/lib/LD/EhFrameHdr.cpp @@ -114,6 +114,12 @@ void EhFrameHdr::emitOutput<32>(MemoryArea& pOutput) pOutput.release(ehframe_region); } +/// emitOutput<64> - write out eh_frame_hdr +template<> +void EhFrameHdr::emitOutput<64>(MemoryArea& pOutput) +{ +} + //===----------------------------------------------------------------------===// // EhFrameHdr //===----------------------------------------------------------------------===// diff --git a/lib/LD/ExecWriter.cpp b/lib/LD/ExecWriter.cpp deleted file mode 100644 index d66cd17..0000000 --- a/lib/LD/ExecWriter.cpp +++ /dev/null @@ -1,16 +0,0 @@ -//===- ExecWriter.cpp ---------------------------------------------------===// -// -// The MCLinker Project -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -#include "mcld/LD/ExecWriter.h" -#include "mcld/Target/TargetLDBackend.h" -#include "mcld/MC/MCLDInput.h" - -using namespace mcld; - -//========================== -// ExecWriter diff --git a/lib/LD/GNUArchiveReader.cpp b/lib/LD/GNUArchiveReader.cpp index 82e4fec..6324824 100644 --- a/lib/LD/GNUArchiveReader.cpp +++ b/lib/LD/GNUArchiveReader.cpp @@ -89,6 +89,10 @@ bool GNUArchiveReader::isThinArchive(Input& pInput) const bool GNUArchiveReader::readArchive(Archive& pArchive) { + // bypass the empty archive + if (Archive::MAGIC_LEN == pArchive.getARFile().memArea()->handler()->size()) + return true; + if (pArchive.getARFile().attribute()->isWholeArchive()) return includeAllMembers(pArchive); diff --git a/lib/LD/LDSymbol.cpp b/lib/LD/LDSymbol.cpp index c6fab43..9002235 100644 --- a/lib/LD/LDSymbol.cpp +++ b/lib/LD/LDSymbol.cpp @@ -19,10 +19,10 @@ using namespace mcld; -static LDSymbol* g_NullSymbol = NULL; - typedef GCFactory<LDSymbol, MCLD_SYMBOLS_PER_INPUT> LDSymbolFactory; +static llvm::ManagedStatic<LDSymbol> g_NullSymbol; +static llvm::ManagedStatic<NullFragment> g_NullSymbolFragment; static llvm::ManagedStatic<LDSymbolFactory> g_LDSymbolFactory; //===----------------------------------------------------------------------===// @@ -72,14 +72,13 @@ void LDSymbol::Clear() LDSymbol* LDSymbol::Null() { - if (NULL == g_NullSymbol) { - g_NullSymbol = new LDSymbol(); + // lazy initialization + if (NULL == g_NullSymbol->resolveInfo()) { g_NullSymbol->setResolveInfo(*ResolveInfo::Null()); - NullFragment* null_frag = new NullFragment(); - g_NullSymbol->setFragmentRef(FragmentRef::Create(*null_frag, 0)); - ResolveInfo::Null()->setSymPtr(g_NullSymbol); + g_NullSymbol->setFragmentRef(FragmentRef::Create(*g_NullSymbolFragment, 0)); + ResolveInfo::Null()->setSymPtr(&*g_NullSymbol); } - return g_NullSymbol; + return &*g_NullSymbol; } void LDSymbol::setFragmentRef(FragmentRef* pFragmentRef) diff --git a/lib/LD/LDWriter.cpp b/lib/LD/LDWriter.cpp deleted file mode 100644 index e78f087..0000000 --- a/lib/LD/LDWriter.cpp +++ /dev/null @@ -1,15 +0,0 @@ -//===- LDWriter.cpp -------------------------------------------------------===// -// -// The MCLinker Project -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -#include "mcld/LD/LDWriter.h" - -using namespace mcld; - -//========================== -// LDReader - diff --git a/lib/LD/NamePool.cpp b/lib/LD/NamePool.cpp index 6af1f7d..7fb8688 100644 --- a/lib/LD/NamePool.cpp +++ b/lib/LD/NamePool.cpp @@ -22,6 +22,11 @@ NamePool::NamePool(NamePool::size_type pSize) NamePool::~NamePool() { delete m_pResolver; + + FreeInfoSet::iterator info, iEnd = m_FreeInfoSet.end(); + for (info = m_FreeInfoSet.begin(); info != iEnd; ++info) { + ResolveInfo::Destroy(*info); + } } /// createSymbol - create a symbol @@ -33,15 +38,16 @@ ResolveInfo* NamePool::createSymbol(const llvm::StringRef& pName, ResolveInfo::SizeType pSize, ResolveInfo::Visibility pVisibility) { - ResolveInfo* result = ResolveInfo::Create(pName); - result->setIsSymbol(true); - result->setSource(pIsDyn); - result->setType(pType); - result->setDesc(pDesc); - result->setBinding(pBinding); - result->setVisibility(pVisibility); - result->setSize(pSize); - return result; + ResolveInfo** result = m_FreeInfoSet.allocate(); + (*result) = ResolveInfo::Create(pName); + (*result)->setIsSymbol(true); + (*result)->setSource(pIsDyn); + (*result)->setType(pType); + (*result)->setDesc(pDesc); + (*result)->setBinding(pBinding); + (*result)->setVisibility(pVisibility); + (*result)->setSize(pSize); + return *result; } /// insertSymbol - insert a symbol and resolve it immediately @@ -65,7 +71,6 @@ void NamePool::insertSymbol(const llvm::StringRef& pName, ResolveInfo* old_symbol = m_Table.insert(pName, exist); ResolveInfo* new_symbol = NULL; if (exist && old_symbol->isSymbol()) { - exist = true; new_symbol = m_Table.getEntryFactory().produce(pName); } else { @@ -82,7 +87,7 @@ void NamePool::insertSymbol(const llvm::StringRef& pName, new_symbol->setSize(pSize); if (!exist) { - // not exit or not a symbol + // old_symbol is neither existed nor a symbol. pResult.info = new_symbol; pResult.existent = false; pResult.overriden = true; @@ -102,8 +107,11 @@ void NamePool::insertSymbol(const llvm::StringRef& pName, pResult.existent = true; pResult.overriden = override; } - else + else { m_pResolver->resolveAgain(*this, action, *old_symbol, *new_symbol, pResult); + } + + m_Table.getEntryFactory().destroy(new_symbol); return; } diff --git a/lib/LD/ObjectWriter.cpp b/lib/LD/ObjectWriter.cpp index 15691f2..17d04eb 100644 --- a/lib/LD/ObjectWriter.cpp +++ b/lib/LD/ObjectWriter.cpp @@ -7,14 +7,12 @@ // //===----------------------------------------------------------------------===// #include <mcld/LD/ObjectWriter.h> -#include <mcld/MC/MCLDInput.h> -#include <mcld/Target/GNULDBackend.h> using namespace mcld; //========================== // ObjectWriter -ObjectWriter::ObjectWriter(GNULDBackend& pBackend) +ObjectWriter::ObjectWriter() { } diff --git a/lib/LD/RelocationFactory.cpp b/lib/LD/RelocationFactory.cpp index 52bf45c..8a065a8 100644 --- a/lib/LD/RelocationFactory.cpp +++ b/lib/LD/RelocationFactory.cpp @@ -71,18 +71,16 @@ Relocation* RelocationFactory::produce(RelocationFactory::Type pType, pFragRef.memcpy(&target_data, (m_pConfig->targets().bitclass()/8)); } - Relocation *result = allocate(); + Relocation* result = allocate(); new (result) Relocation(pType, &pFragRef, pAddend, target_data); return result; } Relocation* RelocationFactory::produceEmptyEntry() { - // FIXME: To prevent relocations from double free by both iplist and - // GCFactory, currently we new relocations directly and let iplist - // delete them. - - return new Relocation(0, 0, 0, 0); + Relocation* result = allocate(); + new (result) Relocation(0, 0, 0, 0); + return result; } void RelocationFactory::destroy(Relocation* pRelocation) diff --git a/lib/LD/LDObjectWriter.cpp b/lib/LD/Relocator.cpp index d08c6a7..d9dfb61 100644 --- a/lib/LD/LDObjectWriter.cpp +++ b/lib/LD/Relocator.cpp @@ -1,4 +1,4 @@ -//===- LDObjectWriter.cpp -------------------------------------------------===// +//===- Relocator.cpp ------------------------------------------------------===// // // The MCLinker Project // @@ -6,18 +6,14 @@ // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// -#include "mcld/MC/MCObjectWriter.h" +#include <mcld/LD/Relocator.h> using namespace mcld; -//========================== -// MCObjectWriter - - -MCObjectWriter::MCObjectWriter() +//===----------------------------------------------------------------------===// +// Relocator +//===----------------------------------------------------------------------===// +Relocator::~Relocator() { } -MCObjectWriter::~MCObjectWriter() -{ -} diff --git a/lib/LD/ResolveInfo.cpp b/lib/LD/ResolveInfo.cpp index 00df6ae..42ee83c 100644 --- a/lib/LD/ResolveInfo.cpp +++ b/lib/LD/ResolveInfo.cpp @@ -275,6 +275,7 @@ ResolveInfo* ResolveInfo::Null() new (g_NullResolveInfo) ResolveInfo(); g_NullResolveInfo->m_Name[0] = '\0'; g_NullResolveInfo->m_BitField = 0x0; + g_NullResolveInfo->setBinding(Local); } return g_NullResolveInfo; } diff --git a/lib/LD/StubFactory.cpp b/lib/LD/StubFactory.cpp index cbe14b2..0124ec0 100644 --- a/lib/LD/StubFactory.cpp +++ b/lib/LD/StubFactory.cpp @@ -7,13 +7,13 @@ // //===----------------------------------------------------------------------===// #include <mcld/LD/StubFactory.h> +#include <mcld/IRBuilder.h> #include <mcld/LD/BranchIslandFactory.h> #include <mcld/LD/BranchIsland.h> #include <mcld/LD/LDSymbol.h> #include <mcld/LD/ResolveInfo.h> #include <mcld/Fragment/Stub.h> #include <mcld/Fragment/Relocation.h> -#include <mcld/Fragment/FragmentLinker.h> #include <mcld/Fragment/FragmentRef.h> #include <string> @@ -39,7 +39,7 @@ void StubFactory::addPrototype(Stub* pPrototype) /// create - create a stub if needed, otherwise return NULL Stub* StubFactory::create(Relocation& pReloc, uint64_t pTargetSymValue, - FragmentLinker& pLinker, + IRBuilder& pBuilder, BranchIslandFactory& pBRIslandFactory) { // find if there is a prototype stub for the input relocation @@ -74,9 +74,8 @@ Stub* StubFactory::create(Relocation& pReloc, // create LDSymbol for the stub LDSymbol* symbol = - pLinker.defineSymbol<FragmentLinker::Force, - FragmentLinker::Resolve>(name, - false, // isDyn + pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Resolve>( + name, ResolveInfo::Function, ResolveInfo::Define, ResolveInfo::Local, diff --git a/lib/MC/MCLDInput.cpp b/lib/MC/MCLDInput.cpp index 1fc6cb5..a10466b 100644 --- a/lib/MC/MCLDInput.cpp +++ b/lib/MC/MCLDInput.cpp @@ -9,6 +9,7 @@ #include <mcld/MC/MCLDInput.h> #include <mcld/MC/Attribute.h> #include <mcld/LD/LDContext.h> +#include <mcld/Support/MemoryArea.h> using namespace mcld; @@ -70,5 +71,7 @@ Input::~Input() { // Attribute is deleted by AttributeFactory // MemoryArea is deleted by MemoryAreaFactory + if (NULL != m_pMemArea) + m_pMemArea->clear(); } diff --git a/lib/MC/SearchDirs.cpp b/lib/MC/SearchDirs.cpp index 12d08e2..940553e 100644 --- a/lib/MC/SearchDirs.cpp +++ b/lib/MC/SearchDirs.cpp @@ -56,7 +56,16 @@ bool SearchDirs::insert(const std::string& pPath) m_DirList.push_back(dir); return true; } - return false; + else { + delete dir; + return false; + } + return true; +} + +bool SearchDirs::insert(const char* pPath) +{ + return insert(std::string(pPath)); } bool SearchDirs::insert(const sys::fs::Path& pPath) diff --git a/lib/MC/SymbolCategory.cpp b/lib/MC/SymbolCategory.cpp index f01083f..3c3881a 100644 --- a/lib/MC/SymbolCategory.cpp +++ b/lib/MC/SymbolCategory.cpp @@ -10,6 +10,7 @@ #include <mcld/LD/LDSymbol.h> #include <mcld/LD/ResolveInfo.h> #include <algorithm> +#include <cassert> using namespace mcld; @@ -24,33 +25,34 @@ SymbolCategory::Category::categorize(const ResolveInfo& pInfo) return Category::Local; if (ResolveInfo::Common == pInfo.desc()) return Category::Common; - if (ResolveInfo::Weak == pInfo.binding()) - return Category::Weak; - return Category::Global; + if (ResolveInfo::Default == pInfo.visibility() || + ResolveInfo::Protected == pInfo.visibility()) + return Category::Dynamic; + return Category::Regular; } //===----------------------------------------------------------------------===// // SymbolCategory SymbolCategory::SymbolCategory() { - m_pFile = new Category(Category::File); - m_pLocal = new Category(Category::Local); - m_pTLS = new Category(Category::TLS); - m_pCommon = new Category(Category::Common); - m_pWeak = new Category(Category::Weak); - m_pGlobal = new Category(Category::Global); + m_pFile = new Category(Category::File); + m_pLocal = new Category(Category::Local); + m_pLocalDyn = new Category(Category::LocalDyn); + m_pCommon = new Category(Category::Common); + m_pDynamic = new Category(Category::Dynamic); + m_pRegular = new Category(Category::Regular); - m_pFile->next = m_pLocal; - m_pLocal->next = m_pTLS; - m_pTLS->next = m_pCommon; - m_pCommon->next = m_pWeak; - m_pWeak->next = m_pGlobal; + m_pFile->next = m_pLocal; + m_pLocal->next = m_pLocalDyn; + m_pLocalDyn->next = m_pCommon; + m_pCommon->next = m_pDynamic; + m_pDynamic->next = m_pRegular; - m_pGlobal->prev = m_pWeak; - m_pWeak->prev = m_pCommon; - m_pCommon->prev = m_pTLS; - m_pTLS->prev = m_pLocal; - m_pLocal->prev = m_pFile; + m_pRegular->prev = m_pDynamic; + m_pDynamic->prev = m_pCommon; + m_pCommon->prev = m_pLocalDyn; + m_pLocalDyn->prev = m_pLocal; + m_pLocal->prev = m_pFile; } SymbolCategory::~SymbolCategory() @@ -63,18 +65,14 @@ SymbolCategory::~SymbolCategory() } } -SymbolCategory& SymbolCategory::add(LDSymbol& pSymbol) +SymbolCategory& SymbolCategory::add(LDSymbol& pSymbol, Category::Type pTarget) { + Category* current = m_pRegular; m_OutputSymbols.push_back(&pSymbol); - assert(NULL != pSymbol.resolveInfo()); - Category::Type target = Category::categorize(*pSymbol.resolveInfo()); - - Category* current = m_pGlobal; - // use non-stable bubble sort to arrange the order of symbols. while (NULL != current) { - if (current->type == target) { + if (current->type == pTarget) { current->end++; break; } @@ -91,23 +89,19 @@ SymbolCategory& SymbolCategory::add(LDSymbol& pSymbol) return *this; } -SymbolCategory& SymbolCategory::forceLocal(LDSymbol& pSymbol) +SymbolCategory& SymbolCategory::add(LDSymbol& pSymbol) { - m_OutputSymbols.insert(localEnd(), &pSymbol); - m_pLocal->end++; - m_pTLS->begin++; - m_pTLS->end++; - m_pCommon->begin++; - m_pCommon->end++; - m_pWeak->begin++; - m_pWeak->end++; - m_pGlobal->begin++; - m_pGlobal->end++; + assert(NULL != pSymbol.resolveInfo()); + return add(pSymbol, Category::categorize(*pSymbol.resolveInfo())); +} - return *this; +SymbolCategory& SymbolCategory::forceLocal(LDSymbol& pSymbol) +{ + return add(pSymbol, Category::Local); } -SymbolCategory& SymbolCategory::arrange(LDSymbol& pSymbol, const ResolveInfo& pSourceInfo) +SymbolCategory& SymbolCategory::arrange(LDSymbol& pSymbol, + const ResolveInfo& pSourceInfo) { assert(NULL != pSymbol.resolveInfo()); Category::Type source = Category::categorize(pSourceInfo); @@ -188,27 +182,30 @@ SymbolCategory& SymbolCategory::arrange(LDSymbol& pSymbol, const ResolveInfo& pS SymbolCategory& SymbolCategory::changeCommonsToGlobal() { - if (emptyCommons()) - return *this; - - size_t com_rear = m_pCommon->end - 1; - size_t com_front = m_pCommon->begin; - size_t weak_rear = m_pWeak->end - 1; - size_t weak_size = m_pWeak->end - m_pWeak->begin; - for (size_t sym = com_rear; sym >= com_front; --sym) { - std::swap(m_OutputSymbols[weak_rear], m_OutputSymbols[sym]); - --weak_rear; + // Change Common to Dynamic/Regular + while (!emptyCommons()) { + size_t pos = m_pCommon->end - 1; + switch (Category::categorize(*(m_OutputSymbols[pos]->resolveInfo()))) { + case Category::Dynamic: + m_pCommon->end--; + m_pDynamic->begin--; + break; + case Category::Regular: + std::swap(m_OutputSymbols[pos], m_OutputSymbols[m_pDynamic->end - 1]); + m_pCommon->end--; + m_pDynamic->begin--; + m_pDynamic->end--; + m_pRegular->begin--; + break; + default: + assert(0); + break; + } } - - m_pWeak->begin = m_pCommon->begin; - m_pWeak->end = m_pCommon->begin + weak_size; - m_pGlobal->begin = m_pWeak->end; - m_pCommon->begin = m_pCommon->end = m_pWeak->begin; - return *this; } -SymbolCategory& SymbolCategory::changeLocalToTLS(const LDSymbol& pSymbol) +SymbolCategory& SymbolCategory::changeLocalToDynamic(const LDSymbol& pSymbol) { // find the position of pSymbol from local category size_t pos = m_pLocal->begin; @@ -222,10 +219,10 @@ SymbolCategory& SymbolCategory::changeLocalToTLS(const LDSymbol& pSymbol) if (m_pLocal->end == pos) return *this; - // bubble sort downward to TLS + // bubble sort downward to LocalDyn std::swap(m_OutputSymbols[pos], m_OutputSymbols[m_pLocal->end - 1]); m_pLocal->end--; - m_pTLS->begin--; + m_pLocalDyn->begin--; return *this; } @@ -234,9 +231,19 @@ size_t SymbolCategory::numOfSymbols() const return m_OutputSymbols.size(); } +size_t SymbolCategory::numOfFiles() const +{ + return m_pFile->size(); +} + size_t SymbolCategory::numOfLocals() const { - return (m_pFile->size() + m_pLocal->size() + m_pTLS->size()); + return m_pLocal->size(); +} + +size_t SymbolCategory::numOfLocalDyns() const +{ + return m_pLocalDyn->size(); } size_t SymbolCategory::numOfCommons() const @@ -244,21 +251,34 @@ size_t SymbolCategory::numOfCommons() const return m_pCommon->size(); } +size_t SymbolCategory::numOfDynamics() const +{ + return m_pDynamic->size(); +} + size_t SymbolCategory::numOfRegulars() const { - return (m_pWeak->size() + m_pGlobal->size()); + return m_pRegular->size(); } bool SymbolCategory::empty() const { - return (emptyLocals() && - emptyCommons() && - emptyRegulars()); + return m_OutputSymbols.empty(); +} + +bool SymbolCategory::emptyFiles() const +{ + return m_pFile->empty(); } bool SymbolCategory::emptyLocals() const { - return (m_pFile->empty() && m_pLocal->empty() && m_pTLS->empty()); + return m_pLocal->empty(); +} + +bool SymbolCategory::emptyLocalDyns() const +{ + return m_pLocalDyn->empty(); } bool SymbolCategory::emptyCommons() const @@ -266,9 +286,14 @@ bool SymbolCategory::emptyCommons() const return m_pCommon->empty(); } +bool SymbolCategory::emptyDynamics() const +{ + return m_pDynamic->empty(); +} + bool SymbolCategory::emptyRegulars() const { - return (m_pWeak->empty() && m_pGlobal->empty()); + return m_pRegular->empty(); } SymbolCategory::iterator SymbolCategory::begin() @@ -291,80 +316,126 @@ SymbolCategory::const_iterator SymbolCategory::end() const return m_OutputSymbols.end(); } -SymbolCategory::iterator SymbolCategory::localBegin() +SymbolCategory::iterator SymbolCategory::fileBegin() { return m_OutputSymbols.begin(); } -SymbolCategory::iterator SymbolCategory::localEnd() +SymbolCategory::iterator SymbolCategory::fileEnd() { - iterator iter = m_OutputSymbols.begin(); + iterator iter = fileBegin(); iter += m_pFile->size(); + return iter; +} + +SymbolCategory::const_iterator SymbolCategory::fileBegin() const +{ + return m_OutputSymbols.begin(); +} + +SymbolCategory::const_iterator SymbolCategory::fileEnd() const +{ + const_iterator iter = fileBegin(); + iter += m_pFile->size(); + return iter; +} + +SymbolCategory::iterator SymbolCategory::localBegin() +{ + return fileEnd(); +} + +SymbolCategory::iterator SymbolCategory::localEnd() +{ + iterator iter = localBegin(); iter += m_pLocal->size(); return iter; } SymbolCategory::const_iterator SymbolCategory::localBegin() const { - return m_OutputSymbols.begin(); + return fileEnd(); } SymbolCategory::const_iterator SymbolCategory::localEnd() const { - const_iterator iter = m_OutputSymbols.begin(); - iter += m_pFile->size(); + const_iterator iter = localBegin(); iter += m_pLocal->size(); return iter; } -SymbolCategory::iterator SymbolCategory::tlsBegin() +SymbolCategory::iterator SymbolCategory::localDynBegin() { return localEnd(); } -SymbolCategory::iterator SymbolCategory::tlsEnd() +SymbolCategory::iterator SymbolCategory::localDynEnd() { - iterator iter = localEnd(); - iter += m_pTLS->size(); + iterator iter = localDynBegin(); + iter += m_pLocalDyn->size(); return iter; } -SymbolCategory::const_iterator SymbolCategory::tlsBegin() const +SymbolCategory::const_iterator SymbolCategory::localDynBegin() const { return localEnd(); } -SymbolCategory::const_iterator SymbolCategory::tlsEnd() const +SymbolCategory::const_iterator SymbolCategory::localDynEnd() const { - const_iterator iter = localEnd(); - iter += m_pTLS->size(); + const_iterator iter = localDynBegin(); + iter += m_pLocalDyn->size(); return iter; } SymbolCategory::iterator SymbolCategory::commonBegin() { - return tlsEnd(); + return localDynEnd(); } SymbolCategory::iterator SymbolCategory::commonEnd() { - iterator iter = tlsEnd(); + iterator iter = commonBegin(); iter += m_pCommon->size(); return iter; } SymbolCategory::const_iterator SymbolCategory::commonBegin() const { - return tlsEnd(); + return localDynEnd(); } SymbolCategory::const_iterator SymbolCategory::commonEnd() const { - const_iterator iter = tlsEnd(); + const_iterator iter = commonBegin(); iter += m_pCommon->size(); return iter; } +SymbolCategory::iterator SymbolCategory::dynamicBegin() +{ + return commonEnd(); +} + +SymbolCategory::iterator SymbolCategory::dynamicEnd() +{ + iterator iter = dynamicBegin(); + iter += m_pDynamic->size(); + return iter; +} + +SymbolCategory::const_iterator SymbolCategory::dynamicBegin() const +{ + return commonEnd(); +} + +SymbolCategory::const_iterator SymbolCategory::dynamicEnd() const +{ + const_iterator iter = dynamicBegin(); + iter += m_pDynamic->size(); + return iter; +} + SymbolCategory::iterator SymbolCategory::regularBegin() { return commonEnd(); diff --git a/lib/Object/ObjectBuilder.cpp b/lib/Object/ObjectBuilder.cpp index ec09901..d222110 100644 --- a/lib/Object/ObjectBuilder.cpp +++ b/lib/Object/ObjectBuilder.cpp @@ -49,7 +49,7 @@ LDSection* ObjectBuilder::CreateSection(const std::string& pName, } /// MergeSection - merge the pInput section to the pOutput section -bool ObjectBuilder::MergeSection(LDSection& pInputSection) +LDSection* ObjectBuilder::MergeSection(LDSection& pInputSection) { const SectionMap::NamePair& pair = m_Config.scripts().sectionMap().find(pInputSection.name()); @@ -70,7 +70,7 @@ bool ObjectBuilder::MergeSection(LDSection& pInputSection) case LDFileFormat::Relocation: case LDFileFormat::NamePool: /** do nothing **/ - return true; + return target; case LDFileFormat::EhFrame: { EhFrame* eh_frame = NULL; if (target->hasEhFrame()) @@ -79,7 +79,8 @@ bool ObjectBuilder::MergeSection(LDSection& pInputSection) eh_frame = IRBuilder::CreateEhFrame(*target); eh_frame->merge(*pInputSection.getEhFrame()); - return true; + UpdateSectionAlign(*target, pInputSection); + return target; } default: { SectionData* data = NULL; @@ -88,10 +89,14 @@ bool ObjectBuilder::MergeSection(LDSection& pInputSection) else data = IRBuilder::CreateSectionData(*target); - return MoveSectionData(*pInputSection.getSectionData(), *data); + if (MoveSectionData(*pInputSection.getSectionData(), *data)) { + UpdateSectionAlign(*target, pInputSection); + return target; + } + return NULL; } } - return true; + return target; } /// MoveSectionData - move the fragments of pTO section data to pTo @@ -125,20 +130,19 @@ bool ObjectBuilder::MoveSectionData(SectionData& pFrom, SectionData& pTo) } to_list.splice(to_list.end(), from_list); - // append the null fragment - NullFragment* null = new NullFragment(); - null->setParent(&pTo); - null->setOffset(offset); - pTo.getFragmentList().push_back(null); - // set up pTo's header pTo.getSection().setSize(offset); - if (pFrom.getSection().align() > pTo.getSection().align()) - pTo.getSection().setAlign(pFrom.getSection().align()); return true; } +/// UpdateSectionFlags - update alignment for input section +void ObjectBuilder::UpdateSectionAlign(LDSection& pTo, const LDSection& pFrom) +{ + if (pFrom.align() > pTo.align()) + pTo.setAlign(pFrom.align()); +} + /// AppendFragment - To append pFrag to the given SectionData pSD. uint64_t ObjectBuilder::AppendFragment(Fragment& pFrag, SectionData& pSD, diff --git a/lib/Object/ObjectLinker.cpp b/lib/Object/ObjectLinker.cpp index 1e2ccb4..bbca437 100644 --- a/lib/Object/ObjectLinker.cpp +++ b/lib/Object/ObjectLinker.cpp @@ -21,9 +21,6 @@ #include <mcld/LD/GroupReader.h> #include <mcld/LD/BinaryReader.h> #include <mcld/LD/ObjectWriter.h> -#include <mcld/LD/DynObjWriter.h> -#include <mcld/LD/ExecWriter.h> -#include <mcld/LD/BinaryWriter.h> #include <mcld/LD/ResolveInfo.h> #include <mcld/LD/RelocData.h> #include <mcld/Support/RealPath.h> @@ -35,32 +32,23 @@ #include <llvm/Support/Casting.h> + using namespace llvm; using namespace mcld; ObjectLinker::ObjectLinker(const LinkerConfig& pConfig, - Module& pModule, - IRBuilder& pBuilder, TargetLDBackend& pLDBackend) : m_Config(pConfig), - m_Module(pModule), - m_Builder(pBuilder), m_pLinker(NULL), + m_pModule(NULL), + m_pBuilder(NULL), m_LDBackend(pLDBackend), m_pObjectReader(NULL), m_pDynObjReader(NULL), m_pArchiveReader(NULL), m_pGroupReader(NULL), m_pBinaryReader(NULL), - m_pObjectWriter(NULL), - m_pDynObjWriter(NULL), - m_pExecWriter(NULL), - m_pBinaryWriter(NULL) -{ - // set up soname - if (!m_Config.options().soname().empty()) { - m_Module.setName(m_Config.options().soname()); - } + m_pWriter(NULL) { } ObjectLinker::~ObjectLinker() @@ -71,10 +59,17 @@ ObjectLinker::~ObjectLinker() delete m_pArchiveReader; delete m_pGroupReader; delete m_pBinaryReader; - delete m_pObjectWriter; - delete m_pDynObjWriter; - delete m_pExecWriter; - delete m_pBinaryWriter; + delete m_pWriter; +} + +void ObjectLinker::setup(Module& pModule, IRBuilder& pBuilder) +{ + m_pModule = &pModule; + m_pBuilder = &pBuilder; + // set up soname + if (!m_Config.options().soname().empty()) { + m_pModule->setName(m_Config.options().soname()); + } } /// initFragmentLinker - initialize FragmentLinker @@ -83,49 +78,37 @@ bool ObjectLinker::initFragmentLinker() { if (NULL == m_pLinker) { m_pLinker = new FragmentLinker(m_Config, - m_Module, + *m_pModule, m_LDBackend); } // initialize the readers and writers // Because constructor can not be failed, we initalize all readers and // writers outside the FragmentLinker constructors. - m_pObjectReader = m_LDBackend.createObjectReader(m_Builder); - m_pArchiveReader = m_LDBackend.createArchiveReader(m_Module); - m_pDynObjReader = m_LDBackend.createDynObjReader(m_Builder); - m_pGroupReader = new GroupReader(m_Module, *m_pObjectReader, + m_pObjectReader = m_LDBackend.createObjectReader(*m_pBuilder); + m_pArchiveReader = m_LDBackend.createArchiveReader(*m_pModule); + m_pDynObjReader = m_LDBackend.createDynObjReader(*m_pBuilder); + m_pGroupReader = new GroupReader(*m_pModule, *m_pObjectReader, *m_pDynObjReader, *m_pArchiveReader); - m_pBinaryReader = m_LDBackend.createBinaryReader(m_Builder); - m_pObjectWriter = m_LDBackend.createObjectWriter(); - m_pDynObjWriter = m_LDBackend.createDynObjWriter(); - m_pExecWriter = m_LDBackend.createExecWriter(); - m_pBinaryWriter = m_LDBackend.createBinaryWriter(); + m_pBinaryReader = m_LDBackend.createBinaryReader(*m_pBuilder); + m_pWriter = m_LDBackend.createWriter(); // initialize Relocator - m_LDBackend.initRelocator(*m_pLinker); - - // initialize BranchIslandFactory - m_LDBackend.initBRIslandFactory(); - - // initialize StubFactory - m_LDBackend.initStubFactory(); - - // initialize target stubs - m_LDBackend.initTargetStubs(*m_pLinker); + m_LDBackend.initRelocator(); return true; } /// initStdSections - initialize standard sections bool ObjectLinker::initStdSections() { - ObjectBuilder builder(m_Config, m_Module); + ObjectBuilder builder(m_Config, *m_pModule); // initialize standard sections if (!m_LDBackend.initStdSections(builder)) return false; // initialize target-dependent sections - m_LDBackend.initTargetSections(m_Module, builder); + m_LDBackend.initTargetSections(*m_pModule, builder); return true; } @@ -133,11 +116,11 @@ bool ObjectLinker::initStdSections() void ObjectLinker::normalize() { // ----- set up inputs ----- // - Module::input_iterator input, inEnd = m_Module.input_end(); - for (input = m_Module.input_begin(); input!=inEnd; ++input) { + Module::input_iterator input, inEnd = m_pModule->input_end(); + for (input = m_pModule->input_begin(); input!=inEnd; ++input) { // is a group node if (isGroup(input)) { - getGroupReader()->readGroup(input, m_Builder.getInputBuilder(), m_Config); + getGroupReader()->readGroup(input, m_pBuilder->getInputBuilder(), m_Config); continue; } @@ -149,12 +132,12 @@ void ObjectLinker::normalize() continue; if (Input::Object == (*input)->type()) { - m_Module.getObjectList().push_back(*input); + m_pModule->getObjectList().push_back(*input); continue; } if (Input::DynObj == (*input)->type()) { - m_Module.getLibraryList().push_back(*input); + m_pModule->getLibraryList().push_back(*input); continue; } @@ -162,7 +145,7 @@ void ObjectLinker::normalize() if (m_Config.options().isBinaryInput()) { (*input)->setType(Input::Object); getBinaryReader()->readBinary(**input); - m_Module.getObjectList().push_back(*input); + m_pModule->getObjectList().push_back(*input); } // is a relocatable object file else if (getObjectReader()->isMyFormat(**input)) { @@ -170,22 +153,22 @@ void ObjectLinker::normalize() getObjectReader()->readHeader(**input); getObjectReader()->readSections(**input); getObjectReader()->readSymbols(**input); - m_Module.getObjectList().push_back(*input); + m_pModule->getObjectList().push_back(*input); } // is a shared object file else if (getDynObjReader()->isMyFormat(**input)) { (*input)->setType(Input::DynObj); getDynObjReader()->readHeader(**input); getDynObjReader()->readSymbols(**input); - m_Module.getLibraryList().push_back(*input); + m_pModule->getLibraryList().push_back(*input); } // is an archive else if (getArchiveReader()->isMyFormat(**input)) { (*input)->setType(Input::Archive); - Archive archive(**input, m_Builder.getInputBuilder()); + Archive archive(**input, m_pBuilder->getInputBuilder()); getArchiveReader()->readArchive(archive); if(archive.numOfObjectMember() > 0) { - m_Module.getInputTree().merge<InputTree::Inclusive>(input, + m_pModule->getInputTree().merge<InputTree::Inclusive>(input, archive.inputs()); } } @@ -199,14 +182,14 @@ void ObjectLinker::normalize() bool ObjectLinker::linkable() const { // check we have input and output files - if (m_Module.getInputTree().empty()) { + if (m_pModule->getInputTree().empty()) { error(diag::err_no_inputs); return false; } // can not mix -static with shared objects - Module::const_lib_iterator lib, libEnd = m_Module.lib_end(); - for (lib = m_Module.lib_begin(); lib != libEnd; ++lib) { + Module::const_lib_iterator lib, libEnd = m_pModule->lib_end(); + for (lib = m_pModule->lib_begin(); lib != libEnd; ++lib) { if((*lib)->attribute()->isStatic()) { error(diag::err_mixed_shared_static_objects) << (*lib)->name() << (*lib)->path(); @@ -214,7 +197,21 @@ bool ObjectLinker::linkable() const } } - // can not mix -r with shared objects + // --nmagic and --omagic options lead to static executable program. + // These options turn off page alignment of sections. Because the + // sections are not aligned to pages, these sections can not contain any + // exported functions. Also, because the two options disable linking + // against shared libraries, the output absolutely does not call outside + // functions. + if (m_Config.options().nmagic() && !m_Config.isCodeStatic()) { + error(diag::err_nmagic_not_static); + return false; + } + if (m_Config.options().omagic() && !m_Config.isCodeStatic()) { + error(diag::err_omagic_not_static); + return false; + } + return true; } @@ -225,8 +222,8 @@ bool ObjectLinker::readRelocations() { // Bitcode is read by the other path. This function reads relocation sections // in object files. - mcld::InputTree::bfs_iterator input, inEnd = m_Module.getInputTree().bfs_end(); - for (input=m_Module.getInputTree().bfs_begin(); input!=inEnd; ++input) { + mcld::InputTree::bfs_iterator input, inEnd = m_pModule->getInputTree().bfs_end(); + for (input=m_pModule->getInputTree().bfs_begin(); input!=inEnd; ++input) { if ((*input)->type() == Input::Object && (*input)->hasMemArea()) { if (!getObjectReader()->readRelocations(**input)) return false; @@ -239,9 +236,9 @@ bool ObjectLinker::readRelocations() /// mergeSections - put allinput sections into output sections bool ObjectLinker::mergeSections() { - ObjectBuilder builder(m_Config, m_Module); - Module::obj_iterator obj, objEnd = m_Module.obj_end(); - for (obj = m_Module.obj_begin(); obj != objEnd; ++obj) { + ObjectBuilder builder(m_Config, *m_pModule); + Module::obj_iterator obj, objEnd = m_pModule->obj_end(); + for (obj = m_pModule->obj_begin(); obj != objEnd; ++obj) { LDContext::sect_iterator sect, sectEnd = (*obj)->context()->sectEnd(); for (sect = (*obj)->context()->sectBegin(); sect != sectEnd; ++sect) { switch ((*sect)->kind()) { @@ -255,7 +252,7 @@ bool ObjectLinker::mergeSections() // skip continue; case LDFileFormat::Target: - if (!m_LDBackend.mergeSection(m_Module, **sect)) { + if (!m_LDBackend.mergeSection(*m_pModule, **sect)) { error(diag::err_cannot_merge_section) << (*sect)->name() << (*obj)->name(); return false; @@ -265,7 +262,7 @@ bool ObjectLinker::mergeSections() if (!(*sect)->hasEhFrame()) continue; // skip - if (!builder.MergeSection(**sect)) { + if (NULL == builder.MergeSection(**sect)) { error(diag::err_cannot_merge_section) << (*sect)->name() << (*obj)->name(); return false; @@ -276,7 +273,15 @@ bool ObjectLinker::mergeSections() if (!(*sect)->hasSectionData()) continue; // skip - if (!builder.MergeSection(**sect)) { + LDSection* out_sect = builder.MergeSection(**sect); + if (NULL != out_sect) { + if (!m_LDBackend.updateSectionFlags(*out_sect, **sect)) { + error(diag::err_cannot_merge_section) << (*sect)->name() + << (*obj)->name(); + return false; + } + } + else { error(diag::err_cannot_merge_section) << (*sect)->name() << (*obj)->name(); return false; @@ -296,12 +301,12 @@ bool ObjectLinker::mergeSections() bool ObjectLinker::addStandardSymbols() { // create and add section symbols for each output section - Module::iterator iter, iterEnd = m_Module.end(); - for (iter = m_Module.begin(); iter != iterEnd; ++iter) { - m_Module.getSectionSymbolSet().add(**iter, m_Module.getNamePool()); + Module::iterator iter, iterEnd = m_pModule->end(); + for (iter = m_pModule->begin(); iter != iterEnd; ++iter) { + m_pModule->getSectionSymbolSet().add(**iter, m_pModule->getNamePool()); } - return m_LDBackend.initStandardSymbols(*m_pLinker, m_Module); + return m_LDBackend.initStandardSymbols(*m_pBuilder, *m_pModule); } /// addTargetSymbols - some targets, such as MIPS and ARM, need some @@ -310,15 +315,24 @@ bool ObjectLinker::addStandardSymbols() /// target symbols, return false bool ObjectLinker::addTargetSymbols() { - m_LDBackend.initTargetSymbols(*m_pLinker); + m_LDBackend.initTargetSymbols(*m_pBuilder, *m_pModule); + return true; +} + +/// addScriptSymbols - define symbols from the command line option or linker +/// scripts. +/// @return if there are some existing symbols with identical name to the +/// script symbols, return false. +bool ObjectLinker::addScriptSymbols() +{ return true; } bool ObjectLinker::scanRelocations() { // apply all relocations of all inputs - Module::obj_iterator input, inEnd = m_Module.obj_end(); - for (input = m_Module.obj_begin(); input != inEnd; ++input) { + Module::obj_iterator input, inEnd = m_pModule->obj_end(); + for (input = m_pModule->obj_begin(); input != inEnd; ++input) { LDContext::sect_iterator rs, rsEnd = (*input)->context()->relocSectEnd(); for (rs = (*input)->context()->relocSectBegin(); rs != rsEnd; ++rs) { // bypass the reloc section if @@ -332,42 +346,54 @@ bool ObjectLinker::scanRelocations() for (reloc = (*rs)->getRelocData()->begin(); reloc != rEnd; ++reloc) { Relocation* relocation = llvm::cast<Relocation>(reloc); // scan relocation - if (LinkerConfig::Object != m_Config.codeGenType()) { - m_LDBackend.scanRelocation(*relocation, - *m_pLinker, - m_Module, - *(*rs)->getLink()); - } - else { - m_LDBackend.partialScanRelocation(*relocation, - *m_pLinker, - m_Module, - *(*rs)->getLink()); - } + if (LinkerConfig::Object != m_Config.codeGenType()) + m_LDBackend.scanRelocation(*relocation, *m_pBuilder, *m_pModule, **rs); + else + m_LDBackend.partialScanRelocation(*relocation, *m_pModule, **rs); } // for all relocations } // for all relocation section } // for all inputs return true; } +/// initStubs - initialize stub-related stuff. +bool ObjectLinker::initStubs() +{ + // initialize BranchIslandFactory + m_LDBackend.initBRIslandFactory(); + + // initialize StubFactory + m_LDBackend.initStubFactory(); + + // initialize target stubs + m_LDBackend.initTargetStubs(); + return true; +} + +/// allocateCommonSymobols - allocate fragments for common symbols to the +/// corresponding sections +bool ObjectLinker::allocateCommonSymbols() +{ + if (LinkerConfig::Object != m_Config.codeGenType() || + m_Config.options().isDefineCommon()) + return m_LDBackend.allocateCommonSymbols(*m_pModule); + return true; +} + /// prelayout - help backend to do some modification before layout bool ObjectLinker::prelayout() { // finalize the section symbols, set their fragment reference and push them // into output symbol table - Module::iterator sect, sEnd = m_Module.end(); - for (sect = m_Module.begin(); sect != sEnd; ++sect) { - m_Module.getSectionSymbolSet().finalize(**sect, m_Module.getSymbolTable()); + Module::iterator sect, sEnd = m_pModule->end(); + for (sect = m_pModule->begin(); sect != sEnd; ++sect) { + m_pModule->getSectionSymbolSet().finalize(**sect, m_pModule->getSymbolTable()); } - m_LDBackend.preLayout(m_Module, *m_pLinker); - - if (LinkerConfig::Object != m_Config.codeGenType() || - m_Config.options().isDefineCommon()) - m_LDBackend.allocateCommonSymbols(m_Module); + m_LDBackend.preLayout(*m_pModule, *m_pBuilder); /// check program interpreter - computer the name size of the runtime dyld - if (!m_pLinker->isStaticLink() && + if (!m_Config.isCodeStatic() && (LinkerConfig::Exec == m_Config.codeGenType() || m_Config.options().isPIE() || m_Config.options().hasDyld())) @@ -379,7 +405,7 @@ bool ObjectLinker::prelayout() /// /// dump all symbols and strings from FragmentLinker and build the format-dependent /// hash table. - m_LDBackend.sizeNamePools(m_Module, m_pLinker->isStaticLink()); + m_LDBackend.sizeNamePools(*m_pModule, m_Config.isCodeStatic()); return true; } @@ -391,14 +417,14 @@ bool ObjectLinker::prelayout() /// directly bool ObjectLinker::layout() { - m_LDBackend.layout(m_Module, *m_pLinker); + m_LDBackend.layout(*m_pModule); return true; } /// prelayout - help backend to do some modification after layout bool ObjectLinker::postlayout() { - m_LDBackend.postLayout(m_Module, *m_pLinker); + m_LDBackend.postLayout(*m_pModule, *m_pBuilder); return true; } @@ -407,7 +433,7 @@ bool ObjectLinker::postlayout() /// symbol. bool ObjectLinker::finalizeSymbolValue() { - return m_pLinker->finalizeSymbols(); + return (m_pLinker->finalizeSymbols() && m_LDBackend.finalizeSymbols()); } /// relocate - applying relocation entries and create relocation @@ -423,23 +449,7 @@ bool ObjectLinker::relocation() /// emitOutput - emit the output file. bool ObjectLinker::emitOutput(MemoryArea& pOutput) { - switch(m_Config.codeGenType()) { - case LinkerConfig::Object: - getObjectWriter()->writeObject(m_Module, pOutput); - return true; - case LinkerConfig::DynObj: - getDynObjWriter()->writeDynObj(m_Module, pOutput); - return true; - case LinkerConfig::Exec: - getExecWriter()->writeExecutable(m_Module, pOutput); - return true; - case LinkerConfig::Binary: - getBinaryWriter()->writeBinary(m_Module, pOutput); - return true; - default: - fatal(diag::unrecognized_output_file) << m_Config.codeGenType(); - } - return false; + return llvm::errc::success == getWriter()->writeObject(*m_pModule, pOutput); } /// postProcessing - do modification after all processes @@ -450,7 +460,7 @@ bool ObjectLinker::postProcessing(MemoryArea& pOutput) // emit .eh_frame_hdr // eh_frame_hdr should be emitted after syncRelocation, because eh_frame_hdr // needs FDE PC value, which will be corrected at syncRelocation - m_LDBackend.postProcessing(*m_pLinker, pOutput); + m_LDBackend.postProcessing(pOutput); return true; } diff --git a/lib/Support/Directory.cpp b/lib/Support/Directory.cpp index 78bb761..a47b162 100644 --- a/lib/Support/Directory.cpp +++ b/lib/Support/Directory.cpp @@ -26,8 +26,9 @@ bool is_symlink(FileStatus f) } // namespace of anonymous -//========================== +//===----------------------------------------------------------------------===// // Directory +//===----------------------------------------------------------------------===// Directory::Directory() : m_Path(), m_FileStatus(), @@ -165,16 +166,16 @@ DirIterator::~DirIterator() Path* DirIterator::path() { - if (m_pParent == 0) // end - return 0; - return m_pEntry->value(); + if (NULL == m_pParent) + return NULL; + return &m_pEntry->value(); } const Path* DirIterator::path() const { - if (m_pParent == 0) // end - return 0; - return m_pEntry->value(); + if (NULL == m_pParent) + return NULL; + return &m_pEntry->value(); } DirIterator& DirIterator::operator=(const DirIterator& pCopy) diff --git a/lib/Support/FileHandle.cpp b/lib/Support/FileHandle.cpp index 4800bfa..7876ac6 100644 --- a/lib/Support/FileHandle.cpp +++ b/lib/Support/FileHandle.cpp @@ -6,6 +6,7 @@ // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// +#include "mcld/Config/Config.h" #include <mcld/Support/FileHandle.h> #include <mcld/Support/FileSystem.h> #include <errno.h> @@ -127,7 +128,7 @@ bool FileHandle::delegate(int pFD, FileHandle::OpenMode pMode) m_Handler = pFD; m_OpenMode = pMode; - m_State = GoodBit; + m_State = (GoodBit | DeputedBit); if (!get_size(m_Handler, m_Size)) { setState(FailBit); @@ -144,9 +145,11 @@ bool FileHandle::close() return false; } - if (-1 == ::close(m_Handler)) { - setState(FailBit); - return false; + if (isOwned()) { + if (-1 == ::close(m_Handler)) { + setState(FailBit); + return false; + } } m_Path.native().clear(); @@ -327,3 +330,8 @@ bool FileHandle::isFailed() const return (m_State & (BadBit | FailBit)); } +bool FileHandle::isOwned() const +{ + return !(m_State & DeputedBit); +} + diff --git a/lib/Support/FileSystem.cpp b/lib/Support/FileSystem.cpp index fb2633d..715960e 100644 --- a/lib/Support/FileSystem.cpp +++ b/lib/Support/FileSystem.cpp @@ -6,6 +6,7 @@ // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// +#include "mcld/Config/Config.h" #include "mcld/Support/FileSystem.h" #include "mcld/Support/Path.h" diff --git a/lib/Support/MemoryArea.cpp b/lib/Support/MemoryArea.cpp index 3a3fa0c..b5873bf 100644 --- a/lib/Support/MemoryArea.cpp +++ b/lib/Support/MemoryArea.cpp @@ -32,11 +32,6 @@ MemoryArea::MemoryArea(FileHandle& pFileHandle) MemoryArea::~MemoryArea() { - SpaceMapType::iterator space, sEnd = m_SpaceMap.end(); - for (space = m_SpaceMap.begin(); space != sEnd; ++space) { - if (space->second != NULL) - Space::Destroy(space->second); - } } // The layout of MemorySpace in the virtual memory space @@ -68,7 +63,7 @@ MemoryRegion* MemoryArea::request(size_t pOffset, size_t pLength) } space = Space::Create(*m_pFileHandle, pOffset, pLength); - m_SpaceMap.insert(std::make_pair(Key(pOffset, pLength), space)); + m_SpaceMap.insert(std::make_pair(Key(space->start(), space->size()), space)); } // adjust r_start @@ -98,8 +93,19 @@ void MemoryArea::release(MemoryRegion* pRegion) // synchronize writable space before we release it. Space::Sync(space, *m_pFileHandle); } - m_SpaceMap.erase(Key(space->start(), space->size())); + + std::pair<SpaceMapType::iterator, SpaceMapType::iterator> range = + m_SpaceMap.equal_range(Key(space->start(), space->size())); + SpaceMapType::iterator it; + for (it = range.first; it != range.second; ++it) { + if (space == it->second) + break; + } + m_SpaceMap.erase(it); + Space::Release(space, *m_pFileHandle); + assert(NULL != space); + Space::Destroy(space); } } } @@ -110,24 +116,23 @@ void MemoryArea::clear() if (NULL == m_pFileHandle) return; + SpaceMapType::iterator space, sEnd = m_SpaceMap.end(); if (m_pFileHandle->isWritable()) { - SpaceMapType::iterator space, sEnd = m_SpaceMap.end(); for (space = m_SpaceMap.begin(); space != sEnd; ++space) { Space::Sync(space->second, *m_pFileHandle); Space::Release(space->second, *m_pFileHandle); + assert(NULL != space->second); + Space::Destroy(space->second); } } else { - SpaceMapType::iterator space, sEnd = m_SpaceMap.end(); - for (space = m_SpaceMap.begin(); space != sEnd; ++space) + for (space = m_SpaceMap.begin(); space != sEnd; ++space) { Space::Release(space->second, *m_pFileHandle); - } - - for (SpaceMapType::iterator space = m_SpaceMap.begin(), - sEnd = m_SpaceMap.end(); space != sEnd; ++space) { - if (space->second != NULL) + assert(NULL != space->second); Space::Destroy(space->second); + } } + m_SpaceMap.clear(); } diff --git a/lib/Support/Path.cpp b/lib/Support/Path.cpp index d359162..ee700c0 100644 --- a/lib/Support/Path.cpp +++ b/lib/Support/Path.cpp @@ -6,6 +6,7 @@ // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// +#include "mcld/Config/Config.h" #include "mcld/Support/FileSystem.h" #include "mcld/Support/Path.h" #include <llvm/ADT/StringRef.h> diff --git a/lib/Support/SystemUtils.cpp b/lib/Support/SystemUtils.cpp index 5dfea36..19c5e90 100644 --- a/lib/Support/SystemUtils.cpp +++ b/lib/Support/SystemUtils.cpp @@ -6,6 +6,7 @@ // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// +#include "mcld/Config/Config.h" #include <mcld/Support/SystemUtils.h> using namespace mcld::sys; diff --git a/lib/Support/UniqueGCFactory.cpp b/lib/Support/UniqueGCFactory.cpp deleted file mode 100644 index 2352181..0000000 --- a/lib/Support/UniqueGCFactory.cpp +++ /dev/null @@ -1,15 +0,0 @@ -//===- UniqueGCFactory.cpp ------------------------------------------------===// -// -// The MCLinker Project -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -#include <UniqueGCFactory.h> - -using namespace mcld; - -//========================== -// UniqueGCFactory - diff --git a/lib/Support/Unix/PathV3.inc b/lib/Support/Unix/PathV3.inc index 68b0c36..1506e94 100644 --- a/lib/Support/Unix/PathV3.inc +++ b/lib/Support/Unix/PathV3.inc @@ -233,7 +233,7 @@ mcld::sys::fs::PathCache::entry_type* bring_one_into_cache(DirIterator& pIter) bool exist = false; entry = pIter.m_pParent->m_Cache.insert(path, exist); if (!exist) - entry->setValue(new Path(path)); + entry->setValue(path); break; } case 0:// meet real end @@ -264,7 +264,7 @@ void open_dir(Directory& pDir) bool exist = false; mcld::sys::fs::PathCache::entry_type* entry = pDir.m_Cache.insert(path, exist); if (!exist) - entry->setValue(new Path(path)); + entry->setValue(path); return; } case 0: diff --git a/lib/Support/raw_ostream.cpp b/lib/Support/raw_ostream.cpp index e294bc3..0b64646 100644 --- a/lib/Support/raw_ostream.cpp +++ b/lib/Support/raw_ostream.cpp @@ -6,6 +6,7 @@ // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// +#include "mcld/Config/Config.h" #include <mcld/Support/raw_ostream.h> #if defined(HAVE_UNISTD_H) diff --git a/lib/Target/ARM/ARMELFArchiveReader.cpp b/lib/Target/ARM/ARMELFArchiveReader.cpp deleted file mode 100644 index 4c6d775..0000000 --- a/lib/Target/ARM/ARMELFArchiveReader.cpp +++ /dev/null @@ -1,14 +0,0 @@ -//===- ARMELFArchiveReader.cpp --------------------------------------------===// -// -// The MCLinker Project -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -#include "ARMELFArchiveReader.h" - -using namespace mcld; - -//========================== -// ARMELFArchiveReader diff --git a/lib/Target/ARM/ARMELFArchiveReader.h b/lib/Target/ARM/ARMELFArchiveReader.h deleted file mode 100644 index 2fa9ce2..0000000 --- a/lib/Target/ARM/ARMELFArchiveReader.h +++ /dev/null @@ -1,29 +0,0 @@ -//===- ARMELFArchiveReader.h ----------------------------------------------===// -// -// The MCLinker Project -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -#ifndef MCLD_ARM_ELF_ARCHIVE_READER_H -#define MCLD_ARM_ELF_ARCHIVE_READER_H -#ifdef ENABLE_UNITTEST -#include <gtest.h> -#endif - -#include "mcld/MC/MCELFArchiveTargetReader.h" - -namespace mcld -{ - -/// ARMELFArchiveReader - ARMELFArchiveReader is -/// a target-dependent reader for ELF archive files. -class ARMELFArchiveReader : public MCELFArchiveTargetReader -{ -}; - -} // namespace of mcld - -#endif - diff --git a/lib/Target/ARM/ARMGNUInfo.h b/lib/Target/ARM/ARMGNUInfo.h index 9091dce..0162f83 100644 --- a/lib/Target/ARM/ARMGNUInfo.h +++ b/lib/Target/ARM/ARMGNUInfo.h @@ -21,6 +21,11 @@ public: uint32_t machine() const { return llvm::ELF::EM_ARM; } + uint64_t defaultTextSegmentAddr() const { return 0x8000; } + + uint64_t flags() const + { return (llvm::ELF::EF_ARM_EABIMASK & 0x05000000); } + }; } // namespace of mcld diff --git a/lib/Target/ARM/ARMLDBackend.cpp b/lib/Target/ARM/ARMLDBackend.cpp index 844c8ba..8b96670 100644 --- a/lib/Target/ARM/ARMLDBackend.cpp +++ b/lib/Target/ARM/ARMLDBackend.cpp @@ -28,7 +28,6 @@ #include <mcld/Fragment/FillFragment.h> #include <mcld/Fragment/AlignFragment.h> #include <mcld/Fragment/RegionFragment.h> -#include <mcld/Fragment/FragmentLinker.h> #include <mcld/Support/MemoryRegion.h> #include <mcld/Support/MemoryArea.h> #include <mcld/Support/MsgHandling.h> @@ -115,63 +114,80 @@ void ARMGNULDBackend::initTargetSections(Module& pModule, ObjectBuilder& pBuilde } } -void ARMGNULDBackend::initTargetSymbols(FragmentLinker& pLinker) +void ARMGNULDBackend::initTargetSymbols(IRBuilder& pBuilder, Module& pModule) { // Define the symbol _GLOBAL_OFFSET_TABLE_ if there is a symbol with the // same name in input - m_pGOTSymbol = pLinker.defineSymbol<FragmentLinker::AsRefered, FragmentLinker::Resolve>( - "_GLOBAL_OFFSET_TABLE_", - false, - ResolveInfo::Object, - ResolveInfo::Define, - ResolveInfo::Local, - 0x0, // size - 0x0, // value - FragmentRef::Null(), // FragRef - ResolveInfo::Hidden); - - FragmentRef* exidx_start = NULL; - FragmentRef* exidx_end = NULL; - ResolveInfo::Desc desc = ResolveInfo::Undefined; - if (NULL != m_pEXIDX && 0x0 != m_pEXIDX->size()) { - exidx_start = FragmentRef::Create(m_pEXIDX->getSectionData()->front(), 0x0); - exidx_end = FragmentRef::Create(m_pEXIDX->getSectionData()->back(), 0x0); - desc = ResolveInfo::Define; - } - else { - exidx_start = FragmentRef::Null(); - exidx_end = FragmentRef::Null(); - } - m_pEXIDXStart = - pLinker.defineSymbol<FragmentLinker::Force, - FragmentLinker::Resolve>("__exidx_start", - false, - ResolveInfo::NoType, - desc, // ResolveInfo::Desc - ResolveInfo::Global, - 0x0, // size - 0x0, // value - exidx_start, // FragRef - ResolveInfo::Hidden); - - m_pEXIDXEnd = - pLinker.defineSymbol<FragmentLinker::Force, - FragmentLinker::Resolve>("__exidx_end", - false, - ResolveInfo::NoType, - desc, //ResolveInfo::Desc - ResolveInfo::Global, + m_pGOTSymbol = pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>( + "_GLOBAL_OFFSET_TABLE_", + ResolveInfo::Object, + ResolveInfo::Define, + ResolveInfo::Local, 0x0, // size 0x0, // value - exidx_end, // FragRef + FragmentRef::Null(), ResolveInfo::Hidden); + if (NULL != m_pEXIDX && 0x0 != m_pEXIDX->size()) { + FragmentRef* exidx_start = + FragmentRef::Create(m_pEXIDX->getSectionData()->front(), 0x0); + FragmentRef* exidx_end = + FragmentRef::Create(m_pEXIDX->getSectionData()->front(), + m_pEXIDX->size()); + m_pEXIDXStart = + pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>( + "__exidx_start", + ResolveInfo::Object, + ResolveInfo::Define, + ResolveInfo::Local, + 0x0, // size + 0x0, // value + exidx_start, // FragRef + ResolveInfo::Default); + + m_pEXIDXEnd = + pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>( + "__exidx_end", + ResolveInfo::Object, + ResolveInfo::Define, + ResolveInfo::Local, + 0x0, // size + 0x0, // value + exidx_end, // FragRef + ResolveInfo::Default); + // change __exidx_start/_end to local dynamic category + if (NULL != m_pEXIDXStart) + pModule.getSymbolTable().changeLocalToDynamic(*m_pEXIDXStart); + if (NULL != m_pEXIDXEnd) + pModule.getSymbolTable().changeLocalToDynamic(*m_pEXIDXEnd); + } else { + m_pEXIDXStart = + pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>( + "__exidx_start", + ResolveInfo::NoType, + ResolveInfo::Define, + ResolveInfo::Absolute, + 0x0, // size + 0x0, // value + FragmentRef::Null(), + ResolveInfo::Default); + + m_pEXIDXEnd = + pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>( + "__exidx_end", + ResolveInfo::NoType, + ResolveInfo::Define, + ResolveInfo::Absolute, + 0x0, // size + 0x0, // value + FragmentRef::Null(), + ResolveInfo::Default); + } } -bool ARMGNULDBackend::initRelocator(const FragmentLinker& pLinker) +bool ARMGNULDBackend::initRelocator() { if (NULL == m_pRelocator) { m_pRelocator = new ARMRelocator(*this); - m_pRelocator->setFragmentLinker(pLinker); } return true; } @@ -182,8 +198,12 @@ Relocator* ARMGNULDBackend::getRelocator() return m_pRelocator; } -void ARMGNULDBackend::doPreLayout(FragmentLinker& pLinker) +void ARMGNULDBackend::doPreLayout(IRBuilder& pBuilder) { + // initialize .dynamic data + if (!config().isCodeStatic() && NULL == m_pDynamic) + m_pDynamic = new ARMELFDynamic(*this, config()); + // set .got size // when building shared object, the .got section is must if (LinkerConfig::Object != config().codeGenType()) { @@ -191,7 +211,7 @@ void ARMGNULDBackend::doPreLayout(FragmentLinker& pLinker) m_pGOT->hasGOT1() || NULL != m_pGOTSymbol) { m_pGOT->finalizeSectionSize(); - defineGOTSymbol(pLinker); + defineGOTSymbol(pBuilder); } // set .plt size @@ -200,19 +220,24 @@ void ARMGNULDBackend::doPreLayout(FragmentLinker& pLinker) ELFFileFormat* file_format = getOutputFormat(); // set .rel.dyn size - if (!m_pRelDyn->empty()) + if (!m_pRelDyn->empty()) { + assert(!config().isCodeStatic() && + "static linkage should not result in a dynamic relocation section"); file_format->getRelDyn().setSize( m_pRelDyn->numOfRelocs() * getRelEntrySize()); + } // set .rel.plt size - if (!m_pRelPLT->empty()) + if (!m_pRelPLT->empty()) { + assert(!config().isCodeStatic() && + "static linkage should not result in a dynamic relocation section"); file_format->getRelPlt().setSize( m_pRelPLT->numOfRelocs() * getRelEntrySize()); + } } } -void ARMGNULDBackend::doPostLayout(Module& pModule, - FragmentLinker& pLinker) +void ARMGNULDBackend::doPostLayout(Module& pModule, IRBuilder& pBuilder) { const ELFFileFormat *file_format = getOutputFormat(); @@ -242,9 +267,7 @@ void ARMGNULDBackend::doPostLayout(Module& pModule, /// Use co-variant return type to return its own dynamic section. ARMELFDynamic& ARMGNULDBackend::dynamic() { - if (NULL == m_pDynamic) - m_pDynamic = new ARMELFDynamic(*this, config()); - + assert(NULL != m_pDynamic); return *m_pDynamic; } @@ -252,17 +275,16 @@ ARMELFDynamic& ARMGNULDBackend::dynamic() /// Use co-variant return type to return its own dynamic section. const ARMELFDynamic& ARMGNULDBackend::dynamic() const { - assert( NULL != m_pDynamic); + assert(NULL != m_pDynamic); return *m_pDynamic; } -void ARMGNULDBackend::defineGOTSymbol(FragmentLinker& pLinker) +void ARMGNULDBackend::defineGOTSymbol(IRBuilder& pBuilder) { // define symbol _GLOBAL_OFFSET_TABLE_ when .got create if (m_pGOTSymbol != NULL) { - pLinker.defineSymbol<FragmentLinker::Force, FragmentLinker::Unresolve>( + pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Unresolve>( "_GLOBAL_OFFSET_TABLE_", - false, ResolveInfo::Object, ResolveInfo::Define, ResolveInfo::Local, @@ -272,9 +294,8 @@ void ARMGNULDBackend::defineGOTSymbol(FragmentLinker& pLinker) ResolveInfo::Hidden); } else { - m_pGOTSymbol = pLinker.defineSymbol<FragmentLinker::Force, FragmentLinker::Resolve>( + m_pGOTSymbol = pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Resolve>( "_GLOBAL_OFFSET_TABLE_", - false, ResolveInfo::Object, ResolveInfo::Define, ResolveInfo::Local, @@ -301,7 +322,7 @@ void ARMGNULDBackend::addCopyReloc(ResolveInfo& pSym) /// copy. /// This is executed at scan relocation stage. LDSymbol& -ARMGNULDBackend::defineSymbolforCopyReloc(FragmentLinker& pLinker, +ARMGNULDBackend::defineSymbolforCopyReloc(IRBuilder& pBuilder, const ResolveInfo& pSym) { // get or create corresponding BSS LDSection @@ -336,9 +357,8 @@ ARMGNULDBackend::defineSymbolforCopyReloc(FragmentLinker& pLinker, binding = ResolveInfo::Global; // Define the copy symbol in the bss section and resolve it - LDSymbol* cpy_sym = pLinker.defineSymbol<FragmentLinker::Force, FragmentLinker::Resolve>( + LDSymbol* cpy_sym = pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Resolve>( pSym.name(), - false, (ResolveInfo::Type)pSym.type(), ResolveInfo::Define, binding, @@ -352,11 +372,10 @@ ARMGNULDBackend::defineSymbolforCopyReloc(FragmentLinker& pLinker, /// checkValidReloc - When we attempt to generate a dynamic relocation for /// ouput file, check if the relocation is supported by dynamic linker. -void ARMGNULDBackend::checkValidReloc(Relocation& pReloc, - const FragmentLinker& pLinker) const +void ARMGNULDBackend::checkValidReloc(Relocation& pReloc) const { // If not PIC object, no relocation type is invalid - if (!pLinker.isOutputPIC()) + if (!config().isCodeIndep()) return; switch(pReloc.type()) { @@ -379,8 +398,8 @@ void ARMGNULDBackend::checkValidReloc(Relocation& pReloc, } } -void ARMGNULDBackend::scanLocalReloc(Relocation& pReloc, - FragmentLinker& pLinker) +void +ARMGNULDBackend::scanLocalReloc(Relocation& pReloc, const LDSection& pSection) { // rsym - The relocation target symbol ResolveInfo* rsym = pReloc.symInfo(); @@ -398,11 +417,12 @@ void ARMGNULDBackend::scanLocalReloc(Relocation& pReloc, // If buiding PIC object (shared library or PIC executable), // a dynamic relocations with RELATIVE type to this location is needed. // Reserve an entry in .rel.dyn - if (pLinker.isOutputPIC()) { + if (config().isCodeIndep()) { m_pRelDyn->reserveEntry(); // set Rel bit rsym->setReserved(rsym->reserved() | ReserveRel); - } + checkAndSetHasTextRel(*pSection.getLink()); + } return; } @@ -416,7 +436,7 @@ void ARMGNULDBackend::scanLocalReloc(Relocation& pReloc, case llvm::ELF::R_ARM_THM_MOVW_ABS_NC: case llvm::ELF::R_ARM_THM_MOVT_ABS: { // PIC code should not contain these kinds of relocation - if (pLinker.isOutputPIC()) { + if (config().isCodeIndep()) { error(diag::non_pic_relocation) << (int)pReloc.type() << pReloc.symInfo()->name(); } @@ -443,7 +463,7 @@ void ARMGNULDBackend::scanLocalReloc(Relocation& pReloc, // If building PIC object, a dynamic relocation with // type RELATIVE is needed to relocate this GOT entry. // Reserve an entry in .rel.dyn - if (pLinker.isOutputPIC()) { + if (config().isCodeIndep()) { // create .rel.dyn section if not exist m_pRelDyn->reserveEntry(); // set GOTRel bit @@ -479,7 +499,8 @@ void ARMGNULDBackend::scanLocalReloc(Relocation& pReloc, } void ARMGNULDBackend::scanGlobalReloc(Relocation& pReloc, - FragmentLinker& pLinker) + IRBuilder& pBuilder, + const LDSection& pSection) { // rsym - The relocation target symbol ResolveInfo* rsym = pReloc.symInfo(); @@ -505,7 +526,7 @@ void ARMGNULDBackend::scanGlobalReloc(Relocation& pReloc, case llvm::ELF::R_ARM_ABS32_NOI: { // Absolute relocation type, symbol may needs PLT entry or // dynamic relocation entry - if (symbolNeedsPLT(pLinker, *rsym)) { + if (symbolNeedsPLT(*rsym)) { // create plt for this symbol if it does not have one if (!(rsym->reserved() & ReservePLT)){ // Symbol needs PLT entry, we need to reserve a PLT entry @@ -519,18 +540,18 @@ void ARMGNULDBackend::scanGlobalReloc(Relocation& pReloc, } } - if (symbolNeedsDynRel( - pLinker, *rsym, (rsym->reserved() & ReservePLT), true)) { + if (symbolNeedsDynRel(*rsym, (rsym->reserved() & ReservePLT), true)) { // symbol needs dynamic relocation entry, reserve an entry in .rel.dyn m_pRelDyn->reserveEntry(); - if (symbolNeedsCopyReloc(pLinker, pReloc, *rsym)) { - LDSymbol& cpy_sym = defineSymbolforCopyReloc(pLinker, *rsym); + if (symbolNeedsCopyReloc(pReloc, *rsym)) { + LDSymbol& cpy_sym = defineSymbolforCopyReloc(pBuilder, *rsym); addCopyReloc(*cpy_sym.resolveInfo()); } else { - checkValidReloc(pReloc, pLinker); + checkValidReloc(pReloc); // set Rel bit rsym->setReserved(rsym->reserved() | ReserveRel); + checkAndSetHasTextRel(*pSection.getLink()); } } return; @@ -594,18 +615,18 @@ void ARMGNULDBackend::scanGlobalReloc(Relocation& pReloc, case llvm::ELF::R_ARM_MOVT_BREL: case llvm::ELF::R_ARM_MOVW_BREL: { // Relative addressing relocation, may needs dynamic relocation - if (symbolNeedsDynRel( - pLinker, *rsym, (rsym->reserved() & ReservePLT), false)) { + if (symbolNeedsDynRel(*rsym, (rsym->reserved() & ReservePLT), false)) { // symbol needs dynamic relocation entry, reserve an entry in .rel.dyn m_pRelDyn->reserveEntry(); - if (symbolNeedsCopyReloc(pLinker, pReloc, *rsym)) { - LDSymbol& cpy_sym = defineSymbolforCopyReloc(pLinker, *rsym); + if (symbolNeedsCopyReloc(pReloc, *rsym)) { + LDSymbol& cpy_sym = defineSymbolforCopyReloc(pBuilder, *rsym); addCopyReloc(*cpy_sym.resolveInfo()); } else { - checkValidReloc(pReloc, pLinker); + checkValidReloc(pReloc); // set Rel bit rsym->setReserved(rsym->reserved() | ReserveRel); + checkAndSetHasTextRel(*pSection.getLink()); } } return; @@ -630,7 +651,7 @@ void ARMGNULDBackend::scanGlobalReloc(Relocation& pReloc, return; // if the symbol's value can be decided at link time, then no need plt - if (symbolFinalValueIsKnown(pLinker, *rsym)) + if (symbolFinalValueIsKnown(*rsym)) return; // if symbol is defined in the ouput file and it's not @@ -666,7 +687,7 @@ void ARMGNULDBackend::scanGlobalReloc(Relocation& pReloc, m_pGOT->reserveGOT(); // if the symbol cannot be fully resolved at link time, then we need a // dynamic relocation - if (!symbolFinalValueIsKnown(pLinker, *rsym)) { + if (!symbolFinalValueIsKnown(*rsym)) { m_pRelDyn->reserveEntry(); // set GOTRel bit rsym->setReserved(rsym->reserved() | GOTRel); @@ -693,16 +714,17 @@ void ARMGNULDBackend::scanGlobalReloc(Relocation& pReloc, } void ARMGNULDBackend::scanRelocation(Relocation& pReloc, - FragmentLinker& pLinker, + IRBuilder& pBuilder, Module& pModule, - const LDSection& pSection) + LDSection& pSection) { // rsym - The relocation target symbol ResolveInfo* rsym = pReloc.symInfo(); assert(NULL != rsym && "ResolveInfo of relocation not set while scanRelocation"); pReloc.updateAddend(); - if (0 == (pSection.flag() & llvm::ELF::SHF_ALLOC)) + assert(NULL != pSection.getLink()); + if (0 == (pSection.getLink()->flag() & llvm::ELF::SHF_ALLOC)) return; // Scan relocation type to determine if an GOT/PLT/Dynamic Relocation @@ -711,21 +733,16 @@ void ARMGNULDBackend::scanRelocation(Relocation& pReloc, // rsym is local if (rsym->isLocal()) - scanLocalReloc(pReloc, pLinker); + scanLocalReloc(pReloc, pSection); // rsym is external else - scanGlobalReloc(pReloc, pLinker); + scanGlobalReloc(pReloc, pBuilder, pSection); // check if we shoule issue undefined reference for the relocation target // symbol if (rsym->isUndef() && !rsym->isDyn() && !rsym->isWeak() && !rsym->isNull()) fatal(diag::undefined_reference) << rsym->name(); - - if ((rsym->reserved() & ReserveRel) != 0x0) { - // set hasTextRelSection if needed - checkAndSetHasTextRel(pSection); - } } uint64_t ARMGNULDBackend::emitSectionData(const LDSection& pSection, @@ -765,7 +782,7 @@ uint64_t ARMGNULDBackend::emitSectionData(const LDSection& pSection, break; } case Fragment::Alignment: { - AlignFragment& align_frag = llvm::cast<AlignFragment>(*frag_iter); + const AlignFragment& align_frag = llvm::cast<AlignFragment>(*frag_iter); uint64_t count = size / align_frag.getValueSize(); switch (align_frag.getValueSize()) { case 1u: @@ -809,17 +826,8 @@ uint64_t ARMGNULDBackend::emitSectionData(const LDSection& pSection, } /// finalizeSymbol - finalize the symbol value -bool ARMGNULDBackend::finalizeTargetSymbols(FragmentLinker& pLinker) +bool ARMGNULDBackend::finalizeTargetSymbols() { - if (NULL != m_pEXIDXStart) { - if (NULL != m_pEXIDX && 0x0 != m_pEXIDX->size()) - m_pEXIDXStart->setValue(m_pEXIDX->addr()); - } - - if (NULL != m_pEXIDXEnd) { - if (NULL != m_pEXIDX && 0x0 != m_pEXIDX->size()) - m_pEXIDXEnd->setValue(m_pEXIDX->addr() + m_pEXIDX->size()); - } return true; } @@ -829,7 +837,7 @@ bool ARMGNULDBackend::mergeSection(Module& pModule, LDSection& pSection) case llvm::ELF::SHT_ARM_ATTRIBUTES: { // FIXME: (Luba) // Handle ARM attributes in the right way. - // In current milestone, FragmentLinker goes through the shortcut. + // In current milestone, we goes through the shortcut. // It reads input's ARM attributes and copies the first ARM attributes // into the output file. The correct way is merge these sections, not // just copy. @@ -940,7 +948,8 @@ ARMGNULDBackend::getTargetSectionOrder(const LDSection& pSectHdr) const } /// doRelax -bool ARMGNULDBackend::doRelax(Module& pModule, FragmentLinker& pLinker, bool& pFinished) +bool +ARMGNULDBackend::doRelax(Module& pModule, IRBuilder& pBuilder, bool& pFinished) { assert(NULL != getStubFactory() && NULL != getBRIslandFactory()); @@ -984,17 +993,20 @@ bool ARMGNULDBackend::doRelax(Module& pModule, FragmentLinker& pLinker, bool& pF Stub* stub = getStubFactory()->create(*relocation, // relocation sym_value, // symbol value - pLinker, + pBuilder, *getBRIslandFactory()); if (NULL != stub) { - assert(NULL != stub->symInfo()); - // increase the size of .symtab and .strtab + // a stub symbol should be local + assert(NULL != stub->symInfo() && stub->symInfo()->isLocal()); LDSection& symtab = file_format->getSymTab(); LDSection& strtab = file_format->getStrTab(); + + // increase the size of .symtab and .strtab if needed if (config().targets().is32Bits()) symtab.setSize(symtab.size() + sizeof(llvm::ELF::Elf32_Sym)); else symtab.setSize(symtab.size() + sizeof(llvm::ELF::Elf64_Sym)); + symtab.setInfo(symtab.getInfo() + 1); strtab.setSize(strtab.size() + stub->symInfo()->nameSize() + 1); isRelaxed = true; @@ -1042,13 +1054,13 @@ bool ARMGNULDBackend::doRelax(Module& pModule, FragmentLinker& pLinker, bool& pF } /// initTargetStubs -bool ARMGNULDBackend::initTargetStubs(FragmentLinker& pLinker) +bool ARMGNULDBackend::initTargetStubs() { if (NULL != getStubFactory()) { - getStubFactory()->addPrototype(new ARMToARMStub(pLinker.isOutputPIC())); - getStubFactory()->addPrototype(new ARMToTHMStub(pLinker.isOutputPIC())); - getStubFactory()->addPrototype(new THMToTHMStub(pLinker.isOutputPIC())); - getStubFactory()->addPrototype(new THMToARMStub(pLinker.isOutputPIC())); + getStubFactory()->addPrototype(new ARMToARMStub(config().isCodeIndep())); + getStubFactory()->addPrototype(new ARMToTHMStub(config().isCodeIndep())); + getStubFactory()->addPrototype(new THMToTHMStub(config().isCodeIndep())); + getStubFactory()->addPrototype(new THMToARMStub(config().isCodeIndep())); return true; } return false; @@ -1056,8 +1068,7 @@ bool ARMGNULDBackend::initTargetStubs(FragmentLinker& pLinker) /// doCreateProgramHdrs - backend can implement this function to create the /// target-dependent segments -void ARMGNULDBackend::doCreateProgramHdrs(Module& pModule, - const FragmentLinker& pLinker) +void ARMGNULDBackend::doCreateProgramHdrs(Module& pModule) { if (NULL != m_pEXIDX && 0x0 != m_pEXIDX->size()) { // make PT_ARM_EXIDX diff --git a/lib/Target/ARM/ARMLDBackend.h b/lib/Target/ARM/ARMLDBackend.h index 6110b1c..170a7bf 100644 --- a/lib/Target/ARM/ARMLDBackend.h +++ b/lib/Target/ARM/ARMLDBackend.h @@ -20,7 +20,6 @@ namespace mcld { class LinkerConfig; class GNUInfo; -class FragmentLinker; class SectionMap; //===----------------------------------------------------------------------===// @@ -93,10 +92,10 @@ public: void initTargetSections(Module& pModule, ObjectBuilder& pBuilder); /// initTargetSymbols - initialize target dependent symbols in output. - void initTargetSymbols(FragmentLinker& pLinker); + void initTargetSymbols(IRBuilder& pBuilder, Module& pModule); /// initRelocator - create and initialize Relocator. - bool initRelocator(const FragmentLinker& pLinker); + bool initRelocator(); /// getRelocator - return relocator. Relocator* getRelocator(); @@ -108,22 +107,15 @@ public: /// - PLT entry (for .plt section) /// - dynamin relocation entries (for .rel.plt and .rel.dyn sections) void scanRelocation(Relocation& pReloc, - FragmentLinker& pLinker, + IRBuilder& pBuilder, Module& pModule, - const LDSection& pSection); - - /// flags - the value of ElfXX_Ehdr::e_flags - virtual uint64_t flags() const - { return (llvm::ELF::EF_ARM_EABIMASK & 0x05000000); } - - uint64_t defaultTextSegmentAddr() const - { return 0x8000; } + LDSection& pSection); /// doPreLayout - Backend can do any needed modification before layout - void doPreLayout(FragmentLinker& pLinker); + void doPreLayout(IRBuilder& pBuilder); /// doPostLayout -Backend can do any needed modification after layout - void doPostLayout(Module& pModule, FragmentLinker& pLinker); + void doPostLayout(Module& pModule, IRBuilder& pBuilder); /// dynamic - the dynamic section of the target machine. /// Use co-variant return type to return its own dynamic section. @@ -172,7 +164,7 @@ public: unsigned int getTargetSectionOrder(const LDSection& pSectHdr) const; /// finalizeTargetSymbols - finalize the symbol value - bool finalizeTargetSymbols(FragmentLinker& pLinker); + bool finalizeTargetSymbols(); /// mergeSection - merge target dependent sections bool mergeSection(Module& pModule, LDSection& pSection); @@ -181,12 +173,13 @@ public: bool readSection(Input& pInput, SectionData& pSD); private: - void scanLocalReloc(Relocation& pReloc, FragmentLinker& pLinker); + void scanLocalReloc(Relocation& pReloc, const LDSection& pSection); - void scanGlobalReloc(Relocation& pReloc, FragmentLinker& pLinker); + void scanGlobalReloc(Relocation& pReloc, + IRBuilder& pBuilder, + const LDSection& pSection); - void checkValidReloc(Relocation& pReloc, - const FragmentLinker& pLinker) const; + void checkValidReloc(Relocation& pReloc) const; /// addCopyReloc - add a copy relocation into .rel.dyn for pSym /// @param pSym - A resolved copy symbol that defined in BSS section @@ -195,10 +188,10 @@ private: /// defineSymbolforCopyReloc - allocate a space in BSS section and /// and force define the copy of pSym to BSS section /// @return the output LDSymbol of the copy symbol - LDSymbol& defineSymbolforCopyReloc(FragmentLinker& pLinker, + LDSymbol& defineSymbolforCopyReloc(IRBuilder& pLinker, const ResolveInfo& pSym); - void defineGOTSymbol(FragmentLinker& pLinker); + void defineGOTSymbol(IRBuilder& pBuilder); /// maxBranchOffset /// FIXME: if we can handle arm attributes, we may refine this! @@ -211,10 +204,10 @@ private: /// implementation. Return true if the output (e.g., .text) is "relaxed" /// (i.e. layout is changed), and set pFinished to true if everything is fit, /// otherwise set it to false. - bool doRelax(Module& pModule, FragmentLinker& pLinker, bool& pFinished); + bool doRelax(Module& pModule, IRBuilder& pBuilder, bool& pFinished); /// initTargetStubs - bool initTargetStubs(FragmentLinker& pLinker); + bool initTargetStubs(); /// getRelEntrySize - the size in BYTE of rel type relocation size_t getRelEntrySize() @@ -226,8 +219,7 @@ private: /// doCreateProgramHdrs - backend can implement this function to create the /// target-dependent segments - virtual void doCreateProgramHdrs(Module& pModule, - const FragmentLinker& pLinker); + virtual void doCreateProgramHdrs(Module& pModule); private: Relocator* m_pRelocator; @@ -252,24 +244,6 @@ private: // LDSection* m_pDebugOverlay; // .ARM.debug_overlay // LDSection* m_pOverlayTable; // .ARM.overlay_table }; - -//===----------------------------------------------------------------------===// -/// ARMMachOLDBackend - linker backend of ARM target of MachO format -/// -/** -class ARMMachOLDBackend : public DarwinARMLDBackend -{ -public: - ARMMachOLDBackend(); - ~ARMMachOLDBackend(); - -private: - MCMachOTargetArchiveReader *createTargetArchiveReader() const; - MCMachOTargetObjectReader *createTargetObjectReader() const; - MCMachOTargetObjectWriter *createTargetObjectWriter() const; - -}; -**/ } // namespace of mcld #endif diff --git a/lib/Target/ARM/ARMRelocator.cpp b/lib/Target/ARM/ARMRelocator.cpp index d613d66..d400818 100644 --- a/lib/Target/ARM/ARMRelocator.cpp +++ b/lib/Target/ARM/ARMRelocator.cpp @@ -11,7 +11,6 @@ #include <llvm/Support/DataTypes.h> #include <llvm/Support/ELF.h> #include <llvm/Support/Host.h> -#include <mcld/Fragment/FragmentLinker.h> #include <mcld/Support/MsgHandling.h> #include "ARMRelocator.h" #include "ARMRelocationFunctions.h" @@ -68,8 +67,14 @@ const char* ARMRelocator::getName(Relocator::Type pType) const return ApplyFunctions[pType].name; } +Relocator::Size ARMRelocator::getSize(Relocation::Type pType) const +{ + return 32; +} + //===--------------------------------------------------------------------===// // non-member functions +//===--------------------------------------------------------------------===// static Relocator::DWord getThumbBit(const Relocation& pReloc) { // Set thumb bit if diff --git a/lib/Target/ARM/ARMRelocator.h b/lib/Target/ARM/ARMRelocator.h index 0bf3653..4af48f9 100644 --- a/lib/Target/ARM/ARMRelocator.h +++ b/lib/Target/ARM/ARMRelocator.h @@ -43,6 +43,8 @@ public: const char* getName(Relocation::Type pType) const; + Size getSize(Relocation::Type pType) const; + const SymGOTMap& getSymGOTMap() const { return m_SymGOTMap; } SymGOTMap& getSymGOTMap() { return m_SymGOTMap; } diff --git a/lib/Target/DarwinLDBackend.cpp b/lib/Target/DarwinLDBackend.cpp deleted file mode 100644 index 5bd55c3..0000000 --- a/lib/Target/DarwinLDBackend.cpp +++ /dev/null @@ -1,15 +0,0 @@ -//===- DarwinLDBackend.cpp ------------------------------------------------===// -// -// The MCLinker Project -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -#include <DarwinLDBackend.h> - -using namespace mcld; - -//========================== -// DarwinLDBackend - diff --git a/lib/Target/ELFDynamic.cpp b/lib/Target/ELFDynamic.cpp index 89917cc..aeccd92 100644 --- a/lib/Target/ELFDynamic.cpp +++ b/lib/Target/ELFDynamic.cpp @@ -35,10 +35,17 @@ EntryIF::~EntryIF() ELFDynamic::ELFDynamic(const GNULDBackend& pParent, const LinkerConfig& pConfig) : m_pEntryFactory(NULL), m_Backend(pParent), m_Config(pConfig), m_Idx(0) { - if (m_Config.targets().is32Bits() && m_Config.targets().isLittleEndian()) { - m_pEntryFactory = new Entry<32, true>(); + // FIXME: support big-endian machine. + if (m_Config.targets().is32Bits()) { + if (m_Config.targets().isLittleEndian()) + m_pEntryFactory = new Entry<32, true>(); + } else if (m_Config.targets().is64Bits()) { + if (m_Config.targets().isLittleEndian()) + m_pEntryFactory = new Entry<64, true>(); + } else { + fatal(diag::unsupported_bitclass) << m_Config.targets().triple().str() + << m_Config.targets().bitclass(); } - // FIXME: support big-endian and 64-bit machine. } @@ -78,7 +85,7 @@ size_t ELFDynamic::entrySize() const void ELFDynamic::reserveOne(uint64_t pTag) { assert(NULL != m_pEntryFactory); - m_EntryList.push_back(new elf_dynamic::Entry<32, true>()); + m_EntryList.push_back(m_pEntryFactory->clone()); } void ELFDynamic::applyOne(uint64_t pTag, uint64_t pValue) @@ -117,6 +124,10 @@ void ELFDynamic::reserveEntries(const ELFFileFormat& pFormat) if (pFormat.hasHashTab()) reserveOne(llvm::ELF::DT_HASH); // DT_HASH + // FIXME: use llvm enum constant + if (pFormat.hasGNUHashTab()) + reserveOne(0x6ffffef5); // DT_GNU_HASH + if (pFormat.hasDynSymTab()) { reserveOne(llvm::ELF::DT_SYMTAB); // DT_SYMTAB reserveOne(llvm::ELF::DT_SYMENT); // DT_SYMENT @@ -149,14 +160,22 @@ void ELFDynamic::reserveEntries(const ELFFileFormat& pFormat) reserveOne(llvm::ELF::DT_RELAENT); // DT_RELAENT } - if (m_Config.options().hasOrigin() || - m_Config.options().Bsymbolic() || - m_Config.options().hasNow() || - m_Backend.hasTextRel() || - (m_Backend.hasStaticTLS() && - (LinkerConfig::DynObj == m_Config.codeGenType()))) { + uint64_t dt_flags = 0x0; + if (m_Config.options().hasOrigin()) + dt_flags |= llvm::ELF::DF_ORIGIN; + if (m_Config.options().Bsymbolic()) + dt_flags |= llvm::ELF::DF_SYMBOLIC; + if (m_Config.options().hasNow()) + dt_flags |= llvm::ELF::DF_BIND_NOW; + if (m_Backend.hasTextRel()) + dt_flags |= llvm::ELF::DF_TEXTREL; + if (m_Backend.hasStaticTLS() && + (LinkerConfig::DynObj == m_Config.codeGenType())) + dt_flags |= llvm::ELF::DF_STATIC_TLS; + + if ((m_Config.options().hasNewDTags() && 0x0 != dt_flags) || + 0 != (dt_flags & llvm::ELF::DF_STATIC_TLS)) reserveOne(llvm::ELF::DT_FLAGS); // DT_FLAGS - } if (m_Backend.hasTextRel()) reserveOne(llvm::ELF::DT_TEXTREL); // DT_TEXTREL @@ -211,6 +230,10 @@ void ELFDynamic::applyEntries(const ELFFileFormat& pFormat) if (pFormat.hasHashTab()) applyOne(llvm::ELF::DT_HASH, pFormat.getHashTab().addr()); // DT_HASH + // FIXME: use llvm enum constant + if (pFormat.hasGNUHashTab()) + applyOne(0x6ffffef5, pFormat.getGNUHashTab().addr()); // DT_GNU_HASH + if (pFormat.hasDynSymTab()) { applyOne(llvm::ELF::DT_SYMTAB, pFormat.getDynSymTab().addr()); // DT_SYMTAB applyOne(llvm::ELF::DT_SYMENT, symbolSize()); // DT_SYMENT @@ -223,15 +246,16 @@ void ELFDynamic::applyEntries(const ELFFileFormat& pFormat) applyTargetEntries(pFormat); // DT_PLTGOT - if (pFormat.hasRelPlt()) - applyOne(llvm::ELF::DT_PLTREL, llvm::ELF::DT_REL); // DT_PLTREL - else if (pFormat.hasRelaPlt()) - applyOne(llvm::ELF::DT_PLTREL, llvm::ELF::DT_RELA); // DT_PLTREL - if (pFormat.hasRelPlt()) { + applyOne(llvm::ELF::DT_PLTREL, llvm::ELF::DT_REL); // DT_PLTREL applyOne(llvm::ELF::DT_JMPREL, pFormat.getRelPlt().addr()); // DT_JMPREL applyOne(llvm::ELF::DT_PLTRELSZ, pFormat.getRelPlt().size()); // DT_PLTRELSZ } + else if (pFormat.hasRelaPlt()) { + applyOne(llvm::ELF::DT_PLTREL, llvm::ELF::DT_RELA); // DT_PLTREL + applyOne(llvm::ELF::DT_JMPREL, pFormat.getRelaPlt().addr()); // DT_JMPREL + applyOne(llvm::ELF::DT_PLTRELSZ, pFormat.getRelaPlt().size()); // DT_PLTRELSZ + } if (pFormat.hasRelDyn()) { applyOne(llvm::ELF::DT_REL, pFormat.getRelDyn().addr()); // DT_REL @@ -265,9 +289,10 @@ void ELFDynamic::applyEntries(const ELFFileFormat& pFormat) if (m_Backend.hasStaticTLS() && (LinkerConfig::DynObj == m_Config.codeGenType())) dt_flags |= llvm::ELF::DF_STATIC_TLS; - if (0x0 != dt_flags) { + + if ((m_Config.options().hasNewDTags() && 0x0 != dt_flags) || + 0 != (dt_flags & llvm::ELF::DF_STATIC_TLS)) applyOne(llvm::ELF::DT_FLAGS, dt_flags); // DT_FLAGS - } uint64_t dt_flags_1 = 0x0; if (m_Config.options().hasNow()) diff --git a/lib/Target/ELFEmulation.cpp b/lib/Target/ELFEmulation.cpp index 3bd2094..bdd76aa 100644 --- a/lib/Target/ELFEmulation.cpp +++ b/lib/Target/ELFEmulation.cpp @@ -9,6 +9,8 @@ #include <mcld/Target/ELFEmulation.h> #include <mcld/LinkerConfig.h> +#include <llvm/Support/Host.h> + using namespace mcld; struct NameMap { @@ -61,6 +63,7 @@ static const NameMap map[] = bool mcld::MCLDEmulateELF(LinkerConfig& pConfig) { + // set up section map if (pConfig.codeGenType() != LinkerConfig::Object) { const unsigned int map_size = (sizeof(map) / sizeof(map[0]) ); for (unsigned int i = 0; i < map_size; ++i) { @@ -70,6 +73,18 @@ bool mcld::MCLDEmulateELF(LinkerConfig& pConfig) return false; } } + + if (!pConfig.options().nostdlib()) { + // TODO: check if user sets the default search path instead via -Y option + // set up default search path + if (llvm::Triple::NetBSD == pConfig.targets().triple().getOS()) { + pConfig.options().directories().insert("=/usr/lib"); + } + else { + pConfig.options().directories().insert("=/lib"); + pConfig.options().directories().insert("=/usr/lib"); + } + } return true; } diff --git a/lib/Target/GNULDBackend.cpp b/lib/Target/GNULDBackend.cpp index 590c14f..ef4f1fb 100644 --- a/lib/Target/GNULDBackend.cpp +++ b/lib/Target/GNULDBackend.cpp @@ -13,6 +13,7 @@ #include <cassert> #include <vector> #include <algorithm> +#include <map> #include <mcld/Module.h> #include <mcld/LinkerConfig.h> @@ -28,7 +29,6 @@ #include <mcld/LD/RelocData.h> #include <mcld/LD/RelocationFactory.h> #include <mcld/MC/Attribute.h> -#include <mcld/Fragment/FragmentLinker.h> #include <mcld/Support/MemoryArea.h> #include <mcld/Support/MemoryRegion.h> #include <mcld/Support/MsgHandling.h> @@ -66,7 +66,6 @@ GNULDBackend::GNULDBackend(const LinkerConfig& pConfig, GNUInfo* pInfo) m_ELFSegmentTable(9), // magic number m_pBRIslandFactory(NULL), m_pStubFactory(NULL), - m_pEhFrame(NULL), m_pEhFrameHdr(NULL), m_bHasTextRel(false), m_bHasStaticTLS(false), @@ -97,14 +96,11 @@ GNULDBackend::~GNULDBackend() delete m_pInfo; delete m_pDynObjFileFormat; delete m_pExecFileFormat; + delete m_pObjectFileFormat; delete m_pSymIndexMap; - delete m_pEhFrame; delete m_pEhFrameHdr; - - if (NULL != m_pBRIslandFactory) - delete m_pBRIslandFactory; - if (NULL != m_pStubFactory) - delete m_pStubFactory; + delete m_pBRIslandFactory; + delete m_pStubFactory; } size_t GNULDBackend::sectionStartOffset() const @@ -126,16 +122,16 @@ size_t GNULDBackend::sectionStartOffset() const } } -uint64_t GNULDBackend::segmentStartAddr(const FragmentLinker& pLinker) const +uint64_t GNULDBackend::segmentStartAddr() const { ScriptOptions::AddressMap::const_iterator mapping = config().scripts().addressMap().find(".text"); if (mapping != config().scripts().addressMap().end()) return mapping.getEntry()->value(); - else if (pLinker.isOutputPIC()) + else if (config().isCodeIndep()) return 0x0; else - return defaultTextSegmentAddr(); + return m_pInfo->defaultTextSegmentAddr(); } GNUArchiveReader* @@ -161,26 +157,11 @@ ELFBinaryReader* GNULDBackend::createBinaryReader(IRBuilder& pBuilder) return new ELFBinaryReader(*this, pBuilder, config()); } -ELFObjectWriter* GNULDBackend::createObjectWriter() +ELFObjectWriter* GNULDBackend::createWriter() { return new ELFObjectWriter(*this, config()); } -ELFDynObjWriter* GNULDBackend::createDynObjWriter() -{ - return new ELFDynObjWriter(*this, config()); -} - -ELFExecWriter* GNULDBackend::createExecWriter() -{ - return new ELFExecWriter(*this, config()); -} - -ELFBinaryWriter* GNULDBackend::createBinaryWriter() -{ - return new ELFBinaryWriter(*this, config()); -} - bool GNULDBackend::initStdSections(ObjectBuilder& pBuilder) { switch (config().codeGenType()) { @@ -214,7 +195,7 @@ bool GNULDBackend::initStdSections(ObjectBuilder& pBuilder) /// initStandardSymbols - define and initialize standard symbols. /// This function is called after section merging but before read relocations. -bool GNULDBackend::initStandardSymbols(FragmentLinker& pLinker, +bool GNULDBackend::initStandardSymbols(IRBuilder& pBuilder, Module& pModule) { if (LinkerConfig::Object == config().codeGenType()) @@ -244,9 +225,8 @@ bool GNULDBackend::initStandardSymbols(FragmentLinker& pLinker, llvm::StringRef start_name = llvm::StringRef("__start_" + section->name()); FragmentRef* start_fragref = FragmentRef::Create( section->getSectionData()->front(), 0x0); - pLinker.defineSymbol<FragmentLinker::AsRefered, - FragmentLinker::Resolve>(start_name, - false, // isDyn + pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>( + start_name, ResolveInfo::NoType, ResolveInfo::Define, ResolveInfo::Global, @@ -258,9 +238,8 @@ bool GNULDBackend::initStandardSymbols(FragmentLinker& pLinker, llvm::StringRef stop_name = llvm::StringRef("__stop_" + section->name()); FragmentRef* stop_fragref = FragmentRef::Create( section->getSectionData()->front(), section->size()); - pLinker.defineSymbol<FragmentLinker::AsRefered, - FragmentLinker::Resolve>(stop_name, - false, // isDyn + pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>( + stop_name, ResolveInfo::NoType, ResolveInfo::Define, ResolveInfo::Global, @@ -285,9 +264,8 @@ bool GNULDBackend::initStandardSymbols(FragmentLinker& pLinker, preinit_array = FragmentRef::Null(); } f_pPreInitArrayStart = - pLinker.defineSymbol<FragmentLinker::AsRefered, - FragmentLinker::Resolve>("__preinit_array_start", - false, // isDyn + pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>( + "__preinit_array_start", ResolveInfo::NoType, ResolveInfo::Define, ResolveInfo::Global, @@ -296,9 +274,8 @@ bool GNULDBackend::initStandardSymbols(FragmentLinker& pLinker, preinit_array, // FragRef ResolveInfo::Hidden); f_pPreInitArrayEnd = - pLinker.defineSymbol<FragmentLinker::AsRefered, - FragmentLinker::Resolve>("__preinit_array_end", - false, // isDyn + pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>( + "__preinit_array_end", ResolveInfo::NoType, ResolveInfo::Define, ResolveInfo::Global, @@ -319,9 +296,8 @@ bool GNULDBackend::initStandardSymbols(FragmentLinker& pLinker, } f_pInitArrayStart = - pLinker.defineSymbol<FragmentLinker::AsRefered, - FragmentLinker::Resolve>("__init_array_start", - false, // isDyn + pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>( + "__init_array_start", ResolveInfo::NoType, ResolveInfo::Define, ResolveInfo::Global, @@ -330,9 +306,8 @@ bool GNULDBackend::initStandardSymbols(FragmentLinker& pLinker, init_array, // FragRef ResolveInfo::Hidden); f_pInitArrayEnd = - pLinker.defineSymbol<FragmentLinker::AsRefered, - FragmentLinker::Resolve>("__init_array_end", - false, // isDyn + pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>( + "__init_array_end", ResolveInfo::NoType, ResolveInfo::Define, ResolveInfo::Global, @@ -353,9 +328,8 @@ bool GNULDBackend::initStandardSymbols(FragmentLinker& pLinker, } f_pFiniArrayStart = - pLinker.defineSymbol<FragmentLinker::AsRefered, - FragmentLinker::Resolve>("__fini_array_start", - false, // isDyn + pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>( + "__fini_array_start", ResolveInfo::NoType, ResolveInfo::Define, ResolveInfo::Global, @@ -364,9 +338,8 @@ bool GNULDBackend::initStandardSymbols(FragmentLinker& pLinker, fini_array, // FragRef ResolveInfo::Hidden); f_pFiniArrayEnd = - pLinker.defineSymbol<FragmentLinker::AsRefered, - FragmentLinker::Resolve>("__fini_array_end", - false, // isDyn + pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>( + "__fini_array_end", ResolveInfo::NoType, ResolveInfo::Define, ResolveInfo::Global, @@ -387,9 +360,8 @@ bool GNULDBackend::initStandardSymbols(FragmentLinker& pLinker, } f_pStack = - pLinker.defineSymbol<FragmentLinker::AsRefered, - FragmentLinker::Resolve>("__stack", - false, // isDyn + pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>( + "__stack", ResolveInfo::NoType, ResolveInfo::Define, ResolveInfo::Global, @@ -402,9 +374,8 @@ bool GNULDBackend::initStandardSymbols(FragmentLinker& pLinker, // TODO: add SectionData for .dynamic section, and then we can get the correct // symbol section index for _DYNAMIC. Now it will be ABS. f_pDynamic = - pLinker.defineSymbol<FragmentLinker::AsRefered, - FragmentLinker::Resolve>("_DYNAMIC", - false, // isDyn + pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>( + "_DYNAMIC", ResolveInfo::Object, ResolveInfo::Define, ResolveInfo::Local, @@ -415,9 +386,8 @@ bool GNULDBackend::initStandardSymbols(FragmentLinker& pLinker, // ----- segment symbols ----- // f_pExecutableStart = - pLinker.defineSymbol<FragmentLinker::AsRefered, - FragmentLinker::Resolve>("__executable_start", - false, // isDyn + pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>( + "__executable_start", ResolveInfo::NoType, ResolveInfo::Define, ResolveInfo::Absolute, @@ -426,9 +396,8 @@ bool GNULDBackend::initStandardSymbols(FragmentLinker& pLinker, FragmentRef::Null(), // FragRef ResolveInfo::Default); f_pEText = - pLinker.defineSymbol<FragmentLinker::AsRefered, - FragmentLinker::Resolve>("etext", - false, // isDyn + pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>( + "etext", ResolveInfo::NoType, ResolveInfo::Define, ResolveInfo::Absolute, @@ -437,9 +406,8 @@ bool GNULDBackend::initStandardSymbols(FragmentLinker& pLinker, FragmentRef::Null(), // FragRef ResolveInfo::Default); f_p_EText = - pLinker.defineSymbol<FragmentLinker::AsRefered, - FragmentLinker::Resolve>("_etext", - false, // isDyn + pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>( + "_etext", ResolveInfo::NoType, ResolveInfo::Define, ResolveInfo::Absolute, @@ -448,9 +416,8 @@ bool GNULDBackend::initStandardSymbols(FragmentLinker& pLinker, FragmentRef::Null(), // FragRef ResolveInfo::Default); f_p__EText = - pLinker.defineSymbol<FragmentLinker::AsRefered, - FragmentLinker::Resolve>("__etext", - false, // isDyn + pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>( + "__etext", ResolveInfo::NoType, ResolveInfo::Define, ResolveInfo::Absolute, @@ -459,9 +426,8 @@ bool GNULDBackend::initStandardSymbols(FragmentLinker& pLinker, FragmentRef::Null(), // FragRef ResolveInfo::Default); f_pEData = - pLinker.defineSymbol<FragmentLinker::AsRefered, - FragmentLinker::Resolve>("edata", - false, // isDyn + pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>( + "edata", ResolveInfo::NoType, ResolveInfo::Define, ResolveInfo::Absolute, @@ -471,9 +437,8 @@ bool GNULDBackend::initStandardSymbols(FragmentLinker& pLinker, ResolveInfo::Default); f_pEnd = - pLinker.defineSymbol<FragmentLinker::AsRefered, - FragmentLinker::Resolve>("end", - false, // isDyn + pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>( + "end", ResolveInfo::NoType, ResolveInfo::Define, ResolveInfo::Absolute, @@ -485,9 +450,8 @@ bool GNULDBackend::initStandardSymbols(FragmentLinker& pLinker, // _edata is defined forcefully. // @ref Google gold linker: defstd.cc: 186 f_p_EData = - pLinker.defineSymbol<FragmentLinker::Force, - FragmentLinker::Resolve>("_edata", - false, // isDyn + pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Resolve>( + "_edata", ResolveInfo::NoType, ResolveInfo::Define, ResolveInfo::Absolute, @@ -499,9 +463,8 @@ bool GNULDBackend::initStandardSymbols(FragmentLinker& pLinker, // __bss_start is defined forcefully. // @ref Google gold linker: defstd.cc: 214 f_pBSSStart = - pLinker.defineSymbol<FragmentLinker::Force, - FragmentLinker::Resolve>("__bss_start", - false, // isDyn + pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Resolve>( + "__bss_start", ResolveInfo::NoType, ResolveInfo::Define, ResolveInfo::Absolute, @@ -513,9 +476,8 @@ bool GNULDBackend::initStandardSymbols(FragmentLinker& pLinker, // _end is defined forcefully. // @ref Google gold linker: defstd.cc: 228 f_p_End = - pLinker.defineSymbol<FragmentLinker::Force, - FragmentLinker::Resolve>("_end", - false, // isDyn + pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Resolve>( + "_end", ResolveInfo::NoType, ResolveInfo::Define, ResolveInfo::Absolute, @@ -527,8 +489,7 @@ bool GNULDBackend::initStandardSymbols(FragmentLinker& pLinker, return true; } -bool -GNULDBackend::finalizeStandardSymbols(FragmentLinker& pLinker) +bool GNULDBackend::finalizeStandardSymbols() { if (LinkerConfig::Object == config().codeGenType()) return true; @@ -752,7 +713,6 @@ const ELFFileFormat* GNULDBackend::getOutputFormat() const } void GNULDBackend::partialScanRelocation(Relocation& pReloc, - FragmentLinker& pLinker, Module& pModule, const LDSection& pSection) { @@ -778,8 +738,7 @@ void GNULDBackend::partialScanRelocation(Relocation& pReloc, /// sizeNamePools - compute the size of regular name pools /// In ELF executable files, regular name pools are .symtab, .strtab, /// .dynsym, .dynstr, .hash and .shstrtab. -void -GNULDBackend::sizeNamePools(const Module& pModule, bool pIsStaticLink) +void GNULDBackend::sizeNamePools(Module& pModule, bool pIsStaticLink) { // number of entries in symbol tables starts from 1 to hold the special entry // at index 0 (STN_UNDEF). See ELF Spec Book I, p1-21. @@ -788,112 +747,118 @@ GNULDBackend::sizeNamePools(const Module& pModule, bool pIsStaticLink) // size of string tables starts from 1 to hold the null character in their // first byte - size_t strtab = 1; - size_t dynstr = pIsStaticLink ? 0 : 1; + size_t strtab = 1; + size_t dynstr = pIsStaticLink ? 0 : 1; size_t shstrtab = 1; - size_t hash = 0; + size_t hash = 0; + size_t gnuhash = 0; - // number of local symbol in the .dynsym + // number of local symbol in the .symtab and .dynsym + size_t symtab_local_cnt = 0; size_t dynsym_local_cnt = 0; - /// compute the size of .symtab, .dynsym and .strtab + Module::SymbolTable& symbols = pModule.getSymbolTable(); + Module::const_sym_iterator symbol, symEnd; + /// Compute the size of .symtab, .strtab, and symtab_local_cnt /// @{ - Module::const_sym_iterator symbol; - const Module::SymbolTable& symbols = pModule.getSymbolTable(); - size_t str_size = 0; - // compute the size of symbols in Local and File category - Module::const_sym_iterator symEnd = symbols.localEnd(); - for (symbol = symbols.localBegin(); symbol != symEnd; ++symbol) { - str_size = (*symbol)->nameSize() + 1; - if (!pIsStaticLink && isDynamicSymbol(**symbol)) { - ++dynsym; - if (ResolveInfo::Section != (*symbol)->type()) - dynstr += str_size; - } + symEnd = symbols.end(); + for (symbol = symbols.begin(); symbol != symEnd; ++symbol) { ++symtab; if (ResolveInfo::Section != (*symbol)->type()) - strtab += str_size; - } - // compute the size of symbols in TLS category - symEnd = symbols.tlsEnd(); - for (symbol = symbols.tlsBegin(); symbol != symEnd; ++symbol) { - str_size = (*symbol)->nameSize() + 1; - if (!pIsStaticLink) { - ++dynsym; - if (ResolveInfo::Section != (*symbol)->type()) - dynstr += str_size; - } - ++symtab; - if (ResolveInfo::Section != (*symbol)->type()) - strtab += str_size; - } - dynsym_local_cnt = dynsym; - // compute the size of the reset of symbols - symEnd = pModule.sym_end(); - for (symbol = symbols.tlsEnd(); symbol != symEnd; ++symbol) { - str_size = (*symbol)->nameSize() + 1; - if (!pIsStaticLink && isDynamicSymbol(**symbol)) { - ++dynsym; - if (ResolveInfo::Section != (*symbol)->type()) - dynstr += str_size; - } - ++symtab; - if (ResolveInfo::Section != (*symbol)->type()) - strtab += str_size; + strtab += (*symbol)->nameSize() + 1; } + symtab_local_cnt = 1 + symbols.numOfFiles() + symbols.numOfLocals() + + symbols.numOfLocalDyns(); ELFFileFormat* file_format = getOutputFormat(); switch(config().codeGenType()) { - // compute size of .dynstr and .hash case LinkerConfig::DynObj: { // soname - if (!pIsStaticLink) - dynstr += pModule.name().size() + 1; + dynstr += pModule.name().size() + 1; } /** fall through **/ case LinkerConfig::Exec: case LinkerConfig::Binary: { - // add DT_NEED strings into .dynstr and .dynamic - // Rules: - // 1. ignore --no-add-needed - // 2. force count in --no-as-needed - // 3. judge --as-needed if (!pIsStaticLink) { - Module::const_lib_iterator lib, libEnd = pModule.lib_end(); - for (lib = pModule.lib_begin(); lib != libEnd; ++lib) { - // --add-needed - if ((*lib)->attribute()->isAddNeeded()) { - // --no-as-needed - if (!(*lib)->attribute()->isAsNeeded()) { - dynstr += (*lib)->name().size() + 1; - dynamic().reserveNeedEntry(); - } - // --as-needed - else if ((*lib)->isNeeded()) { - dynstr += (*lib)->name().size() + 1; - dynamic().reserveNeedEntry(); - } + /// Compute the size of .dynsym, .dynstr, and dynsym_local_cnt + symEnd = symbols.dynamicEnd(); + for (symbol = symbols.localDynBegin(); symbol != symEnd; ++symbol) { + ++dynsym; + if (ResolveInfo::Section != (*symbol)->type()) + dynstr += (*symbol)->nameSize() + 1; + } + dynsym_local_cnt = 1 + symbols.numOfLocalDyns(); + + // compute .gnu.hash + if (GeneralOptions::GNU == config().options().getHashStyle() || + GeneralOptions::Both == config().options().getHashStyle()) { + // count the number of dynsym to hash + size_t hashed_sym_cnt = 0; + symEnd = symbols.dynamicEnd(); + for (symbol = symbols.dynamicBegin(); symbol != symEnd; ++symbol) { + if (DynsymCompare().needGNUHash(**symbol)) + ++hashed_sym_cnt; + } + // Special case for empty .dynsym + if (hashed_sym_cnt == 0) + gnuhash = 5 * 4 + config().targets().bitclass() / 8; + else { + size_t nbucket = getHashBucketCount(hashed_sym_cnt, true); + gnuhash = (4 + nbucket + hashed_sym_cnt) * 4; + gnuhash += (1U << getGNUHashMaskbitslog2(hashed_sym_cnt)) / 8; } } // compute .hash - // Both Elf32_Word and Elf64_Word are 4 bytes - hash = (2 + getHashBucketCount(dynsym, false) + dynsym) * - sizeof(llvm::ELF::Elf32_Word); - } + if (GeneralOptions::SystemV == config().options().getHashStyle() || + GeneralOptions::Both == config().options().getHashStyle()) { + // Both Elf32_Word and Elf64_Word are 4 bytes + hash = (2 + getHashBucketCount(dynsym, false) + dynsym) * + sizeof(llvm::ELF::Elf32_Word); + } - // set size - if (config().targets().is32Bits()) - file_format->getDynSymTab().setSize(dynsym*sizeof(llvm::ELF::Elf32_Sym)); - else - file_format->getDynSymTab().setSize(dynsym*sizeof(llvm::ELF::Elf64_Sym)); - file_format->getDynStrTab().setSize(dynstr); - file_format->getHashTab().setSize(hash); + // add DT_NEEDED + Module::const_lib_iterator lib, libEnd = pModule.lib_end(); + for (lib = pModule.lib_begin(); lib != libEnd; ++lib) { + if (!(*lib)->attribute()->isAsNeeded() || (*lib)->isNeeded()) { + dynstr += (*lib)->name().size() + 1; + dynamic().reserveNeedEntry(); + } + } - // set .dynsym sh_info to one greater than the symbol table - // index of the last local symbol - file_format->getDynSymTab().setInfo(dynsym_local_cnt); + // add DT_RPATH + if (!config().options().getRpathList().empty()) { + dynamic().reserveNeedEntry(); + GeneralOptions::const_rpath_iterator rpath, + rpathEnd = config().options().rpath_end(); + for (rpath = config().options().rpath_begin(); + rpath != rpathEnd; ++rpath) + dynstr += (*rpath).size() + 1; + } + + // set size + if (config().targets().is32Bits()) { + file_format->getDynSymTab().setSize(dynsym * + sizeof(llvm::ELF::Elf32_Sym)); + } else { + file_format->getDynSymTab().setSize(dynsym * + sizeof(llvm::ELF::Elf64_Sym)); + } + file_format->getDynStrTab().setSize(dynstr); + file_format->getHashTab().setSize(hash); + file_format->getGNUHashTab().setSize(gnuhash); + + // set .dynsym sh_info to one greater than the symbol table + // index of the last local symbol + file_format->getDynSymTab().setInfo(dynsym_local_cnt); + + // Because some entries in .dynamic section need information of .dynsym, + // .dynstr, .symtab, .strtab and .hash, we can not reserve non-DT_NEEDED + // entries until we get the size of the sections mentioned above + dynamic().reserveEntries(*file_format); + file_format->getDynamic().setSize(dynamic().numOfBytes()); + } } /* fall through */ case LinkerConfig::Object: { @@ -905,41 +870,46 @@ GNULDBackend::sizeNamePools(const Module& pModule, bool pIsStaticLink) // set .symtab sh_info to one greater than the symbol table // index of the last local symbol - file_format->getSymTab().setInfo(symbols.numOfLocals() + 1); + file_format->getSymTab().setInfo(symtab_local_cnt); + + // compute the size of .shstrtab section. + Module::const_iterator sect, sectEnd = pModule.end(); + for (sect = pModule.begin(); sect != sectEnd; ++sect) { + switch ((*sect)->kind()) { + case LDFileFormat::Null: + break; + // take StackNote directly + case LDFileFormat::StackNote: + shstrtab += ((*sect)->name().size() + 1); + break; + case LDFileFormat::EhFrame: + if (((*sect)->size() != 0) || + ((*sect)->hasEhFrame() && + config().codeGenType() == LinkerConfig::Object)) + shstrtab += ((*sect)->name().size() + 1); + break; + case LDFileFormat::Relocation: + if (((*sect)->size() != 0) || + ((*sect)->hasRelocData() && + config().codeGenType() == LinkerConfig::Object)) + shstrtab += ((*sect)->name().size() + 1); + break; + default: + if (((*sect)->size() != 0) || + ((*sect)->hasSectionData() && + config().codeGenType() == LinkerConfig::Object)) + shstrtab += ((*sect)->name().size() + 1); + break; + } // end of switch + } // end of for + shstrtab += (strlen(".shstrtab") + 1); + file_format->getShStrTab().setSize(shstrtab); break; } default: fatal(diag::fatal_illegal_codegen_type) << pModule.name(); break; } // end of switch - /// @} - - /// reserve fixed entries in the .dynamic section. - /// @{ - if (LinkerConfig::DynObj == config().codeGenType() || - LinkerConfig::Exec == config().codeGenType() || - LinkerConfig::Binary == config().codeGenType()) { - // Because some entries in .dynamic section need information of .dynsym, - // .dynstr, .symtab, .strtab and .hash, we can not reserve non-DT_NEEDED - // entries until we get the size of the sections mentioned above - if (!pIsStaticLink) - dynamic().reserveEntries(*file_format); - file_format->getDynamic().setSize(dynamic().numOfBytes()); - } - /// @} - - /// compute the size of .shstrtab section. - /// @{ - Module::const_iterator sect, sectEnd = pModule.end(); - for (sect = pModule.begin(); sect != sectEnd; ++sect) { - // StackNote sections will always be in output! - if (0 != (*sect)->size() || LDFileFormat::StackNote == (*sect)->kind()) { - shstrtab += ((*sect)->name().size() + 1); - } - } - shstrtab += (strlen(".shstrtab") + 1); - file_format->getShStrTab().setSize(shstrtab); - /// @} } /// emitSymbol32 - emit an ELF32 symbol @@ -974,14 +944,19 @@ void GNULDBackend::emitSymbol64(llvm::ELF::Elf64_Sym& pSym, { // FIXME: check the endian between host and target // write out symbol + if (ResolveInfo::Section != pSymbol.type()) { + pSym.st_name = pStrtabsize; + strcpy((pStrtab + pStrtabsize), pSymbol.name()); + } + else { + pSym.st_name = 0; + } pSym.st_name = pStrtabsize; pSym.st_value = pSymbol.value(); pSym.st_size = getSymbolSize(pSymbol); pSym.st_info = getSymbolInfo(pSymbol); pSym.st_other = pSymbol.visibility(); pSym.st_shndx = getSymbolShndx(pSymbol); - // write out string - strcpy((pStrtab + pStrtabsize), pSymbol.name()); } /// emitRegNamePools - emit regular name pools - .symtab, .strtab @@ -1015,54 +990,37 @@ void GNULDBackend::emitRegNamePools(const Module& pModule, // set up strtab_region char* strtab = (char*)strtab_region->start(); - strtab[0] = '\0'; - // initialize the first ELF symbol - if (config().targets().is32Bits()) { - symtab32[0].st_name = 0; - symtab32[0].st_value = 0; - symtab32[0].st_size = 0; - symtab32[0].st_info = 0; - symtab32[0].st_other = 0; - symtab32[0].st_shndx = 0; - } - else { // must 64 - symtab64[0].st_name = 0; - symtab64[0].st_value = 0; - symtab64[0].st_size = 0; - symtab64[0].st_info = 0; - symtab64[0].st_other = 0; - symtab64[0].st_shndx = 0; - } + // emit the first ELF symbol + if (config().targets().is32Bits()) + emitSymbol32(symtab32[0], *LDSymbol::Null(), strtab, 0, 0); + else + emitSymbol64(symtab64[0], *LDSymbol::Null(), strtab, 0, 0); bool sym_exist = false; HashTableType::entry_type* entry = NULL; if (LinkerConfig::Object == config().codeGenType()) { - entry = m_pSymIndexMap->insert(NULL, sym_exist); + entry = m_pSymIndexMap->insert(LDSymbol::Null(), sym_exist); entry->setValue(0); } - size_t symtabIdx = 1; + size_t symIdx = 1; size_t strtabsize = 1; - // compute size of .symtab, .dynsym and .strtab - Module::const_sym_iterator symbol; - Module::const_sym_iterator symEnd = pModule.sym_end(); - for (symbol = pModule.sym_begin(); symbol != symEnd; ++symbol) { - // maintain output's symbol and index map if building .o file + + const Module::SymbolTable& symbols = pModule.getSymbolTable(); + Module::const_sym_iterator symbol, symEnd; + + symEnd = symbols.end(); + for (symbol = symbols.begin(); symbol != symEnd; ++symbol) { if (LinkerConfig::Object == config().codeGenType()) { entry = m_pSymIndexMap->insert(*symbol, sym_exist); - entry->setValue(symtabIdx); + entry->setValue(symIdx); } - if (config().targets().is32Bits()) - emitSymbol32(symtab32[symtabIdx], **symbol, strtab, strtabsize, - symtabIdx); + emitSymbol32(symtab32[symIdx], **symbol, strtab, strtabsize, symIdx); else - emitSymbol64(symtab64[symtabIdx], **symbol, strtab, strtabsize, - symtabIdx); - - // sum up counters - ++symtabIdx; + emitSymbol64(symtab64[symIdx], **symbol, strtab, strtabsize, symIdx); + ++symIdx; if (ResolveInfo::Section != (*symbol)->type()) strtabsize += (*symbol)->nameSize() + 1; } @@ -1072,13 +1030,11 @@ void GNULDBackend::emitRegNamePools(const Module& pModule, /// /// the size of these tables should be computed before layout /// layout should computes the start offset of these tables -void GNULDBackend::emitDynNamePools(const Module& pModule, - MemoryArea& pOutput) +void GNULDBackend::emitDynNamePools(Module& pModule, MemoryArea& pOutput) { ELFFileFormat* file_format = getOutputFormat(); if (!file_format->hasDynSymTab() || !file_format->hasDynStrTab() || - !file_format->hasHashTab() || !file_format->hasDynamic()) return; @@ -1087,15 +1043,12 @@ void GNULDBackend::emitDynNamePools(const Module& pModule, LDSection& symtab_sect = file_format->getDynSymTab(); LDSection& strtab_sect = file_format->getDynStrTab(); - LDSection& hash_sect = file_format->getHashTab(); LDSection& dyn_sect = file_format->getDynamic(); MemoryRegion* symtab_region = pOutput.request(symtab_sect.offset(), symtab_sect.size()); MemoryRegion* strtab_region = pOutput.request(strtab_sect.offset(), strtab_sect.size()); - MemoryRegion* hash_region = pOutput.request(hash_sect.offset(), - hash_sect.size()); MemoryRegion* dyn_region = pOutput.request(dyn_sect.offset(), dyn_sect.size()); // set up symtab_region @@ -1110,125 +1063,76 @@ void GNULDBackend::emitDynNamePools(const Module& pModule, << config().targets().bitclass(); } - // initialize the first ELF symbol - if (config().targets().is32Bits()) { - symtab32[0].st_name = 0; - symtab32[0].st_value = 0; - symtab32[0].st_size = 0; - symtab32[0].st_info = 0; - symtab32[0].st_other = 0; - symtab32[0].st_shndx = 0; - } - else { // must 64 - symtab64[0].st_name = 0; - symtab64[0].st_value = 0; - symtab64[0].st_size = 0; - symtab64[0].st_info = 0; - symtab64[0].st_other = 0; - symtab64[0].st_shndx = 0; - } // set up strtab_region char* strtab = (char*)strtab_region->start(); - strtab[0] = '\0'; - // add the first symbol into m_pSymIndexMap - entry = m_pSymIndexMap->insert(NULL, sym_exist); - entry->setValue(0); + // emit the first ELF symbol + if (config().targets().is32Bits()) + emitSymbol32(symtab32[0], *LDSymbol::Null(), strtab, 0, 0); + else + emitSymbol64(symtab64[0], *LDSymbol::Null(), strtab, 0, 0); - size_t symtabIdx = 1; + size_t symIdx = 1; size_t strtabsize = 1; - // emit of .dynsym, and .dynstr - Module::const_sym_iterator symbol; - const Module::SymbolTable& symbols = pModule.getSymbolTable(); - // emit symbol in File and Local category if it's dynamic symbol - Module::const_sym_iterator symEnd = symbols.localEnd(); - for (symbol = symbols.localBegin(); symbol != symEnd; ++symbol) { - if (!isDynamicSymbol(**symbol)) - continue; - + Module::SymbolTable& symbols = pModule.getSymbolTable(); + // emit .gnu.hash + if (GeneralOptions::GNU == config().options().getHashStyle() || + GeneralOptions::Both == config().options().getHashStyle()) { + // Currently we may add output symbols after sizeNamePools(), and a + // non-stable sort is used in SymbolCategory::arrange(), so we just + // sort .dynsym right before emitting .gnu.hash + std::stable_sort(symbols.dynamicBegin(), symbols.dynamicEnd(), + DynsymCompare()); + emitGNUHashTab(symbols, pOutput); + } + // emit .hash + if (GeneralOptions::SystemV == config().options().getHashStyle() || + GeneralOptions::Both == config().options().getHashStyle()) + emitELFHashTab(symbols, pOutput); + + // emit .dynsym, and .dynstr (emit LocalDyn and Dynamic category) + Module::const_sym_iterator symbol, symEnd = symbols.dynamicEnd(); + for (symbol = symbols.localDynBegin(); symbol != symEnd; ++symbol) { if (config().targets().is32Bits()) - emitSymbol32(symtab32[symtabIdx], **symbol, strtab, strtabsize, - symtabIdx); + emitSymbol32(symtab32[symIdx], **symbol, strtab, strtabsize, symIdx); else - emitSymbol64(symtab64[symtabIdx], **symbol, strtab, strtabsize, - symtabIdx); - + emitSymbol64(symtab64[symIdx], **symbol, strtab, strtabsize, symIdx); // maintain output's symbol and index map entry = m_pSymIndexMap->insert(*symbol, sym_exist); - entry->setValue(symtabIdx); + entry->setValue(symIdx); // sum up counters - ++symtabIdx; - if (ResolveInfo::Section != (*symbol)->type()) - strtabsize += (*symbol)->nameSize() + 1; - } - - // emit symbols in TLS category, all symbols in TLS category shold be emitited - symEnd = symbols.tlsEnd(); - for (symbol = symbols.tlsBegin(); symbol != symEnd; ++symbol) { - if (config().targets().is32Bits()) - emitSymbol32(symtab32[symtabIdx], **symbol, strtab, strtabsize, - symtabIdx); - else - emitSymbol64(symtab64[symtabIdx], **symbol, strtab, strtabsize, - symtabIdx); - - // maintain output's symbol and index map - entry = m_pSymIndexMap->insert(*symbol, sym_exist); - entry->setValue(symtabIdx); - // sum up counters - ++symtabIdx; - if (ResolveInfo::Section != (*symbol)->type()) - strtabsize += (*symbol)->nameSize() + 1; - } - - // emit the reset of the symbols if the symbol is dynamic symbol - symEnd = pModule.sym_end(); - for (symbol = symbols.tlsEnd(); symbol != symEnd; ++symbol) { - if (!isDynamicSymbol(**symbol)) - continue; - - if (config().targets().is32Bits()) - emitSymbol32(symtab32[symtabIdx], **symbol, strtab, strtabsize, - symtabIdx); - else - emitSymbol64(symtab64[symtabIdx], **symbol, strtab, strtabsize, - symtabIdx); - - // maintain output's symbol and index map - entry = m_pSymIndexMap->insert(*symbol, sym_exist); - entry->setValue(symtabIdx); - // sum up counters - ++symtabIdx; + ++symIdx; if (ResolveInfo::Section != (*symbol)->type()) strtabsize += (*symbol)->nameSize() + 1; } // emit DT_NEED // add DT_NEED strings into .dynstr - // Rules: - // 1. ignore --no-add-needed - // 2. force count in --no-as-needed - // 3. judge --as-needed ELFDynamic::iterator dt_need = dynamic().needBegin(); Module::const_lib_iterator lib, libEnd = pModule.lib_end(); for (lib = pModule.lib_begin(); lib != libEnd; ++lib) { - // --add-needed - if ((*lib)->attribute()->isAddNeeded()) { - // --no-as-needed - if (!(*lib)->attribute()->isAsNeeded()) { - strcpy((strtab + strtabsize), (*lib)->name().c_str()); - (*dt_need)->setValue(llvm::ELF::DT_NEEDED, strtabsize); - strtabsize += (*lib)->name().size() + 1; - ++dt_need; - } - // --as-needed - else if ((*lib)->isNeeded()) { - strcpy((strtab + strtabsize), (*lib)->name().c_str()); - (*dt_need)->setValue(llvm::ELF::DT_NEEDED, strtabsize); - strtabsize += (*lib)->name().size() + 1; - ++dt_need; - } + if (!(*lib)->attribute()->isAsNeeded() || (*lib)->isNeeded()) { + strcpy((strtab + strtabsize), (*lib)->name().c_str()); + (*dt_need)->setValue(llvm::ELF::DT_NEEDED, strtabsize); + strtabsize += (*lib)->name().size() + 1; + ++dt_need; + } + } + + if (!config().options().getRpathList().empty()) { + if (!config().options().hasNewDTags()) + (*dt_need)->setValue(llvm::ELF::DT_RPATH, strtabsize); + else + (*dt_need)->setValue(llvm::ELF::DT_RUNPATH, strtabsize); + ++dt_need; + + GeneralOptions::const_rpath_iterator rpath, + rpathEnd = config().options().rpath_end(); + for (rpath = config().options().rpath_begin(); rpath != rpathEnd; ++rpath) { + memcpy((strtab + strtabsize), (*rpath).data(), (*rpath).size()); + strtabsize += (*rpath).size(); + strtab[strtabsize++] = (rpath + 1 == rpathEnd ? '\0' : ':'); } } @@ -1245,18 +1149,27 @@ void GNULDBackend::emitDynNamePools(const Module& pModule, strcpy((strtab + strtabsize), pModule.name().c_str()); strtabsize += pModule.name().size() + 1; } - // emit hash table - // FIXME: this verion only emit SVR4 hash section. - // Please add GNU new hash section +} +/// emitELFHashTab - emit .hash +void GNULDBackend::emitELFHashTab(const Module::SymbolTable& pSymtab, + MemoryArea& pOutput) +{ + ELFFileFormat* file_format = getOutputFormat(); + if (!file_format->hasHashTab()) + return; + LDSection& hash_sect = file_format->getHashTab(); + MemoryRegion* hash_region = pOutput.request(hash_sect.offset(), + hash_sect.size()); // both 32 and 64 bits hash table use 32-bit entry // set up hash_region uint32_t* word_array = (uint32_t*)hash_region->start(); uint32_t& nbucket = word_array[0]; uint32_t& nchain = word_array[1]; - nbucket = getHashBucketCount(symtabIdx, false); - nchain = symtabIdx; + size_t dynsymSize = 1 + pSymtab.numOfLocalDyns() + pSymtab.numOfDynamics(); + nbucket = getHashBucketCount(dynsymSize, false); + nchain = dynsymSize; uint32_t* bucket = (word_array + 2); uint32_t* chain = (bucket + nbucket); @@ -1266,21 +1179,140 @@ void GNULDBackend::emitDynNamePools(const Module& pModule, StringHash<ELF> hash_func; - if (config().targets().is32Bits()) { - for (size_t sym_idx=0; sym_idx < symtabIdx; ++sym_idx) { - llvm::StringRef name(strtab + symtab32[sym_idx].st_name); - size_t bucket_pos = hash_func(name) % nbucket; - chain[sym_idx] = bucket[bucket_pos]; - bucket[bucket_pos] = sym_idx; + size_t idx = 1; + Module::const_sym_iterator symbol, symEnd = pSymtab.dynamicEnd(); + for (symbol = pSymtab.localDynBegin(); symbol != symEnd; ++symbol) { + llvm::StringRef name((*symbol)->name()); + size_t bucket_pos = hash_func(name) % nbucket; + chain[idx] = bucket[bucket_pos]; + bucket[bucket_pos] = idx; + ++idx; + } +} + +/// emitGNUHashTab - emit .gnu.hash +void GNULDBackend::emitGNUHashTab(Module::SymbolTable& pSymtab, + MemoryArea& pOutput) +{ + ELFFileFormat* file_format = getOutputFormat(); + if (!file_format->hasGNUHashTab()) + return; + + MemoryRegion* gnuhash_region = + pOutput.request(file_format->getGNUHashTab().offset(), + file_format->getGNUHashTab().size()); + + uint32_t* word_array = (uint32_t*)gnuhash_region->start(); + // fixed-length fields + uint32_t& nbucket = word_array[0]; + uint32_t& symidx = word_array[1]; + uint32_t& maskwords = word_array[2]; + uint32_t& shift2 = word_array[3]; + // variable-length fields + uint8_t* bitmask = (uint8_t*)(word_array + 4); + uint32_t* bucket = NULL; + uint32_t* chain = NULL; + + // count the number of dynsym to hash + size_t unhashed_sym_cnt = pSymtab.numOfLocalDyns(); + size_t hashed_sym_cnt = pSymtab.numOfDynamics(); + Module::const_sym_iterator symbol, symEnd = pSymtab.dynamicEnd(); + for (symbol = pSymtab.dynamicBegin(); symbol != symEnd; ++symbol) { + if (DynsymCompare().needGNUHash(**symbol)) + break; + ++unhashed_sym_cnt; + --hashed_sym_cnt; + } + + // special case for the empty hash table + if (hashed_sym_cnt == 0) { + nbucket = 1; // one empty bucket + symidx = 1 + unhashed_sym_cnt; // symidx above unhashed symbols + maskwords = 1; // bitmask length + shift2 = 0; // bloom filter + + if (config().targets().is32Bits()) { + uint32_t* maskval = (uint32_t*)bitmask; + *maskval = 0; // no valid hashes + } else { + // must be 64 + uint64_t* maskval = (uint64_t*)bitmask; + *maskval = 0; // no valid hashes } + bucket = (uint32_t*)(bitmask + config().targets().bitclass() / 8); + *bucket = 0; // no hash in the only bucket + return; } - else if (config().targets().is64Bits()) { - for (size_t sym_idx=0; sym_idx < symtabIdx; ++sym_idx) { - llvm::StringRef name(strtab + symtab64[sym_idx].st_name); - size_t bucket_pos = hash_func(name) % nbucket; - chain[sym_idx] = bucket[bucket_pos]; - bucket[bucket_pos] = sym_idx; + + uint32_t maskbitslog2 = getGNUHashMaskbitslog2(hashed_sym_cnt); + uint32_t maskbits = 1u << maskbitslog2; + uint32_t shift1 = config().targets().is32Bits() ? 5 : 6; + uint32_t mask = (1u << shift1) - 1; + + nbucket = getHashBucketCount(hashed_sym_cnt, true); + symidx = 1 + unhashed_sym_cnt; + maskwords = 1 << (maskbitslog2 - shift1); + shift2 = maskbitslog2; + + // setup bucket and chain + bucket = (uint32_t*)(bitmask + maskbits / 8); + chain = (bucket + nbucket); + + // build the gnu style hash table + typedef std::multimap<uint32_t, + std::pair<LDSymbol*, uint32_t> > SymMapType; + SymMapType symmap; + symEnd = pSymtab.dynamicEnd(); + for (symbol = pSymtab.localDynBegin() + symidx - 1; symbol != symEnd; + ++symbol) { + StringHash<DJB> hasher; + uint32_t djbhash = hasher((*symbol)->name()); + uint32_t hash = djbhash % nbucket; + symmap.insert(std::make_pair(hash, std::make_pair(*symbol, djbhash))); + } + + // compute bucket, chain, and bitmask + std::vector<uint64_t> bitmasks(maskwords); + size_t hashedidx = symidx; + for (size_t idx = 0; idx < nbucket; ++idx) { + size_t count = 0; + std::pair<SymMapType::iterator, SymMapType::iterator> ret; + ret = symmap.equal_range(idx); + for (SymMapType::iterator it = ret.first; it != ret.second; ) { + // rearrange the hashed symbol ordering + *(pSymtab.localDynBegin() + hashedidx - 1) = it->second.first; + uint32_t djbhash = it->second.second; + uint32_t val = ((djbhash >> shift1) & ((maskbits >> shift1) - 1)); + bitmasks[val] |= 1u << (djbhash & mask); + bitmasks[val] |= 1u << ((djbhash >> shift2) & mask); + val = djbhash & ~1u; + // advance the iterator and check if we're dealing w/ the last elment + if (++it == ret.second) { + // last element terminates the chain + val |= 1; + } + chain[hashedidx - symidx] = val; + + ++hashedidx; + ++count; } + + if (count == 0) + bucket[idx] = 0; + else + bucket[idx] = hashedidx - count; + } + + // write the bitmasks + if (config().targets().is32Bits()) { + uint32_t* maskval = (uint32_t*)bitmask; + for (size_t i = 0; i < maskwords; ++i) + std::memcpy(maskval + i, &bitmasks[i], 4); + } else { + // must be 64 + uint64_t* maskval = (uint64_t*)bitmask; + for (size_t i = 0; i < maskwords; ++i) + std::memcpy(maskval + i, &bitmasks[i], 8); } } @@ -1291,7 +1323,7 @@ void GNULDBackend::sizeInterp() if (config().options().hasDyld()) dyld_name = config().options().dyld().c_str(); else - dyld_name = dyld(); + dyld_name = m_pInfo->dyld(); LDSection& interp = getOutputFormat()->getInterp(); interp.setSize(std::strlen(dyld_name) + 1); @@ -1307,7 +1339,7 @@ void GNULDBackend::emitInterp(MemoryArea& pOutput) if (config().options().hasDyld()) dyld_name = config().options().dyld().c_str(); else - dyld_name = dyld(); + dyld_name = m_pInfo->dyld(); std::memcpy(region->start(), dyld_name, interp.size()); } @@ -1381,9 +1413,14 @@ unsigned int GNULDBackend::getSectionOrder(const LDSection& pSectHdr) const case LDFileFormat::Target: return getTargetSectionOrder(pSectHdr); - // handle .interp + // handle .interp and .note.* sections case LDFileFormat::Note: - return SHO_INTERP; + if (file_format->hasInterp() && (&pSectHdr == &file_format->getInterp())) + return SHO_INTERP; + else if (is_write) + return SHO_RW_NOTE; + else + return SHO_RO_NOTE; case LDFileFormat::EhFrame: case LDFileFormat::EhFrameHdr: @@ -1456,7 +1493,8 @@ GNULDBackend::getSymbolShndx(const LDSymbol& pSymbol) const if (pSymbol.resolveInfo()->isUndef() || pSymbol.isDyn()) return llvm::ELF::SHN_UNDEF; - if (pSymbol.resolveInfo()->isLocal()) { + if (pSymbol.resolveInfo()->isLocal() && + LinkerConfig::Object != config().codeGenType()) { switch (pSymbol.type()) { case ResolveInfo::NoType: case ResolveInfo::File: @@ -1472,12 +1510,43 @@ GNULDBackend::getSymbolShndx(const LDSymbol& pSymbol) const } /// getSymbolIdx - called by emitRelocation to get the ouput symbol table index -size_t GNULDBackend::getSymbolIdx(LDSymbol* pSymbol) const +size_t GNULDBackend::getSymbolIdx(const LDSymbol* pSymbol) const { - HashTableType::iterator entry = m_pSymIndexMap->find(pSymbol); + HashTableType::iterator entry = m_pSymIndexMap->find(const_cast<LDSymbol *>(pSymbol)); + assert(entry != m_pSymIndexMap->end() && "symbol not found in the symbol table"); return entry.getEntry()->value(); } +/// isTemporary - Whether pSymbol is a local label. +bool GNULDBackend::isTemporary(const LDSymbol& pSymbol) const +{ + if (ResolveInfo::Local != pSymbol.binding()) + return false; + + if (pSymbol.nameSize() < 2) + return false; + + const char* name = pSymbol.name(); + if ('.' == name[0] && 'L' == name[1]) + return true; + + // UnixWare 2.1 cc generate DWARF debugging symbols with `..' prefix. + // @ref Google gold linker, target.cc:39 @@ Target::do_is_local_label_name() + if (name[0] == '.' && name[1] == '.') + return true; + + // Work arround for gcc's bug + // gcc sometimes generate symbols with '_.L_' prefix. + // @ref Google gold linker, target.cc:39 @@ Target::do_is_local_label_name() + if (pSymbol.nameSize() < 4) + return false; + + if (name[0] == '_' && name[1] == '.' && name[2] == 'L' && name[3] == '_') + return true; + + return false; +} + /// allocateCommonSymbols - allocate common symbols in the corresponding /// sections. This is executed at pre-layout stage. /// @refer Google gold linker: common.cc: 214 @@ -1486,7 +1555,8 @@ GNULDBackend::allocateCommonSymbols(Module& pModule) { SymbolCategory& symbol_list = pModule.getSymbolTable(); - if (symbol_list.emptyCommons() && symbol_list.emptyLocals()) + if (symbol_list.emptyCommons() && symbol_list.emptyFiles() && + symbol_list.emptyLocals() && symbol_list.emptyLocalDyns()) return true; SymbolCategory::iterator com_sym, com_end; @@ -1575,10 +1645,33 @@ GNULDBackend::allocateCommonSymbols(Module& pModule) return true; } +/// updateSectionFlags - update pTo's flags when merging pFrom +/// update the output section flags based on input section flags. +/// @ref The Google gold linker: +/// output.cc: 2809: Output_section::update_flags_for_input_section +bool GNULDBackend::updateSectionFlags(LDSection& pTo, const LDSection& pFrom) +{ + // union the flags from input + uint32_t flags = pTo.flag(); + flags |= (pFrom.flag() & + (llvm::ELF::SHF_WRITE | + llvm::ELF::SHF_ALLOC | + llvm::ELF::SHF_EXECINSTR)); + + // if there is an input section is not SHF_MERGE, clean this flag + if (0 == (pFrom.flag() & llvm::ELF::SHF_MERGE)) + flags &= ~llvm::ELF::SHF_MERGE; + + // if there is an input section is not SHF_STRINGS, clean this flag + if (0 == (pFrom.flag() & llvm::ELF::SHF_STRINGS)) + flags &= ~llvm::ELF::SHF_STRINGS; + + pTo.setFlag(flags); + return true; +} /// createProgramHdrs - base on output sections to create the program headers -void GNULDBackend::createProgramHdrs(Module& pModule, - const FragmentLinker& pLinker) +void GNULDBackend::createProgramHdrs(Module& pModule) { ELFFileFormat *file_format = getOutputFormat(); @@ -1633,7 +1726,8 @@ void GNULDBackend::createProgramHdrs(Module& pModule, if (createPT_LOAD) { // create new PT_LOAD segment load_seg = m_ELFSegmentTable.produce(llvm::ELF::PT_LOAD, cur_flag); - load_seg->setAlign(abiPageSize()); + if (!config().options().nmagic() && !config().options().omagic()) + load_seg->setAlign(abiPageSize()); } assert(NULL != load_seg); @@ -1695,12 +1789,31 @@ void GNULDBackend::createProgramHdrs(Module& pModule, getSegmentFlag(file_format->getStackNote().flag())); } + // make PT_NOTE + ELFSegment *note_seg = NULL; + prev_flag = getSegmentFlag(0); + for (sect = pModule.begin(); sect != sect_end; ++sect) { + if ((*sect)->kind() != LDFileFormat::Note || + ((*sect)->flag() & llvm::ELF::SHF_ALLOC) == 0) + continue; + + cur_flag = getSegmentFlag((*sect)->flag()); + // we have different section orders for read-only and writable notes, so + // create 2 segments if needed. + if (note_seg == NULL || + (cur_flag & llvm::ELF::PF_W) != (prev_flag & llvm::ELF::PF_W)) + note_seg = m_ELFSegmentTable.produce(llvm::ELF::PT_NOTE, cur_flag); + + note_seg->addSection(*sect); + prev_flag = cur_flag; + } + // create target dependent segments - doCreateProgramHdrs(pModule, pLinker); + doCreateProgramHdrs(pModule); } /// setupProgramHdrs - set up the attributes of segments -void GNULDBackend::setupProgramHdrs(const FragmentLinker& pLinker) +void GNULDBackend::setupProgramHdrs() { // update segment info ELFSegmentFactory::iterator seg, seg_end = m_ELFSegmentTable.end(); @@ -1719,7 +1832,7 @@ void GNULDBackend::setupProgramHdrs(const FragmentLinker& pLinker) phdr_size = sizeof(llvm::ELF::Elf64_Phdr); } segment.setOffset(offset); - segment.setVaddr(segmentStartAddr(pLinker) + offset); + segment.setVaddr(segmentStartAddr() + offset); segment.setPaddr(segment.vaddr()); segment.setFilesz(numOfSegments() * phdr_size); segment.setMemsz(numOfSegments() * phdr_size); @@ -1734,7 +1847,7 @@ void GNULDBackend::setupProgramHdrs(const FragmentLinker& pLinker) segment.setOffset(segment.front()->offset()); if (llvm::ELF::PT_LOAD == segment.type() && LDFileFormat::Null == segment.front()->kind()) - segment.setVaddr(segmentStartAddr(pLinker)); + segment.setVaddr(segmentStartAddr()); else segment.setVaddr(segment.front()->addr()); segment.setPaddr(segment.vaddr()); @@ -1752,7 +1865,7 @@ void GNULDBackend::setupProgramHdrs(const FragmentLinker& pLinker) /// setupGNUStackInfo - setup the section flag of .note.GNU-stack in output /// @ref gold linker: layout.cc:2608 -void GNULDBackend::setupGNUStackInfo(Module& pModule, FragmentLinker& pLinker) +void GNULDBackend::setupGNUStackInfo(Module& pModule) { uint32_t flag = 0x0; if (config().options().hasStackSet()) { @@ -1787,7 +1900,7 @@ void GNULDBackend::setupGNUStackInfo(Module& pModule, FragmentLinker& pLinker) // 2.3 a special case. Use the target default to decide if the stack should // be executable if (llvm::ELF::SHF_EXECINSTR != flag && object_count != stack_note_count) - if (isDefaultExecStack()) + if (m_pInfo->isDefaultExecStack()) flag = llvm::ELF::SHF_EXECINSTR; } @@ -1877,8 +1990,7 @@ void GNULDBackend::setOutputSectionOffset(Module& pModule, } /// setOutputSectionOffset - helper function to set output sections' address -void GNULDBackend::setOutputSectionAddress(FragmentLinker& pLinker, - Module& pModule, +void GNULDBackend::setOutputSectionAddress(Module& pModule, Module::iterator pSectBegin, Module::iterator pSectEnd) { @@ -1907,39 +2019,43 @@ void GNULDBackend::setOutputSectionAddress(FragmentLinker& pLinker, mapping = config().scripts().addressMap().find((*seg).front()->name()); if (mapping != config().scripts().addressMap().end()) { - // check address mapping + // use address mapping in script options start_addr = mapping.getEntry()->value(); - if ((*seg).front()->kind() != LDFileFormat::Null) { - const uint64_t remainder = start_addr % abiPageSize(); - if (remainder != (*seg).front()->offset() % abiPageSize()) { - uint64_t padding = abiPageSize() + remainder - - (*seg).front()->offset() % abiPageSize(); - setOutputSectionOffset(pModule, - pModule.begin() + (*seg).front()->index(), - pModule.end(), - (*seg).front()->offset() + padding); - if (config().options().hasRelro()) - setupRelro(pModule); - } - } } else { if ((*seg).front()->kind() == LDFileFormat::Null) { // 1st PT_LOAD - start_addr = segmentStartAddr(pLinker); + start_addr = segmentStartAddr(); } else if ((*prev).front()->kind() == LDFileFormat::Null) { // prev segment is 1st PT_LOAD - start_addr = segmentStartAddr(pLinker) + (*seg).front()->offset(); + start_addr = segmentStartAddr() + (*seg).front()->offset(); } else { // Others start_addr = (*prev).front()->addr() + (*seg).front()->offset(); } + // Try to align p_vaddr at page boundary if not in script options. + // To do so will add more padding in file, but can save one page + // at runtime. + alignAddress(start_addr, (*seg).align()); + } - // padding - if (((*seg).front()->offset() & (abiPageSize() - 1)) != 0) - start_addr += abiPageSize(); + // in p75, http://www.sco.com/developers/devspecs/gabi41.pdf + // p_align: As "Program Loading" describes in this chapter of the + // processor supplement, loadable process segments must have congruent + // values for p_vaddr and p_offset, modulo the page size. + if ((start_addr & ((*seg).align() - 1)) != + ((*seg).front()->offset() & ((*seg).align() - 1))) { + uint64_t padding = (*seg).align() + + (start_addr & ((*seg).align() - 1)) - + ((*seg).front()->offset() & ((*seg).align() - 1)); + setOutputSectionOffset(pModule, + pModule.begin() + (*seg).front()->index(), + pModule.end(), + (*seg).front()->offset() + padding); + if (config().options().hasRelro()) + setupRelro(pModule); } for (ELFSegment::sect_iterator sect = (*seg).begin(), @@ -1963,7 +2079,7 @@ void GNULDBackend::setOutputSectionAddress(FragmentLinker& pLinker, } /// layout - layout method -void GNULDBackend::layout(Module& pModule, FragmentLinker& pLinker) +void GNULDBackend::layout(Module& pModule) { std::vector<SHOEntry> output_list; // 1. determine what sections will go into final output, and push the needed @@ -1971,44 +2087,55 @@ void GNULDBackend::layout(Module& pModule, FragmentLinker& pLinker) for (Module::iterator it = pModule.begin(), ie = pModule.end(); it != ie; ++it) { switch ((*it)->kind()) { - // take NULL and StackNote directly - case LDFileFormat::Null: - case LDFileFormat::StackNote: + // take NULL and StackNote directly + case LDFileFormat::Null: + case LDFileFormat::StackNote: + output_list.push_back(std::make_pair(*it, getSectionOrder(**it))); + break; + // ignore if section size is 0 + case LDFileFormat::EhFrame: + if (((*it)->size() != 0) || + ((*it)->hasEhFrame() && + config().codeGenType() == LinkerConfig::Object)) output_list.push_back(std::make_pair(*it, getSectionOrder(**it))); - break; - // ignore if section size is 0 - case LDFileFormat::Regular: - case LDFileFormat::Target: - case LDFileFormat::MetaData: - case LDFileFormat::BSS: - case LDFileFormat::Debug: - case LDFileFormat::EhFrame: - case LDFileFormat::GCCExceptTable: - case LDFileFormat::NamePool: - case LDFileFormat::Relocation: - case LDFileFormat::Note: - case LDFileFormat::EhFrameHdr: - if (0 != (*it)->size()) { - output_list.push_back(std::make_pair(*it, getSectionOrder(**it))); - } - break; - case LDFileFormat::Group: - if (LinkerConfig::Object == config().codeGenType()) { - //TODO: support incremental linking - ; - } - break; - case LDFileFormat::Version: - if (0 != (*it)->size()) { - output_list.push_back(std::make_pair(*it, getSectionOrder(**it))); - warning(diag::warn_unsupported_symbolic_versioning) << (*it)->name(); - } - break; - default: - if (0 != (*it)->size()) { - error(diag::err_unsupported_section) << (*it)->name() << (*it)->kind(); - } - break; + break; + case LDFileFormat::Relocation: + if (((*it)->size() != 0) || + ((*it)->hasRelocData() && + config().codeGenType() == LinkerConfig::Object)) + output_list.push_back(std::make_pair(*it, getSectionOrder(**it))); + break; + case LDFileFormat::Regular: + case LDFileFormat::Target: + case LDFileFormat::MetaData: + case LDFileFormat::BSS: + case LDFileFormat::Debug: + case LDFileFormat::GCCExceptTable: + case LDFileFormat::Note: + case LDFileFormat::NamePool: + case LDFileFormat::EhFrameHdr: + if (((*it)->size() != 0) || + ((*it)->hasSectionData() && + config().codeGenType() == LinkerConfig::Object)) + output_list.push_back(std::make_pair(*it, getSectionOrder(**it))); + break; + case LDFileFormat::Group: + if (LinkerConfig::Object == config().codeGenType()) { + //TODO: support incremental linking + ; + } + break; + case LDFileFormat::Version: + if (0 != (*it)->size()) { + output_list.push_back(std::make_pair(*it, getSectionOrder(**it))); + warning(diag::warn_unsupported_symbolic_versioning) << (*it)->name(); + } + break; + default: + if (0 != (*it)->size()) { + error(diag::err_unsupported_section) << (*it)->name() << (*it)->kind(); + } + break; } } // end of for @@ -2024,7 +2151,7 @@ void GNULDBackend::layout(Module& pModule, FragmentLinker& pLinker) // 4. create program headers if (LinkerConfig::Object != config().codeGenType()) { - createProgramHdrs(pModule, pLinker); + createProgramHdrs(pModule); } // 5. set output section offset @@ -2032,12 +2159,13 @@ void GNULDBackend::layout(Module& pModule, FragmentLinker& pLinker) } /// preLayout - Backend can do any needed modification before layout -void GNULDBackend::preLayout(Module& pModule, FragmentLinker& pLinker) +void GNULDBackend::preLayout(Module& pModule, IRBuilder& pBuilder) { // prelayout target first - doPreLayout(pLinker); + doPreLayout(pBuilder); - if (config().options().hasEhFrameHdr() && getOutputFormat()->hasEhFrame()) { + if (LinkerConfig::Object != config().codeGenType() && + config().options().hasEhFrameHdr() && getOutputFormat()->hasEhFrame()) { // init EhFrameHdr and size the output section ELFFileFormat* format = getOutputFormat(); m_pEhFrameHdr = new EhFrameHdr(format->getEhFrameHdr(), @@ -2045,12 +2173,12 @@ void GNULDBackend::preLayout(Module& pModule, FragmentLinker& pLinker) m_pEhFrameHdr->sizeOutput(); } - // change .tbss and .tdata section symbol from Local to TLS category + // change .tbss and .tdata section symbol from Local to LocalDyn category if (NULL != f_pTDATA) - pModule.getSymbolTable().changeLocalToTLS(*f_pTDATA); + pModule.getSymbolTable().changeLocalToDynamic(*f_pTDATA); if (NULL != f_pTBSS) - pModule.getSymbolTable().changeLocalToTLS(*f_pTBSS); + pModule.getSymbolTable().changeLocalToDynamic(*f_pTBSS); // To merge input's relocation sections into output's relocation sections. // @@ -2111,12 +2239,11 @@ void GNULDBackend::preLayout(Module& pModule, FragmentLinker& pLinker) } // end of if // set up the section flag of .note.GNU-stack section - setupGNUStackInfo(pModule, pLinker); + setupGNUStackInfo(pModule); } /// postLayout - Backend can do any needed modification after layout -void GNULDBackend::postLayout(Module& pModule, - FragmentLinker& pLinker) +void GNULDBackend::postLayout(Module& pModule, IRBuilder& pBuilder) { // 1. set up section address and segment attributes if (LinkerConfig::Object != config().codeGenType()) { @@ -2126,25 +2253,28 @@ void GNULDBackend::postLayout(Module& pModule, } // 1.2 set up the output sections' address - setOutputSectionAddress(pLinker, pModule, pModule.begin(), pModule.end()); + setOutputSectionAddress(pModule, pModule.begin(), pModule.end()); // 1.3 do relaxation - relax(pModule, pLinker); + relax(pModule, pBuilder); // 1.4 set up the attributes of program headers - setupProgramHdrs(pLinker); + setupProgramHdrs(); } // 2. target specific post layout - doPostLayout(pModule, pLinker); + doPostLayout(pModule, pBuilder); } -void GNULDBackend::postProcessing(FragmentLinker& pLinker, MemoryArea& pOutput) +void GNULDBackend::postProcessing(MemoryArea& pOutput) { - if (config().options().hasEhFrameHdr() && getOutputFormat()->hasEhFrame()) { + if (LinkerConfig::Object != config().codeGenType() && + config().options().hasEhFrameHdr() && getOutputFormat()->hasEhFrame()) { // emit eh_frame_hdr if (config().targets().is32Bits()) m_pEhFrameHdr->emitOutput<32>(pOutput); + else + m_pEhFrameHdr->emitOutput<64>(pOutput); } } @@ -2174,6 +2304,27 @@ unsigned GNULDBackend::getHashBucketCount(unsigned pNumOfSymbols, return result; } +/// getGNUHashMaskbitslog2 - calculate the number of mask bits in log2 +/// @ref binutils gold, dynobj.cc:1165 +unsigned GNULDBackend::getGNUHashMaskbitslog2(unsigned pNumOfSymbols) const +{ + uint32_t maskbitslog2 = 1; + for (uint32_t x = pNumOfSymbols >> 1; x != 0; x >>=1) + ++maskbitslog2; + + if (maskbitslog2 < 3) + maskbitslog2 = 5; + else if (((1U << (maskbitslog2 - 2)) & pNumOfSymbols) != 0) + maskbitslog2 += 3; + else + maskbitslog2 += 2; + + if (config().targets().bitclass() == 64 && maskbitslog2 == 5) + maskbitslog2 = 6; + + return maskbitslog2; +} + /// isDynamicSymbol /// @ref Google gold linker: symtab.cc:311 bool GNULDBackend::isDynamicSymbol(const LDSymbol& pSymbol) @@ -2189,10 +2340,8 @@ bool GNULDBackend::isDynamicSymbol(const LDSymbol& pSymbol) LinkerConfig::Exec == config().codeGenType() || LinkerConfig::Binary == config().codeGenType()) { if (pSymbol.resolveInfo()->visibility() == ResolveInfo::Default || - pSymbol.resolveInfo()->visibility() == ResolveInfo::Protected || - pSymbol.resolveInfo()->type() == ResolveInfo::ThreadLocal) { + pSymbol.resolveInfo()->visibility() == ResolveInfo::Protected) return true; - } } return false; } @@ -2212,10 +2361,8 @@ bool GNULDBackend::isDynamicSymbol(const ResolveInfo& pResolveInfo) LinkerConfig::Exec == config().codeGenType() || LinkerConfig::Binary == config().codeGenType()) { if (pResolveInfo.visibility() == ResolveInfo::Default || - pResolveInfo.visibility() == ResolveInfo::Protected || - pResolveInfo.type() == ResolveInfo::ThreadLocal) { + pResolveInfo.visibility() == ResolveInfo::Protected) return true; - } } return false; } @@ -2227,7 +2374,7 @@ uint64_t GNULDBackend::commonPageSize() const if (config().options().commPageSize() > 0) return std::min(config().options().commPageSize(), abiPageSize()); else - return std::min(static_cast<uint64_t>(0x1000), abiPageSize()); + return std::min(m_pInfo->commonPageSize(), abiPageSize()); } /// abiPageSize - the abi page size of the target machine. @@ -2237,7 +2384,7 @@ uint64_t GNULDBackend::abiPageSize() const if (config().options().maxPageSize() > 0) return config().options().maxPageSize(); else - return static_cast<uint64_t>(0x1000); + return m_pInfo->abiPageSize(); } /// isSymbolPreemtible - whether the symbol can be preemted by other @@ -2271,8 +2418,7 @@ bool GNULDBackend::isSymbolPreemptible(const ResolveInfo& pSym) const /// symbolNeedsDynRel - return whether the symbol needs a dynamic relocation /// @ref Google gold linker, symtab.h:645 -bool GNULDBackend::symbolNeedsDynRel(const FragmentLinker& pLinker, - const ResolveInfo& pSym, +bool GNULDBackend::symbolNeedsDynRel(const ResolveInfo& pSym, bool pSymHasPLT, bool isAbsReloc) const { @@ -2284,13 +2430,17 @@ bool GNULDBackend::symbolNeedsDynRel(const FragmentLinker& pLinker, LinkerConfig::Binary == config().codeGenType())) return false; - if (pSym.isAbsolute()) + // An absolute symbol can be resolved directly if it is either local + // or we are linking statically. Otherwise it can still be overridden + // at runtime. + if (pSym.isAbsolute() && + (pSym.binding() == ResolveInfo::Local || config().isCodeStatic())) return false; - if (pLinker.isOutputPIC() && isAbsReloc) + if (config().isCodeIndep() && isAbsReloc) return true; if (pSymHasPLT && ResolveInfo::Function == pSym.type()) return false; - if (!pLinker.isOutputPIC() && pSymHasPLT) + if (!config().isCodeIndep() && pSymHasPLT) return false; if (pSym.isDyn() || pSym.isUndef() || isSymbolPreemptible(pSym)) @@ -2301,8 +2451,7 @@ bool GNULDBackend::symbolNeedsDynRel(const FragmentLinker& pLinker, /// symbolNeedsPLT - return whether the symbol needs a PLT entry /// @ref Google gold linker, symtab.h:596 -bool GNULDBackend::symbolNeedsPLT(const FragmentLinker& pLinker, - const ResolveInfo& pSym) const +bool GNULDBackend::symbolNeedsPLT(const ResolveInfo& pSym) const { if (pSym.isUndef() && !pSym.isDyn() && @@ -2316,7 +2465,7 @@ bool GNULDBackend::symbolNeedsPLT(const FragmentLinker& pLinker, if (pSym.type() != ResolveInfo::Function) return false; - if (pLinker.isStaticLink() && !pLinker.isOutputPIC()) + if (config().isCodeStatic()) return false; if (config().options().isPIE()) @@ -2330,12 +2479,12 @@ bool GNULDBackend::symbolNeedsPLT(const FragmentLinker& pLinker, /// symbolHasFinalValue - return true if the symbol's value can be decided at /// link time /// @ref Google gold linker, Symbol::final_value_is_known -bool GNULDBackend::symbolFinalValueIsKnown(const FragmentLinker& pLinker, - const ResolveInfo& pSym) const +bool GNULDBackend::symbolFinalValueIsKnown(const ResolveInfo& pSym) const { // if the output is pic code or if not executables, symbols' value may change // at runtime - if (pLinker.isOutputPIC() || + // FIXME: CodeIndep() || LinkerConfig::Relocatable == CodeGenType + if (config().isCodeIndep() || (LinkerConfig::Exec != config().codeGenType() && LinkerConfig::Binary != config().codeGenType())) return false; @@ -2352,17 +2501,16 @@ bool GNULDBackend::symbolFinalValueIsKnown(const FragmentLinker& pLinker, // if the symbol is undefined and not in dynamic objects, for example, a weak // undefined symbol, then whether the symbol's final value can be known // depends on whrther we're doing static link - return pLinker.isStaticLink(); + return config().isCodeStatic(); } /// symbolNeedsCopyReloc - return whether the symbol needs a copy relocation -bool GNULDBackend::symbolNeedsCopyReloc(const FragmentLinker& pLinker, - const Relocation& pReloc, +bool GNULDBackend::symbolNeedsCopyReloc(const Relocation& pReloc, const ResolveInfo& pSym) const { // only the reference from dynamic executable to non-function symbol in // the dynamic objects may need copy relocation - if (pLinker.isOutputPIC() || + if (config().isCodeIndep() || !pSym.isDyn() || pSym.type() == ResolveInfo::Function || pSym.size() == 0) @@ -2437,14 +2585,14 @@ bool GNULDBackend::initStubFactory() return true; } -bool GNULDBackend::relax(Module& pModule, FragmentLinker& pLinker) +bool GNULDBackend::relax(Module& pModule, IRBuilder& pBuilder) { if (!mayRelax()) return true; bool finished = true; do { - if (doRelax(pModule, pLinker, finished)) { + if (doRelax(pModule, pBuilder, finished)) { // If the sections (e.g., .text) are relaxed, the layout is also changed // We need to do the following: @@ -2456,10 +2604,24 @@ bool GNULDBackend::relax(Module& pModule, FragmentLinker& pLinker) setupRelro(pModule); // 3. set up the output sections' address - setOutputSectionAddress(pLinker, pModule, pModule.begin(), pModule.end()); + setOutputSectionAddress(pModule, pModule.begin(), pModule.end()); } } while (!finished); return true; } +bool GNULDBackend::DynsymCompare::needGNUHash(const LDSymbol& X) const +{ + // FIXME: in bfd and gold linker, an undefined symbol might be hashed + // when the ouput is not PIC, if the symbol is referred by a non pc-relative + // reloc, and its value is set to the addr of the plt entry. + return !X.resolveInfo()->isUndef() && !X.isDyn(); +} + +bool GNULDBackend::DynsymCompare::operator()(const LDSymbol* X, + const LDSymbol* Y) const +{ + return !needGNUHash(*X) && needGNUHash(*Y); +} + diff --git a/lib/Target/Hexagon/Hexagon.h b/lib/Target/Hexagon/Hexagon.h new file mode 100644 index 0000000..5a286ef --- /dev/null +++ b/lib/Target/Hexagon/Hexagon.h @@ -0,0 +1,32 @@ +//===- Hexagon.h ----------------------------------------------------------===// +// +// The MCLinker Project +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#ifndef MCLD_HEXAGON_H +#define MCLD_HEXAGON_H +#include <string> +#include <mcld/Target/TargetMachine.h> + +namespace llvm { + +class Target; + +} // namespace of llvm + +namespace mcld { + +class TargetLDBackend; + +extern mcld::Target TheHexagonTarget; + +TargetLDBackend* +createHexagonLDBackend(const llvm::Target&, const std::string&); + +} // namespace of mcld + +#endif + diff --git a/lib/Target/Hexagon/HexagonDiagnostic.cpp b/lib/Target/Hexagon/HexagonDiagnostic.cpp new file mode 100644 index 0000000..01b8f9b --- /dev/null +++ b/lib/Target/Hexagon/HexagonDiagnostic.cpp @@ -0,0 +1,37 @@ +//===- HexagonDiagnostic.cpp ----------------------------------------------===// +// +// The MCLinker Project +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#include <llvm/ADT/Triple.h> +#include <mcld/Support/TargetRegistry.h> +#include <mcld/LD/DWARFLineInfo.h> +#include "Hexagon.h" + +using namespace mcld; + +namespace mcld { + +// createHexagonDiagnostic - the help function to create corresponding +// HexagonDiagnostic +// +DiagnosticLineInfo* +createHexagonDiagLineInfo(const Target& pTarget, const std::string &pTriple) +{ + return new DWARFLineInfo(); +} + +} // namespace of mcld + +//===----------------------------------------------------------------------===// +// InitializeHexagonDiagnostic +//===----------------------------------------------------------------------===// +extern "C" void MCLDInitializeHexagonDiagnosticLineInfo() { + // Register the linker frontend + mcld::TargetRegistry::RegisterDiagnosticLineInfo(TheHexagonTarget, + createHexagonDiagLineInfo); +} + diff --git a/lib/Target/Hexagon/HexagonELFDynamic.cpp b/lib/Target/Hexagon/HexagonELFDynamic.cpp new file mode 100644 index 0000000..96d0946 --- /dev/null +++ b/lib/Target/Hexagon/HexagonELFDynamic.cpp @@ -0,0 +1,37 @@ +//===- HexagonELFDynamic.cpp ----------------------------------------------===// +// +// The MCLinker Project +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#include "HexagonELFDynamic.h" + +#include <mcld/LD/ELFFileFormat.h> + +using namespace mcld; + +HexagonELFDynamic::HexagonELFDynamic(const GNULDBackend& pParent, + const LinkerConfig& pConfig) + : ELFDynamic(pParent, pConfig) { +} + +HexagonELFDynamic::~HexagonELFDynamic() +{ +} + +void HexagonELFDynamic::reserveTargetEntries(const ELFFileFormat& pFormat) +{ + // reservePLTGOT + if (pFormat.hasGOTPLT()) + reserveOne(llvm::ELF::DT_PLTGOT); +} + +void HexagonELFDynamic::applyTargetEntries(const ELFFileFormat& pFormat) +{ + // applyPLTGOT + if (pFormat.hasGOTPLT()) + applyOne(llvm::ELF::DT_PLTGOT, pFormat.getGOTPLT().addr()); +} + diff --git a/lib/Target/Hexagon/HexagonELFDynamic.h b/lib/Target/Hexagon/HexagonELFDynamic.h new file mode 100644 index 0000000..423d918 --- /dev/null +++ b/lib/Target/Hexagon/HexagonELFDynamic.h @@ -0,0 +1,32 @@ +//===- HexagonELFDynamic.h ------------------------------------------------===// +// +// The MCLinker Project +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#ifndef MCLD_HEXAGON_ELFDYNAMIC_SECTION_H +#define MCLD_HEXAGON_ELFDYNAMIC_SECTION_H +#ifdef ENABLE_UNITTEST +#include <gtest.h> +#endif + +#include <mcld/Target/ELFDynamic.h> + +namespace mcld { + +class HexagonELFDynamic : public ELFDynamic +{ +public: + HexagonELFDynamic(const GNULDBackend& pParent, const LinkerConfig& pConfig); + ~HexagonELFDynamic(); + +private: + void reserveTargetEntries(const ELFFileFormat& pFormat); + void applyTargetEntries(const ELFFileFormat& pFormat); +}; + +} // namespace of mcld + +#endif diff --git a/lib/Target/Hexagon/HexagonELFMCLinker.cpp b/lib/Target/Hexagon/HexagonELFMCLinker.cpp new file mode 100644 index 0000000..6cc4a01 --- /dev/null +++ b/lib/Target/Hexagon/HexagonELFMCLinker.cpp @@ -0,0 +1,23 @@ +//===- HexagonELFMCLinker.cpp ---------------------------------------------===// +// +// The MCLinker Project +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#include "HexagonELFMCLinker.h" +#include <mcld/LinkerConfig.h> + +using namespace mcld; + +HexagonELFMCLinker::HexagonELFMCLinker(LinkerConfig& pConfig, + mcld::Module& pModule, + MemoryArea& pOutput) + : ELFMCLinker(pConfig, pModule, pOutput) { +} + +HexagonELFMCLinker::~HexagonELFMCLinker() +{ +} + diff --git a/lib/Target/Hexagon/HexagonELFMCLinker.h b/lib/Target/Hexagon/HexagonELFMCLinker.h new file mode 100644 index 0000000..c588ddf --- /dev/null +++ b/lib/Target/Hexagon/HexagonELFMCLinker.h @@ -0,0 +1,38 @@ +//===- HexagonELFMCLinker.h -----------------------------------------------===// +// +// The MCLinker Project +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#ifndef HEXAGON_ELFSECTLINKER_H +#define HEXAGON_ELFSECTLINKER_H +#ifdef ENABLE_UNITTEST +#include <gtest.h> +#endif +#include <mcld/Target/ELFMCLinker.h> + +namespace mcld { + +class Module; +class MemoryArea; + +/** \class HexagonELFMCLinker + * \brief HexagonELFMCLinker sets up the environment for linking. + * + * \see + */ +class HexagonELFMCLinker : public ELFMCLinker +{ +public: + HexagonELFMCLinker(LinkerConfig& pConfig, + mcld::Module& pModule, + MemoryArea& pOutput); + + ~HexagonELFMCLinker(); +}; + +} // namespace of mcld + +#endif diff --git a/lib/Target/Hexagon/HexagonEmulation.cpp b/lib/Target/Hexagon/HexagonEmulation.cpp new file mode 100644 index 0000000..3b8ee0d --- /dev/null +++ b/lib/Target/Hexagon/HexagonEmulation.cpp @@ -0,0 +1,65 @@ +//===- HexagonEmulation.cpp -----------------------------------------------===// +// +// The MCLinker Project +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#include "Hexagon.h" +#include <mcld/LinkerConfig.h> +#include <mcld/Target/ELFEmulation.h> +#include <mcld/Support/TargetRegistry.h> + +namespace mcld { + +static bool MCLDEmulateHexagonELF(LinkerConfig& pConfig) +{ + if (!MCLDEmulateELF(pConfig)) + return false; + + // set up bitclass and endian + pConfig.targets().setEndian(TargetOptions::Little); + pConfig.targets().setBitClass(32); + + // set up target-dependent constraints of attributes + pConfig.attribute().constraint().enableWholeArchive(); + pConfig.attribute().constraint().enableAsNeeded(); + pConfig.attribute().constraint().setSharedSystem(); + + // set up the predefined attributes + pConfig.attribute().predefined().unsetWholeArchive(); + pConfig.attribute().predefined().unsetAsNeeded(); + pConfig.attribute().predefined().setDynamic(); + return true; +} + +//===----------------------------------------------------------------------===// +// emulateHexagonLD - the help function to emulate Hexagon ld +//===----------------------------------------------------------------------===// +bool emulateHexagonLD(const std::string& pTriple, LinkerConfig& pConfig) +{ + llvm::Triple theTriple(pTriple); + if (theTriple.isOSDarwin()) { + assert(0 && "MachO linker has not supported yet"); + return false; + } + if (theTriple.isOSWindows()) { + assert(0 && "COFF linker has not supported yet"); + return false; + } + + return MCLDEmulateHexagonELF(pConfig); +} + +} // namespace of mcld + +//===----------------------------------------------------------------------===// +// HexagonEmulation +//===----------------------------------------------------------------------===// +extern "C" void MCLDInitializeHexagonEmulation() { + // Register the emulation + mcld::TargetRegistry::RegisterEmulation(mcld::TheHexagonTarget, + mcld::emulateHexagonLD); +} + diff --git a/lib/Target/Hexagon/HexagonGNUInfo.h b/lib/Target/Hexagon/HexagonGNUInfo.h new file mode 100644 index 0000000..082e2e5 --- /dev/null +++ b/lib/Target/Hexagon/HexagonGNUInfo.h @@ -0,0 +1,33 @@ +//===- HexagonGNUInfo.h ---------------------------------------------------===// +// +// The MCLinker Project +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#ifndef MCLD_TARGET_HEXAGON_GNU_INFO_H +#define MCLD_TARGET_HEXAGON_GNU_INFO_H +#include <mcld/Target/GNUInfo.h> + +#include <llvm/Support/ELF.h> + +namespace mcld { + +class HexagonGNUInfo : public GNUInfo +{ +public: + HexagonGNUInfo(const llvm::Triple& pTriple) : GNUInfo(pTriple) { } + + uint32_t machine() const { return llvm::ELF::EM_HEXAGON; } + + uint64_t defaultTextSegmentAddr() const { return 0x0; } + + /// flags - the value of ElfXX_Ehdr::e_flags + uint64_t flags() const { return 0x2; } +}; + +} // namespace of mcld + +#endif + diff --git a/lib/Target/Hexagon/HexagonGOT.cpp b/lib/Target/Hexagon/HexagonGOT.cpp new file mode 100644 index 0000000..551b40f --- /dev/null +++ b/lib/Target/Hexagon/HexagonGOT.cpp @@ -0,0 +1,48 @@ +//===- HexagonGOT.cpp -----------------------------------------------------===// +// +// The MCLinker Project +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#include "HexagonGOT.h" + +#include <mcld/LD/LDFileFormat.h> +#include <mcld/LD/SectionData.h> + +#include <llvm/Support/Casting.h> + +using namespace mcld; + +//===----------------------------------------------------------------------===// +// HexagonGOT +//===----------------------------------------------------------------------===// +HexagonGOT::HexagonGOT(LDSection& pSection) + : GOT(pSection), m_pLast(NULL) +{ +} + +HexagonGOT::~HexagonGOT() +{ +} + +void HexagonGOT::reserve(size_t pNum) +{ + for (size_t i = 0; i < pNum; i++) { + new HexagonGOTEntry(0, m_SectionData); + } +} + +HexagonGOTEntry* HexagonGOT::consume() +{ + if (NULL == m_pLast) { + assert(!empty() && "Consume empty GOT entry!"); + m_pLast = llvm::cast<HexagonGOTEntry>(&m_SectionData->front()); + return m_pLast; + } + + m_pLast = llvm::cast<HexagonGOTEntry>(m_pLast->getNextNode()); + return m_pLast; +} + diff --git a/lib/Target/Hexagon/HexagonGOT.h b/lib/Target/Hexagon/HexagonGOT.h new file mode 100644 index 0000000..4f9120c --- /dev/null +++ b/lib/Target/Hexagon/HexagonGOT.h @@ -0,0 +1,55 @@ +//===- HexagonGOT.h -------------------------------------------------------===// +// +// The MCLinker Project +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#ifndef MCLD_TARGET_HEXAGON_GOT_H +#define MCLD_TARGET_HEXAGON_GOT_H +#ifdef ENABLE_UNITTEST +#include <gtest.h> +#endif + +#include <mcld/Target/GOT.h> + +namespace mcld { + +class LDSection; +class SectionData; + +/** \class HexagonGOTEntry + * \brief GOT Entry with size of 4 bytes + */ +class HexagonGOTEntry : public GOT::Entry<4> +{ +public: + HexagonGOTEntry(uint64_t pContent, SectionData* pParent) + : GOT::Entry<4>(pContent, pParent) + {} +}; + +/** \class HexagonGOT + * \brief Hexagon Global Offset Table. + */ + +class HexagonGOT : public GOT +{ +public: + HexagonGOT(LDSection& pSection); + + ~HexagonGOT(); + + void reserve(size_t pNum = 1); + + HexagonGOTEntry* consume(); + +private: + HexagonGOTEntry* m_pLast; ///< the last consumed entry +}; + +} // namespace of mcld + +#endif + diff --git a/lib/Target/Hexagon/HexagonLDBackend.cpp b/lib/Target/Hexagon/HexagonLDBackend.cpp new file mode 100644 index 0000000..0d7ba26 --- /dev/null +++ b/lib/Target/Hexagon/HexagonLDBackend.cpp @@ -0,0 +1,270 @@ +//===- HexagonLDBackend.cpp -----------------------------------------------===// +// +// The MCLinker Project +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#include "Hexagon.h" +#include "HexagonELFDynamic.h" +#include "HexagonLDBackend.h" +#include "HexagonRelocator.h" +#include "HexagonGNUInfo.h" + +#include <llvm/ADT/Triple.h> +#include <llvm/Support/Casting.h> + +#include <mcld/LinkerConfig.h> +#include <mcld/IRBuilder.h> +#include <mcld/Fragment/FillFragment.h> +#include <mcld/Fragment/RegionFragment.h> +#include <mcld/Support/MemoryRegion.h> +#include <mcld/Support/MsgHandling.h> +#include <mcld/Support/TargetRegistry.h> +#include <mcld/Object/ObjectBuilder.h> + +#include <cstring> + +using namespace mcld; + +//===----------------------------------------------------------------------===// +// HexagonLDBackend +//===----------------------------------------------------------------------===// +HexagonLDBackend::HexagonLDBackend(const LinkerConfig& pConfig, + HexagonGNUInfo* pInfo) + : GNULDBackend(pConfig, pInfo), + m_pRelocator(NULL), + m_pGOT(NULL), + m_pPLT(NULL), + m_pRelDyn(NULL), + m_pRelPLT(NULL), + m_pDynamic(NULL), + m_pGOTSymbol(NULL) { +} + +HexagonLDBackend::~HexagonLDBackend() +{ + delete m_pRelocator; + delete m_pGOT; + delete m_pPLT; + delete m_pRelDyn; + delete m_pRelPLT; + delete m_pDynamic; +} + +bool HexagonLDBackend::initRelocator() +{ + if (NULL == m_pRelocator) { + m_pRelocator = new HexagonRelocator(*this); + } + return true; +} + +Relocator* HexagonLDBackend::getRelocator() +{ + assert(NULL != m_pRelocator); + return m_pRelocator; +} + +void HexagonLDBackend::doPreLayout(IRBuilder& pBuilder) +{ + // initialize .dynamic data + if (!config().isCodeStatic() && NULL == m_pDynamic) + m_pDynamic = new HexagonELFDynamic(*this, config()); +} + +void HexagonLDBackend::doPostLayout(Module& pModule, IRBuilder& pBuilder) +{ +} + +/// dynamic - the dynamic section of the target machine. +/// Use co-variant return type to return its own dynamic section. +HexagonELFDynamic& HexagonLDBackend::dynamic() +{ + assert(NULL != m_pDynamic); + return *m_pDynamic; +} + +/// dynamic - the dynamic section of the target machine. +/// Use co-variant return type to return its own dynamic section. +const HexagonELFDynamic& HexagonLDBackend::dynamic() const +{ + assert(NULL != m_pDynamic); + return *m_pDynamic; +} + +void HexagonLDBackend::scanRelocation(Relocation& pReloc, + IRBuilder& pBuilder, + Module& pModule, + LDSection& pSection) +{ + pReloc.updateAddend(); +} + +uint64_t HexagonLDBackend::emitSectionData(const LDSection& pSection, + MemoryRegion& pRegion) const +{ + return 0; +} + +HexagonGOT& HexagonLDBackend::getGOT() +{ + assert(NULL != m_pGOT); + return *m_pGOT; +} + +const HexagonGOT& HexagonLDBackend::getGOT() const +{ + assert(NULL != m_pGOT); + return *m_pGOT; +} + +HexagonPLT& HexagonLDBackend::getPLT() +{ + assert(NULL != m_pPLT && "PLT section not exist"); + return *m_pPLT; +} + +const HexagonPLT& HexagonLDBackend::getPLT() const +{ + assert(NULL != m_pPLT && "PLT section not exist"); + return *m_pPLT; +} + +OutputRelocSection& HexagonLDBackend::getRelDyn() +{ + assert(NULL != m_pRelDyn && ".rel.dyn section not exist"); + return *m_pRelDyn; +} + +const OutputRelocSection& HexagonLDBackend::getRelDyn() const +{ + assert(NULL != m_pRelDyn && ".rel.dyn section not exist"); + return *m_pRelDyn; +} + +OutputRelocSection& HexagonLDBackend::getRelPLT() +{ + assert(NULL != m_pRelPLT && ".rel.plt section not exist"); + return *m_pRelPLT; +} + +const OutputRelocSection& HexagonLDBackend::getRelPLT() const +{ + assert(NULL != m_pRelPLT && ".rel.plt section not exist"); + return *m_pRelPLT; +} + +unsigned int +HexagonLDBackend::getTargetSectionOrder(const LDSection& pSectHdr) const +{ + const ELFFileFormat* file_format = getOutputFormat(); + + if (&pSectHdr == &file_format->getGOT()) { + if (config().options().hasNow()) + return SHO_RELRO; + return SHO_RELRO_LAST; + } + + if (&pSectHdr == &file_format->getPLT()) + return SHO_PLT; + + return SHO_UNDEFINED; +} + +void HexagonLDBackend::initTargetSections(Module& pModule, + ObjectBuilder& pBuilder) +{ + if (LinkerConfig::Object != config().codeGenType()) { + ELFFileFormat* file_format = getOutputFormat(); + // initialize .got + LDSection& got = file_format->getGOT(); + m_pGOT = new HexagonGOT(got); + + // initialize .plt + LDSection& plt = file_format->getPLT(); + m_pPLT = new HexagonPLT(plt, + *m_pGOT, + config()); + + // initialize .rel.plt + LDSection& relplt = file_format->getRelPlt(); + relplt.setLink(&plt); + m_pRelPLT = new OutputRelocSection(pModule, relplt); + + // initialize .rel.dyn + LDSection& reldyn = file_format->getRelDyn(); + m_pRelDyn = new OutputRelocSection(pModule, reldyn); + + } +} + +void HexagonLDBackend::initTargetSymbols(IRBuilder& pBuilder, Module& pModule) +{ + if (LinkerConfig::Object != config().codeGenType()) { + // Define the symbol _GLOBAL_OFFSET_TABLE_ if there is a symbol with the + // same name in input + m_pGOTSymbol = pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>( + "_GLOBAL_OFFSET_TABLE_", + ResolveInfo::Object, + ResolveInfo::Define, + ResolveInfo::Local, + 0x0, // size + 0x0, // value + FragmentRef::Null(), + ResolveInfo::Hidden); + } +} + +/// finalizeSymbol - finalize the symbol value +bool HexagonLDBackend::finalizeTargetSymbols() +{ + return true; +} + +/// doCreateProgramHdrs - backend can implement this function to create the +/// target-dependent segments +void HexagonLDBackend::doCreateProgramHdrs(Module& pModule) +{ + // TODO +} + +namespace mcld { + +//===----------------------------------------------------------------------===// +/// createHexagonLDBackend - the help funtion to create corresponding +/// HexagonLDBackend +TargetLDBackend* createHexagonLDBackend(const llvm::Target& pTarget, + const LinkerConfig& pConfig) +{ + if (pConfig.targets().triple().isOSDarwin()) { + assert(0 && "MachO linker is not supported yet"); + /** + return new HexagonMachOLDBackend(createHexagonMachOArchiveReader, + createHexagonMachOObjectReader, + createHexagonMachOObjectWriter); + **/ + } + if (pConfig.targets().triple().isOSWindows()) { + assert(0 && "COFF linker is not supported yet"); + /** + return new HexagonCOFFLDBackend(createHexagonCOFFArchiveReader, + createHexagonCOFFObjectReader, + createHexagonCOFFObjectWriter); + **/ + } + return new HexagonLDBackend(pConfig, + new HexagonGNUInfo(pConfig.targets().triple())); +} + +} // namespace of mcld + +//===----------------------------------------------------------------------===// +// Force static initialization. +//===----------------------------------------------------------------------===// +extern "C" void MCLDInitializeHexagonLDBackend() { + // Register the linker backend + mcld::TargetRegistry::RegisterTargetLDBackend(TheHexagonTarget, + createHexagonLDBackend); +} diff --git a/lib/Target/Hexagon/HexagonLDBackend.h b/lib/Target/Hexagon/HexagonLDBackend.h new file mode 100644 index 0000000..46da924 --- /dev/null +++ b/lib/Target/Hexagon/HexagonLDBackend.h @@ -0,0 +1,149 @@ +//===- HexagonLDBackend.h -------------------------------------------------===// +// +// The MCLinker Project +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#ifndef HEXAGON_LDBACKEND_H +#define HEXAGON_LDBACKEND_H + +#include "HexagonELFDynamic.h" +#include "HexagonGOT.h" +#include "HexagonPLT.h" +#include <mcld/LD/LDSection.h> +#include <mcld/Target/GNULDBackend.h> +#include <mcld/Target/OutputRelocSection.h> + +namespace mcld { + +class LinkerConfig; +class HexagonGNUInfo; + +//===----------------------------------------------------------------------===// +/// HexagonLDBackend - linker backend of Hexagon target of GNU ELF format +/// +class HexagonLDBackend : public GNULDBackend +{ +public: + HexagonLDBackend(const LinkerConfig& pConfig, HexagonGNUInfo* pInfo); + + ~HexagonLDBackend(); + + uint32_t machine() const; + + HexagonGOT& getGOT(); + + const HexagonGOT& getGOT() const; + + HexagonPLT& getPLT(); + + const HexagonPLT& getPLT() const; + + /// preLayout - Backend can do any needed modification before layout + void doPreLayout(IRBuilder& pBuilder); + + /// postLayout - Backend can do any needed modification after layout + void doPostLayout(Module& pModule, IRBuilder& pBuilder); + + /// dynamic - the dynamic section of the target machine. + /// Use co-variant return type to return its own dynamic section. + HexagonELFDynamic& dynamic(); + + /// dynamic - the dynamic section of the target machine. + /// Use co-variant return type to return its own dynamic section. + const HexagonELFDynamic& dynamic() const; + + /// emitSectionData - write out the section data into the memory region. + /// When writers get a LDSection whose kind is LDFileFormat::Target, writers + /// call back target backend to emit the data. + /// + /// Backends handle the target-special tables (plt, gp,...) by themselves. + /// Backend can put the data of the tables in MCSectionData directly + /// - LDSection.getSectionData can get the section data. + /// Or, backend can put the data into special data structure + /// - backend can maintain its own map<LDSection, table> to get the table + /// from given LDSection. + /// + /// @param pSection - the given LDSection + /// @param pLayout - for comouting the size of fragment + /// @param pRegion - the region to write out data + /// @return the size of the table in the file. + uint64_t emitSectionData(const LDSection& pSection, + MemoryRegion& pRegion) const; + + /// initRelocator - create and initialize Relocator. + bool initRelocator(); + + /// getRelocator - return relocator. + Relocator* getRelocator(); + + ResolveInfo::Desc getSymDesc(uint16_t shndx) const + { + if (shndx >= llvm::ELF::SHN_HEXAGON_SCOMMON && + shndx <= llvm::ELF::SHN_HEXAGON_SCOMMON_8) + return ResolveInfo::Common; + return ResolveInfo::NoneDesc; + } + + void initTargetSections(Module& pModule, ObjectBuilder& pBuilder); + + void initTargetSymbols(IRBuilder& pBuilder, Module& pModule); + + /// scanRelocation - determine the empty entries are needed or not and create + /// the empty entries if needed. + /// For Hexagon, following entries are check to create: + /// - GOT entry (for .got and .got.plt sections) + /// - PLT entry (for .plt section) + /// - dynamin relocation entries (for .rel.plt and .rel.dyn sections) + void scanRelocation(Relocation& pReloc, + IRBuilder& pBuilder, + Module& pModule, + LDSection& pSection); + + OutputRelocSection& getRelDyn(); + + const OutputRelocSection& getRelDyn() const; + + OutputRelocSection& getRelPLT(); + + const OutputRelocSection& getRelPLT() const; + + /// getTargetSectionOrder - compute the layout order of Hexagon target section + unsigned int getTargetSectionOrder(const LDSection& pSectHdr) const; + + /// finalizeTargetSymbols - finalize the symbol value + bool finalizeTargetSymbols(); + +private: + + /// getRelEntrySize - the size in BYTE of rel type relocation + size_t getRelEntrySize() + { return 8; } + + /// getRelEntrySize - the size in BYTE of rela type relocation + size_t getRelaEntrySize() + { return 12; } + + /// doCreateProgramHdrs - backend can implement this function to create the + /// target-dependent segments + void doCreateProgramHdrs(Module& pModule); + +private: + Relocator* m_pRelocator; + HexagonGOT* m_pGOT; + HexagonPLT* m_pPLT; + /// m_RelDyn - dynamic relocation table of .rel.dyn + OutputRelocSection* m_pRelDyn; + /// m_RelPLT - dynamic relocation table of .rel.plt + OutputRelocSection* m_pRelPLT; + + HexagonELFDynamic* m_pDynamic; + LDSymbol* m_pGOTSymbol; + LDSymbol* m_pBSSEnd; +}; +} // namespace of mcld + +#endif + diff --git a/lib/Target/Hexagon/HexagonMCLinker.cpp b/lib/Target/Hexagon/HexagonMCLinker.cpp new file mode 100644 index 0000000..4f4f839 --- /dev/null +++ b/lib/Target/Hexagon/HexagonMCLinker.cpp @@ -0,0 +1,53 @@ +//===- HexagonMCLinker.cpp ------------------------------------------------===// +// +// The MCLinker Project +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#include "Hexagon.h" +#include "HexagonELFMCLinker.h" +#include <mcld/Module.h> +#include <mcld/Support/TargetRegistry.h> +#include <llvm/ADT/Triple.h> + +using namespace mcld; + +namespace mcld { + +/// createHexagonMCLinker - the help funtion to create corresponding +/// HexagonMCLinker +MCLinker* createHexagonMCLinker(const std::string &pTriple, + LinkerConfig& pConfig, + mcld::Module& pModule, + MemoryArea& pOutput) +{ + Triple theTriple(pTriple); + if (theTriple.isOSDarwin()) { + assert(0 && "MachO linker has not supported yet"); + return NULL; + } + if (theTriple.isOSWindows()) { + assert(0 && "COFF linker has not supported yet"); + return NULL; + } + + if (theTriple.isArch32Bit()) + return new HexagonELFMCLinker(pConfig, pModule, pOutput); + + assert(0 && "Hexagon_64 has not supported yet"); + return NULL; +} + +} // namespace of mcld + +//===----------------------------------------------------------------------===// +// HexagonMCLinker +//===----------------------------------------------------------------------===// +extern "C" void MCLDInitializeHexagonMCLinker() { + // Register the linker frontend + mcld::TargetRegistry::RegisterMCLinker(TheHexagonTarget, + createHexagonMCLinker); +} + diff --git a/lib/Target/Hexagon/HexagonPLT.cpp b/lib/Target/Hexagon/HexagonPLT.cpp new file mode 100644 index 0000000..ae39af2 --- /dev/null +++ b/lib/Target/Hexagon/HexagonPLT.cpp @@ -0,0 +1,97 @@ +//===- HexagonPLT.cpp -----------------------------------------------------===// +// +// The MCLinker Project +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#include "HexagonPLT.h" + +#include <llvm/Support/ELF.h> +#include <llvm/Support/Casting.h> + +#include <mcld/LD/LDSection.h> +#include <mcld/LinkerConfig.h> +#include <mcld/Support/MsgHandling.h> + +using namespace mcld; + +//===----------------------------------------------------------------------===// +// PLT entry data +//===----------------------------------------------------------------------===// +HexagonDynPLT0::HexagonDynPLT0(SectionData& pParent) + : PLT::Entry<sizeof(hexagon_dyn_plt0)>(pParent) +{ +} + +HexagonExecPLT0::HexagonExecPLT0(SectionData& pParent) + : PLT::Entry<sizeof(hexagon_exec_plt0)>(pParent) +{ +} + +//===----------------------------------------------------------------------===// +// HexagonPLT +//===----------------------------------------------------------------------===// +HexagonPLT::HexagonPLT(LDSection& pSection, + HexagonGOT &pGOTPLT, + const LinkerConfig& pConfig) + : PLT(pSection), + m_GOT(pGOTPLT), + m_Config(pConfig) +{ + assert(LinkerConfig::DynObj == m_Config.codeGenType() || + LinkerConfig::Exec == m_Config.codeGenType() || + LinkerConfig::Binary == m_Config.codeGenType()); + + if (LinkerConfig::DynObj == m_Config.codeGenType()) { + m_PLT0 = hexagon_dyn_plt0; + m_PLT0Size = sizeof (hexagon_dyn_plt0); + // create PLT0 + new HexagonDynPLT0(*m_SectionData); + } + else { + m_PLT0 = hexagon_exec_plt0; + m_PLT0Size = sizeof (hexagon_exec_plt0); + // create PLT0 + new HexagonExecPLT0(*m_SectionData); + } + m_Last = m_SectionData->begin(); +} + +HexagonPLT::~HexagonPLT() +{ +} + +PLTEntryBase* HexagonPLT::getPLT0() const +{ + iterator first = m_SectionData->getFragmentList().begin(); + + assert(first != m_SectionData->getFragmentList().end() && + "FragmentList is empty, getPLT0 failed!"); + + PLTEntryBase* plt0 = &(llvm::cast<PLTEntryBase>(*first)); + + return plt0; +} + +void HexagonPLT::finalizeSectionSize() +{ + uint64_t size = 0; + // plt0 size + size = getPLT0()->size(); + + m_Section.setSize(size); + + uint32_t offset = 0; + SectionData::iterator frag, fragEnd = m_SectionData->end(); + for (frag = m_SectionData->begin(); frag != fragEnd; ++frag) { + frag->setOffset(offset); + offset += frag->size(); + } +} + +void HexagonPLT::reserveEntry(size_t pNum) +{ +} + diff --git a/lib/Target/Hexagon/HexagonPLT.h b/lib/Target/Hexagon/HexagonPLT.h new file mode 100644 index 0000000..a5743d4 --- /dev/null +++ b/lib/Target/Hexagon/HexagonPLT.h @@ -0,0 +1,84 @@ +//===- HexagonPLT.h -------------------------------------------------------===// +// +// The MCLinker Project +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#ifndef MCLD_TARGET_HEXAGON_PLT_H +#define MCLD_TARGET_HEXAGON_PLT_H + +#include "HexagonGOT.h" +#include <mcld/Target/PLT.h> + +namespace { + +const uint8_t hexagon_dyn_plt0[] = { + 0 +}; + +const uint8_t hexagon_exec_plt0[] = { + 0 +}; + +} // anonymous namespace + +namespace mcld { + +class GOTEntry; +class LinkerConfig; + +//===----------------------------------------------------------------------===// +// HexagonPLT Entry +//===----------------------------------------------------------------------===// +class HexagonDynPLT0 : public PLT::Entry<sizeof(hexagon_dyn_plt0)> +{ +public: + HexagonDynPLT0(SectionData& pParent); +}; + +class HexagonExecPLT0 : public PLT::Entry<sizeof(hexagon_exec_plt0)> +{ +public: + HexagonExecPLT0(SectionData& pParent); +}; + +//===----------------------------------------------------------------------===// +// HexagonPLT +//===----------------------------------------------------------------------===// +/** \class HexagonPLT + * \brief Hexagon Procedure Linkage Table + */ +class HexagonPLT : public PLT +{ +public: + HexagonPLT(LDSection& pSection, + HexagonGOT& pGOTPLT, + const LinkerConfig& pConfig); + ~HexagonPLT(); + + // finalizeSectionSize - set LDSection size + void finalizeSectionSize(); + + void reserveEntry(size_t pNum = 1) ; + +private: + PLTEntryBase* getPLT0() const; + +private: + HexagonGOT& m_GOT; + + // the last consumed entry. + SectionData::iterator m_Last; + + const uint8_t *m_PLT0; + unsigned int m_PLT0Size; + + const LinkerConfig& m_Config; +}; + +} // namespace of mcld + +#endif + diff --git a/lib/Target/Hexagon/HexagonRelocationFunctions.h b/lib/Target/Hexagon/HexagonRelocationFunctions.h new file mode 100644 index 0000000..c854dcb --- /dev/null +++ b/lib/Target/Hexagon/HexagonRelocationFunctions.h @@ -0,0 +1,113 @@ +//===- HexagonRelocationFunction.h ----------------------------------------===// +// +// The MCLinker Project +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#define DECL_HEXAGON_APPLY_RELOC_FUNC(Name) \ +static HexagonRelocator::Result Name (Relocation& pEntry, \ + HexagonRelocator& pParent); + +#define DECL_HEXAGON_APPLY_RELOC_FUNCS \ +DECL_HEXAGON_APPLY_RELOC_FUNC(none) \ +DECL_HEXAGON_APPLY_RELOC_FUNC(relocB22PCREL) \ +DECL_HEXAGON_APPLY_RELOC_FUNC(relocB15PCREL) \ +DECL_HEXAGON_APPLY_RELOC_FUNC(relocLO16) \ +DECL_HEXAGON_APPLY_RELOC_FUNC(relocHI16) \ +DECL_HEXAGON_APPLY_RELOC_FUNC(reloc32) \ +DECL_HEXAGON_APPLY_RELOC_FUNC(reloc16) \ +DECL_HEXAGON_APPLY_RELOC_FUNC(reloc8) \ +DECL_HEXAGON_APPLY_RELOC_FUNC(relocB13PCREL) \ +DECL_HEXAGON_APPLY_RELOC_FUNC(reloc32PCREL) \ +DECL_HEXAGON_APPLY_RELOC_FUNC(unsupport) + + +#define DECL_HEXAGON_APPLY_RELOC_FUNC_PTRS \ + { &none, 0, "R_HEX_NONE" }, \ + { &relocB22PCREL, 1, "R_HEX_B22_PCREL" }, \ + { &relocB15PCREL, 2, "R_HEX_B15_PCREL" }, \ + { &unsupport, 3, "R_HEX_B7_PCREL" }, \ + { &relocLO16, 4, "R_HEX_LO16" }, \ + { &relocHI16, 5, "R_HEX_HI16" }, \ + { &reloc32, 6, "R_HEX_32" }, \ + { &reloc16, 7, "R_HEX_16" }, \ + { &reloc8, 8, "R_HEX_8" }, \ + { &unsupport, 9, "R_HEX_GPREL16_0" }, \ + { &unsupport, 10, "R_HEX_GPREL16_1" }, \ + { &unsupport, 11, "R_HEX_GPREL16_2" }, \ + { &unsupport, 12, "R_HEX_GPREL16_3" }, \ + { &unsupport, 13, "R_HEX_HL16" }, \ + { &relocB13PCREL, 14, "R_HEX_B13_PCREL" }, \ + { &unsupport, 15, "R_HEX_B9_PCREL" }, \ + { &unsupport, 16, "R_HEX_B32_PCREL_X" }, \ + { &unsupport, 17, "R_HEX_32_6_X" }, \ + { &unsupport, 18, "R_HEX_B22_PCREL_X" }, \ + { &unsupport, 19, "R_HEX_B15_PCREL_X" }, \ + { &unsupport, 20, "R_HEX_B13_PCREL_X" }, \ + { &unsupport, 21, "R_HEX_B9_PCREL_X" }, \ + { &unsupport, 22, "R_HEX_B7_PCREL_X" }, \ + { &unsupport, 23, "R_HEX_16_X" }, \ + { &unsupport, 24, "R_HEX_12_X" }, \ + { &unsupport, 25, "R_HEX_11_X" }, \ + { &unsupport, 26, "R_HEX_10_X" }, \ + { &unsupport, 27, "R_HEX_9_X" }, \ + { &unsupport, 28, "R_HEX_8_X" }, \ + { &unsupport, 29, "R_HEX_7_X" }, \ + { &unsupport, 30, "R_HEX_6_X" }, \ + { &reloc32PCREL, 31, "R_HEX_32_PCREL" }, \ + { &unsupport, 32, "R_HEX_COPY" }, \ + { &unsupport, 33, "R_HEX_GLOB_DAT" }, \ + { &unsupport, 34, "R_HEX_JMP_SLOT" }, \ + { &unsupport, 35, "R_HEX_RELATIVE" }, \ + { &unsupport, 36, "R_HEX_PLT_B22_PCREL" }, \ + { &unsupport, 37, "R_HEX_GOTREL_LO16" }, \ + { &unsupport, 38, "R_HEX_GOTREL_HI16" }, \ + { &unsupport, 39, "R_HEX_GOTREL_32" }, \ + { &unsupport, 40, "R_HEX_GOT_LO16" }, \ + { &unsupport, 41, "R_HEX_GOT_HI16" }, \ + { &unsupport, 42, "R_HEX_GOT_32" }, \ + { &unsupport, 43, "R_HEX_GOT_16" }, \ + { &unsupport, 44, "R_HEX_DTPMOD_32" }, \ + { &unsupport, 45, "R_HEX_DTPREL_LO16" }, \ + { &unsupport, 46, "R_HEX_DTPREL_HI16" }, \ + { &unsupport, 47, "R_HEX_DTPREL_32" }, \ + { &unsupport, 48, "R_HEX_DTPREL_16" }, \ + { &unsupport, 49, "R_HEX_GD_PLT_B22_PCREL" }, \ + { &unsupport, 50, "R_HEX_GD_GOT_LO16" }, \ + { &unsupport, 51, "R_HEX_GD_GOT_HI16" }, \ + { &unsupport, 52, "R_HEX_GD_GOT_32" }, \ + { &unsupport, 53, "R_HEX_GD_GOT_16" }, \ + { &unsupport, 54, "R_HEX_IE_LO16" }, \ + { &unsupport, 55, "R_HEX_IE_HI16" }, \ + { &unsupport, 56, "R_HEX_IE_32" }, \ + { &unsupport, 57, "R_HEX_IE_GOT_LO16" }, \ + { &unsupport, 58, "R_HEX_IE_GOT_HI16" }, \ + { &unsupport, 59, "R_HEX_IE_GOT_32" }, \ + { &unsupport, 60, "R_HEX_IE_GOT_16" }, \ + { &unsupport, 61, "R_HEX_TPREL_LO16" }, \ + { &unsupport, 62, "R_HEX_TPREL_HI16" }, \ + { &unsupport, 63, "R_HEX_TPREL_32" }, \ + { &unsupport, 64, "R_HEX_TPREL_16" }, \ + { &unsupport, 65, "R_HEX_6_PCREL_X" }, \ + { &unsupport, 66, "R_HEX_GOTREL_32_6_X" }, \ + { &unsupport, 67, "R_HEX_GOTREL_16_X" }, \ + { &unsupport, 68, "R_HEX_GOTREL_11_X" }, \ + { &unsupport, 69, "R_HEX_GOT_32_6_X" }, \ + { &unsupport, 70, "R_HEX_GOT_16_X" }, \ + { &unsupport, 71, "R_HEX_GOT_11_X" }, \ + { &unsupport, 72, "R_HEX_DTPREL_32_6_X" }, \ + { &unsupport, 73, "R_HEX_DTPREL_16_X" }, \ + { &unsupport, 74, "R_HEX_DTPREL_11_X" }, \ + { &unsupport, 75, "R_HEX_GD_GOT_32_6_X" }, \ + { &unsupport, 76, "R_HEX_GD_GOT_16_X" }, \ + { &unsupport, 77, "R_HEX_GD_GOT_11_X" }, \ + { &unsupport, 78, "R_HEX_IE_32_6_X" }, \ + { &unsupport, 79, "R_HEX_IE_16_X" }, \ + { &unsupport, 80, "R_HEX_IE_GOT_32_6_X" }, \ + { &unsupport, 81, "R_HEX_IE_GOT_16_X" }, \ + { &unsupport, 82, "R_HEX_IE_GOT_11_X" }, \ + { &unsupport, 83, "R_HEX_TPREL_32_6_X" }, \ + { &unsupport, 84, "R_HEX_TPREL_16_X" }, \ + { &unsupport, 85, "R_HEX_TPREL_11_X" } diff --git a/lib/Target/Hexagon/HexagonRelocator.cpp b/lib/Target/Hexagon/HexagonRelocator.cpp new file mode 100644 index 0000000..1bfa2b0 --- /dev/null +++ b/lib/Target/Hexagon/HexagonRelocator.cpp @@ -0,0 +1,259 @@ +//===- HexagonRelocator.cpp -----------------------------------------------===// +// +// The MCLinker Project +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include <llvm/ADT/Twine.h> +#include <llvm/Support/DataTypes.h> +#include <llvm/Support/ELF.h> +#include <mcld/Support/MsgHandling.h> + +#include "HexagonRelocator.h" +#include "HexagonRelocationFunctions.h" + +using namespace mcld; + +//===--------------------------------------------------------------------===// +// Relocation Functions and Tables +//===--------------------------------------------------------------------===// +DECL_HEXAGON_APPLY_RELOC_FUNCS + +/// the prototype of applying function +typedef Relocator::Result (*ApplyFunctionType)(Relocation& pReloc, + HexagonRelocator& pParent); + +// the table entry of applying functions +struct ApplyFunctionTriple +{ + ApplyFunctionType func; + unsigned int type; + const char* name; +}; + +// declare the table of applying functions +static const ApplyFunctionTriple ApplyFunctions[] = { + DECL_HEXAGON_APPLY_RELOC_FUNC_PTRS +}; + +//===--------------------------------------------------------------------===// +// HexagonRelocator +//===--------------------------------------------------------------------===// +HexagonRelocator::HexagonRelocator(HexagonLDBackend& pParent) + : Relocator(), + m_Target(pParent) { +} + +HexagonRelocator::~HexagonRelocator() +{ +} + +Relocator::Result +HexagonRelocator::applyRelocation(Relocation& pRelocation) +{ + Relocation::Type type = pRelocation.type(); + + if (type > 85) { // 86-255 relocs do not exists for Hexagon + return Relocator::Unknown; + } + + // apply the relocation + return ApplyFunctions[type].func(pRelocation, *this); +} + +const char* HexagonRelocator::getName(Relocation::Type pType) const +{ + return ApplyFunctions[pType].name; +} + +Relocator::Size HexagonRelocator::getSize(Relocation::Type pType) const +{ + return 32; +} +//===--------------------------------------------------------------------===// +// Relocation helper function +//===--------------------------------------------------------------------===// +template<typename T1, typename T2> +T1 ApplyMask(T2 pMask, T1 pData) { + T1 result = 0; + size_t off = 0; + + for (size_t bit = 0; bit != sizeof (T1) * 8; ++bit) { + const bool valBit = (pData >> off) & 1; + const bool maskBit = (pMask >> bit) & 1; + if (maskBit) { + result |= static_cast<T1>(valBit) << bit; + ++off; + } + } + return result; +} + +//=========================================// +// Each relocation function implementation // +//=========================================// + +// R_HEX_NONE +HexagonRelocator::Result none(Relocation& pReloc, HexagonRelocator& pParent) +{ + return HexagonRelocator::OK; +} + +// R_HEX_B22_PCREL: Word32_B22 : 0x01ff3ffe (S + A - P) >> 2 : Signed Verify +HexagonRelocator::Result relocB22PCREL(Relocation& pReloc, + HexagonRelocator& pParent) +{ + HexagonRelocator::Address S = pReloc.symValue(); + HexagonRelocator::DWord A = pReloc.addend(); + HexagonRelocator::DWord P = pReloc.place(); + + int32_t result = (int32_t) ((S + A - P) >> 2); + int32_t range = 1 << 21; + + if ( (result < range) && (result > -range)) { + pReloc.target() = pReloc.target() | ApplyMask(0x01ff3ffe, result); + return HexagonRelocator::OK; + } + return HexagonRelocator::Overflow; +} + +// R_HEX_B15_PCREL: Word32_B15 : 0x00df20fe (S + A - P) >> 2 : Signed Verify +HexagonRelocator::Result relocB15PCREL(Relocation& pReloc, + HexagonRelocator& pParent) +{ + HexagonRelocator::Address S = pReloc.symValue(); + HexagonRelocator::DWord A = pReloc.addend(); + HexagonRelocator::DWord P = pReloc.place(); + + int32_t result = (int32_t) ((S + A - P) >> 2); + int32_t range = 1 << 14; + if ( (result < range) && (result > -range)) { + pReloc.target() = pReloc.target() | ApplyMask(0x00df20fe,result); + return HexagonRelocator::OK; + } + return HexagonRelocator::Overflow; +} + +// R_HEX_B7_PCREL: Word32_B7 : 0x0001f18 (S + A - P) >> 2 : Signed Verify +HexagonRelocator::Result relocB7PCREL(Relocation& pReloc, + HexagonRelocator& pParent) +{ + HexagonRelocator::Address S = pReloc.symValue(); + HexagonRelocator::DWord A = pReloc.addend(); + HexagonRelocator::DWord P = pReloc.place(); + + int32_t result = (int32_t) ((S + A - P) >> 2); + int32_t range = 1 << 6; + if ( (result < range) && (result > -range)) { + pReloc.target() = pReloc.target() | ApplyMask(0x00001f18, result); + return HexagonRelocator::OK; + } + return HexagonRelocator::Overflow; +} + +// R_HEX_LO16: Word32_LO : 0x00c03fff (S + A) : Unsigned Truncate +HexagonRelocator::Result relocLO16(Relocation& pReloc, + HexagonRelocator& pParent) +{ + HexagonRelocator::Address S = pReloc.symValue(); + HexagonRelocator::DWord A = pReloc.addend(); + + uint32_t result = (uint32_t) (S + A); + pReloc.target() = pReloc.target() | ApplyMask(0x00c03fff, result); + return HexagonRelocator::OK; +} + +// R_HEX_HI16: Word32_LO : 0x00c03fff (S + A) >> 16 : Unsigned Truncate +HexagonRelocator::Result relocHI16(Relocation& pReloc, + HexagonRelocator& pParent) +{ + HexagonRelocator::Address S = pReloc.symValue(); + HexagonRelocator::DWord A = pReloc.addend(); + + uint32_t result = (uint32_t) ((S + A) >> 16); + pReloc.target() = pReloc.target() | ApplyMask(0x00c03fff, result); + return HexagonRelocator::OK; +} + +// R_HEX_32: Word32 : 0xffffffff : (S + A) : Unsigned Truncate +HexagonRelocator::Result reloc32(Relocation& pReloc, HexagonRelocator& pParent) +{ + HexagonRelocator::DWord A = pReloc.addend(); + HexagonRelocator::DWord S = pReloc.symValue(); + + uint32_t result = (uint32_t) (S + A); + + pReloc.target() = result | pReloc.target(); + return HexagonRelocator::OK; +} + +// R_HEX_16: Word32 : 0xffff : (S + A) : Unsigned Truncate +HexagonRelocator::Result reloc16(Relocation& pReloc, HexagonRelocator& pParent) +{ + HexagonRelocator::DWord A = pReloc.addend(); + HexagonRelocator::DWord S = pReloc.symValue(); + + uint32_t result = (uint32_t) (S + A); + pReloc.target() = pReloc.target() | ApplyMask(0x0000ffff, result); + + return HexagonRelocator::OK; +} + +// R_HEX_8: Word32 : 0xff : (S + A) : Unsigned Truncate +HexagonRelocator::Result reloc8(Relocation& pReloc, HexagonRelocator& pParent) +{ + HexagonRelocator::DWord A = pReloc.addend(); + HexagonRelocator::DWord S = pReloc.symValue(); + + uint32_t result = (uint32_t) (S + A); + pReloc.target() = pReloc.target() | ApplyMask(0x000000ff, result); + + return HexagonRelocator::OK; +} + +// R_HEX_B13_PCREL : Word32_B13 : 0x00202ffe (S + A - P)>>2 : Signed Verify +HexagonRelocator::Result relocB13PCREL(Relocation& pReloc, + HexagonRelocator& pParent) +{ + HexagonRelocator::Address S = pReloc.symValue(); + HexagonRelocator::DWord A = pReloc.addend(); + HexagonRelocator::DWord P = pReloc.place(); + + int32_t result = ((S + A - P) >> 2); + int32_t range = 1L << 12; + if (result < range && result > -range) { + pReloc.target() = pReloc.target() | ApplyMask(0x00202ffe, result); + return HexagonRelocator::OK; + } + return HexagonRelocator::Overflow; +} + +HexagonRelocator::Result unsupport(Relocation& pReloc, + HexagonRelocator& pParent) +{ + return HexagonRelocator::Unsupport; +} + + + +// R_HEX_32_PCREL : Word32 : 0xffffffff (S + A - P) : Signed Verify +HexagonRelocator::Result reloc32PCREL(Relocation& pReloc, + HexagonRelocator& pParent) +{ + HexagonRelocator::Address S = pReloc.symValue(); + HexagonRelocator::DWord A = pReloc.addend(); + HexagonRelocator::DWord P = pReloc.place(); + + int64_t result = S + A - P; + int32_t range = 1 << 31; + + if (result < range && result > -range) { + pReloc.target() = pReloc.target() | ApplyMask(0xffffffff, result); + return HexagonRelocator::OK; + } + + return HexagonRelocator::Overflow; +} diff --git a/lib/Target/Hexagon/HexagonRelocator.h b/lib/Target/Hexagon/HexagonRelocator.h new file mode 100644 index 0000000..b7347ee --- /dev/null +++ b/lib/Target/Hexagon/HexagonRelocator.h @@ -0,0 +1,66 @@ +//===- HexagonRelocator.h ------------------------------------------------===// +// +// The MCLinker Project +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#ifndef HEXAGON_RELOCATION_FACTORY_H +#define HEXAGON_RELOCATION_FACTORY_H +#ifdef ENABLE_UNITTEST +#include <gtest.h> +#endif + +#include <mcld/LD/Relocator.h> +#include <mcld/Target/GOT.h> +#include <mcld/Target/PLT.h> +#include <mcld/Target/SymbolEntryMap.h> +#include "HexagonLDBackend.h" + +namespace mcld { + +class ResolveInfo; + +/** \class HexagonRelocator + * \brief HexagonRelocator creates and destroys the Hexagon relocations. + * + */ +class HexagonRelocator : public Relocator +{ +public: + typedef SymbolEntryMap<PLTEntryBase> SymPLTMap; + typedef SymbolEntryMap<HexagonGOTEntry> SymGOTMap; + +public: + HexagonRelocator(HexagonLDBackend& pParent); + ~HexagonRelocator(); + + Result applyRelocation(Relocation& pRelocation); + + HexagonLDBackend& getTarget() + { return m_Target; } + + const HexagonLDBackend& getTarget() const + { return m_Target; } + + const char* getName(Relocation::Type pType) const; + + Size getSize(Relocation::Type pType) const; + + const SymPLTMap& getSymPLTMap() const { return m_SymPLTMap; } + SymPLTMap& getSymPLTMap() { return m_SymPLTMap; } + + const SymGOTMap& getSymGOTMap() const { return m_SymGOTMap; } + SymGOTMap& getSymGOTMap() { return m_SymGOTMap; } + +private: + HexagonLDBackend& m_Target; + SymPLTMap m_SymPLTMap; + SymGOTMap m_SymGOTMap; +}; + +} // namespace of mcld + +#endif + diff --git a/lib/Target/Hexagon/HexagonTargetMachine.cpp b/lib/Target/Hexagon/HexagonTargetMachine.cpp new file mode 100644 index 0000000..4e4f1c2 --- /dev/null +++ b/lib/Target/Hexagon/HexagonTargetMachine.cpp @@ -0,0 +1,29 @@ +//===- HexagonTargetMachine.cpp -------------------------------------------===// +// +// The MCLinker Project +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#include "HexagonTargetMachine.h" +#include "Hexagon.h" +#include <mcld/Target/TargetMachine.h> +#include <mcld/Support/TargetRegistry.h> + +extern "C" void MCLDInitializeHexagonLDTarget() { + // Register createTargetMachine function pointer to mcld::Target + mcld::RegisterTargetMachine<mcld::HexagonTargetMachine> + X(mcld::TheHexagonTarget); +} + +mcld::HexagonTargetMachine::HexagonTargetMachine(llvm::TargetMachine& pPM, + const mcld::Target &pTarget, + const std::string& pTriple) + : mcld::MCLDTargetMachine(pPM, pTarget, pTriple) { +} + +mcld::HexagonTargetMachine::~HexagonTargetMachine() +{ +} + diff --git a/lib/Target/Hexagon/HexagonTargetMachine.h b/lib/Target/Hexagon/HexagonTargetMachine.h new file mode 100644 index 0000000..a374475 --- /dev/null +++ b/lib/Target/Hexagon/HexagonTargetMachine.h @@ -0,0 +1,28 @@ +//===- HexagonTargetMachine.h ---------------------------------------------===// +// +// The MCLinker Project +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#ifndef MCLD_HEXAGON_TARGET_MACHINE_H +#define MCLD_HEXAGON_TARGET_MACHINE_H +#include "Hexagon.h" +#include <mcld/Target/TargetMachine.h> + +namespace mcld { + +class HexagonTargetMachine : public MCLDTargetMachine +{ +public: + HexagonTargetMachine(llvm::TargetMachine &pTM, + const mcld::Target &pTarget, + const std::string &pTriple); + + virtual ~HexagonTargetMachine(); +}; + +} // namespace of mcld + +#endif diff --git a/lib/Target/Hexagon/TargetInfo/HexagonTargetInfo.cpp b/lib/Target/Hexagon/TargetInfo/HexagonTargetInfo.cpp new file mode 100644 index 0000000..0b113aa --- /dev/null +++ b/lib/Target/Hexagon/TargetInfo/HexagonTargetInfo.cpp @@ -0,0 +1,22 @@ +//===- HexagonTargetInfo.cpp -----------------------------------------------===// +// +// The MCLinker Project +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#include <mcld/Target/TargetMachine.h> +#include <mcld/Support/TargetRegistry.h> + +namespace mcld { + +mcld::Target TheHexagonTarget; + +extern "C" void MCLDInitializeHexagonLDTargetInfo() { + // register into mcld::TargetRegistry + mcld::RegisterTarget X(TheHexagonTarget, "hexagon"); +} + +} // namespace of mcld + diff --git a/lib/Target/Mips/MipsGNUInfo.h b/lib/Target/Mips/MipsGNUInfo.h index 9bbc548..a1d8cd2 100644 --- a/lib/Target/Mips/MipsGNUInfo.h +++ b/lib/Target/Mips/MipsGNUInfo.h @@ -17,10 +17,36 @@ namespace mcld { class MipsGNUInfo : public GNUInfo { public: + enum { + // The original o32 abi. + E_MIPS_ABI_O32 = 0x00001000, + // O32 extended to work on 64 bit architectures. + E_MIPS_ABI_O64 = 0x00002000, + // EABI in 32 bit mode. + E_MIPS_ABI_EABI32 = 0x00003000, + // EABI in 64 bit mode. + E_MIPS_ABI_EABI64 = 0x00004000 + }; + +public: MipsGNUInfo(const llvm::Triple& pTriple) : GNUInfo(pTriple) { } uint32_t machine() const { return llvm::ELF::EM_MIPS; } + uint64_t defaultTextSegmentAddr() const { return 0x80000; } + + uint64_t flags() const + { + // TODO: (simon) The correct flag's set depend on command line + // arguments and flags from input .o files. + return llvm::ELF::EF_MIPS_ARCH_32R2 | + llvm::ELF::EF_MIPS_NOREORDER | + llvm::ELF::EF_MIPS_PIC | + llvm::ELF::EF_MIPS_CPIC | + E_MIPS_ABI_O32; + } + + uint64_t abiPageSize() const { return 0x10000; } }; } // namespace of mcld diff --git a/lib/Target/Mips/MipsLDBackend.cpp b/lib/Target/Mips/MipsLDBackend.cpp index 59b8d18..0806a2a 100644 --- a/lib/Target/Mips/MipsLDBackend.cpp +++ b/lib/Target/Mips/MipsLDBackend.cpp @@ -20,7 +20,6 @@ #include <mcld/IRBuilder.h> #include <mcld/MC/Attribute.h> #include <mcld/Fragment/FillFragment.h> -#include <mcld/Fragment/FragmentLinker.h> #include <mcld/Support/MemoryRegion.h> #include <mcld/Support/MemoryArea.h> #include <mcld/Support/MsgHandling.h> @@ -28,17 +27,6 @@ #include <mcld/Target/OutputRelocSection.h> #include <mcld/Object/ObjectBuilder.h> -enum { - // The original o32 abi. - E_MIPS_ABI_O32 = 0x00001000, - // O32 extended to work on 64 bit architectures. - E_MIPS_ABI_O64 = 0x00002000, - // EABI in 32 bit mode. - E_MIPS_ABI_EABI32 = 0x00003000, - // EABI in 64 bit mode. - E_MIPS_ABI_EABI64 = 0x00004000 -}; - using namespace mcld; //===----------------------------------------------------------------------===// @@ -79,13 +67,12 @@ void MipsGNULDBackend::initTargetSections(Module& pModule, ObjectBuilder& pBuild } } -void MipsGNULDBackend::initTargetSymbols(FragmentLinker& pLinker) +void MipsGNULDBackend::initTargetSymbols(IRBuilder& pBuilder, Module& pModule) { // Define the symbol _GLOBAL_OFFSET_TABLE_ if there is a symbol with the // same name in input - m_pGOTSymbol = pLinker.defineSymbol<FragmentLinker::AsRefered, FragmentLinker::Resolve>( + m_pGOTSymbol = pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>( "_GLOBAL_OFFSET_TABLE_", - false, ResolveInfo::Object, ResolveInfo::Define, ResolveInfo::Local, @@ -94,9 +81,8 @@ void MipsGNULDBackend::initTargetSymbols(FragmentLinker& pLinker) FragmentRef::Null(), // FragRef ResolveInfo::Hidden); - m_pGpDispSymbol = pLinker.defineSymbol<FragmentLinker::AsRefered, FragmentLinker::Resolve>( + m_pGpDispSymbol = pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>( "_gp_disp", - false, ResolveInfo::Section, ResolveInfo::Define, ResolveInfo::Absolute, @@ -110,11 +96,10 @@ void MipsGNULDBackend::initTargetSymbols(FragmentLinker& pLinker) } } -bool MipsGNULDBackend::initRelocator(const FragmentLinker& pLinker) +bool MipsGNULDBackend::initRelocator() { if (NULL == m_pRelocator) { m_pRelocator = new MipsRelocator(*this); - m_pRelocator->setFragmentLinker(pLinker); } return true; } @@ -126,9 +111,9 @@ Relocator* MipsGNULDBackend::getRelocator() } void MipsGNULDBackend::scanRelocation(Relocation& pReloc, - FragmentLinker& pLinker, + IRBuilder& pBuilder, Module& pModule, - const LDSection& pSection) + LDSection& pSection) { // rsym - The relocation target symbol ResolveInfo* rsym = pReloc.symInfo(); @@ -142,7 +127,8 @@ void MipsGNULDBackend::scanRelocation(Relocation& pReloc, pReloc.updateAddend(); - if (0 == (pSection.flag() & llvm::ELF::SHF_ALLOC)) + assert(NULL != pSection.getLink()); + if (0 == (pSection.getLink()->flag() & llvm::ELF::SHF_ALLOC)) return; // We test isLocal or if pInputSym is not a dynamic symbol @@ -150,47 +136,22 @@ void MipsGNULDBackend::scanRelocation(Relocation& pReloc, // Don't put undef symbols into local entries. if ((rsym->isLocal() || !isDynamicSymbol(*rsym) || !rsym->isDyn()) && !rsym->isUndef()) - scanLocalReloc(pReloc, pLinker); + scanLocalReloc(pReloc, pBuilder, pSection); else - scanGlobalReloc(pReloc, pLinker); + scanGlobalReloc(pReloc, pBuilder, pSection); // check if we shoule issue undefined reference for the relocation target // symbol if (rsym->isUndef() && !rsym->isDyn() && !rsym->isWeak() && !rsym->isNull()) fatal(diag::undefined_reference) << rsym->name(); - - if ((rsym->reserved() & ReserveRel) != 0x0) { - // set hasTextRelSection if needed - checkAndSetHasTextRel(pSection); - } -} - -uint64_t MipsGNULDBackend::flags() const -{ - // TODO: (simon) The correct flag's set depend on command line - // arguments and flags from input .o files. - return llvm::ELF::EF_MIPS_ARCH_32R2 | - llvm::ELF::EF_MIPS_NOREORDER | - llvm::ELF::EF_MIPS_PIC | - llvm::ELF::EF_MIPS_CPIC | - E_MIPS_ABI_O32; -} - -uint64_t MipsGNULDBackend::defaultTextSegmentAddr() const -{ - return 0x80000; } -uint64_t MipsGNULDBackend::abiPageSize() const +void MipsGNULDBackend::doPreLayout(IRBuilder& pBuilder) { - if (config().options().maxPageSize() > 0) - return config().options().maxPageSize(); - else - return static_cast<uint64_t>(0x10000); -} + // initialize .dynamic data + if (!config().isCodeStatic() && NULL == m_pDynamic) + m_pDynamic = new MipsELFDynamic(*this, config()); -void MipsGNULDBackend::doPreLayout(FragmentLinker& pLinker) -{ // set .got size // when building shared object, the .got section is must. if (LinkerConfig::Object != config().codeGenType()) { @@ -198,18 +159,21 @@ void MipsGNULDBackend::doPreLayout(FragmentLinker& pLinker) m_pGOT->hasGOT1() || NULL != m_pGOTSymbol) { m_pGOT->finalizeSectionSize(); - defineGOTSymbol(pLinker); + defineGOTSymbol(pBuilder); } ELFFileFormat* file_format = getOutputFormat(); // set .rel.dyn size - if (!m_pRelDyn->empty()) + if (!m_pRelDyn->empty()) { + assert(!config().isCodeStatic() && + "static linkage should not result in a dynamic relocation section"); file_format->getRelDyn().setSize( m_pRelDyn->numOfRelocs() * getRelEntrySize()); + } } } -void MipsGNULDBackend::doPostLayout(Module& pModule, - FragmentLinker& pLinker) + +void MipsGNULDBackend::doPostLayout(Module& pModule, IRBuilder& pBuilder) { } @@ -217,9 +181,7 @@ void MipsGNULDBackend::doPostLayout(Module& pModule, /// Use co-variant return type to return its own dynamic section. MipsELFDynamic& MipsGNULDBackend::dynamic() { - if (NULL == m_pDynamic) - m_pDynamic = new MipsELFDynamic(*this, config()); - + assert(NULL != m_pDynamic); return *m_pDynamic; } @@ -227,7 +189,7 @@ MipsELFDynamic& MipsGNULDBackend::dynamic() /// Use co-variant return type to return its own dynamic section. const MipsELFDynamic& MipsGNULDBackend::dynamic() const { - assert( NULL != m_pDynamic); + assert(NULL != m_pDynamic); return *m_pDynamic; } @@ -260,7 +222,7 @@ bool MipsGNULDBackend::isGlobalGOTSymbol(const LDSymbol& pSymbol) const /// In ELF executable files, regular name pools are .symtab, .strtab, /// .dynsym, .dynstr, .hash and .shstrtab. void -MipsGNULDBackend::sizeNamePools(const Module& pModule, bool pIsStaticLink) +MipsGNULDBackend::sizeNamePools(Module& pModule, bool pIsStaticLink) { // number of entries in symbol tables starts from 1 to hold the special entry // at index 0 (STN_UNDEF). See ELF Spec Book I, p1-21. @@ -275,53 +237,37 @@ MipsGNULDBackend::sizeNamePools(const Module& pModule, bool pIsStaticLink) size_t hash = 0; // number of local symbol in the .dynsym + size_t symtab_local_cnt = 0; size_t dynsym_local_cnt = 0; - /// compute the size of .symtab, .dynsym and .strtab - /// @{ - Module::const_sym_iterator symbol; const Module::SymbolTable& symbols = pModule.getSymbolTable(); - size_t str_size = 0; - // compute the size of symbols in Local and File category - Module::const_sym_iterator symEnd = symbols.localEnd(); - for (symbol = symbols.localBegin(); symbol != symEnd; ++symbol) { - str_size = (*symbol)->nameSize() + 1; - if (!pIsStaticLink && isDynamicSymbol(**symbol)) { - ++dynsym; - if (ResolveInfo::Section != (*symbol)->type() || *symbol == m_pGpDispSymbol) - dynstr += str_size; - } - ++symtab; - if (ResolveInfo::Section != (*symbol)->type() || *symbol == m_pGpDispSymbol) - strtab += str_size; - } - // compute the size of symbols in TLS category - symEnd = symbols.tlsEnd(); - for (symbol = symbols.tlsBegin(); symbol != symEnd; ++symbol) { - str_size = (*symbol)->nameSize() + 1; - if (!pIsStaticLink) { - ++dynsym; - if (ResolveInfo::Section != (*symbol)->type() || *symbol == m_pGpDispSymbol) - dynstr += str_size; - } + Module::const_sym_iterator symbol, symEnd; + /// Compute the size of .symtab, .strtab, and symtab_local_cnt + /// @{ + symEnd = symbols.end(); + for (symbol = symbols.begin(); symbol != symEnd; ++symbol) { ++symtab; - if (ResolveInfo::Section != (*symbol)->type() || *symbol == m_pGpDispSymbol) - strtab += str_size; + if (ResolveInfo::Section != (*symbol)->type() || + *symbol == m_pGpDispSymbol) + strtab += (*symbol)->nameSize() + 1; } - dynsym_local_cnt = dynsym; - // compute the size of the reset of symbols - symEnd = pModule.sym_end(); - for (symbol = symbols.tlsEnd(); symbol != symEnd; ++symbol) { - str_size = (*symbol)->nameSize() + 1; - if (!pIsStaticLink && isDynamicSymbol(**symbol)) { + symtab_local_cnt = 1 + symbols.numOfFiles() + symbols.numOfLocals() + + symbols.numOfLocalDyns(); + /// @} + + /// Compute the size of .dynsym, .dynstr, and dynsym_local_cnt + /// @{ + if (!pIsStaticLink) { + symEnd = symbols.dynamicEnd(); + for (symbol = symbols.localDynBegin(); symbol != symEnd; ++symbol) { ++dynsym; - if (ResolveInfo::Section != (*symbol)->type() || *symbol == m_pGpDispSymbol) - dynstr += str_size; + if (ResolveInfo::Section != (*symbol)->type() || + *symbol == m_pGpDispSymbol) + dynstr += (*symbol)->nameSize() + 1; } - ++symtab; - if (ResolveInfo::Section != (*symbol)->type() || *symbol == m_pGpDispSymbol) - strtab += str_size; + dynsym_local_cnt = 1 + symbols.numOfLocalDyns(); } + /// @} ELFFileFormat* file_format = getOutputFormat(); @@ -357,6 +303,15 @@ MipsGNULDBackend::sizeNamePools(const Module& pModule, bool pIsStaticLink) } } + if (!config().options().getRpathList().empty()) { + dynamic().reserveNeedEntry(); + GeneralOptions::const_rpath_iterator rpath, + rpathEnd = config().options().rpath_end(); + for (rpath = config().options().rpath_begin(); + rpath != rpathEnd; ++rpath) + dynstr += (*rpath).size() + 1; + } + // compute .hash // Both Elf32_Word and Elf64_Word are 4 bytes hash = (2 + getHashBucketCount(dynsym, false) + dynsym) * @@ -385,7 +340,7 @@ MipsGNULDBackend::sizeNamePools(const Module& pModule, bool pIsStaticLink) // set .symtab sh_info to one greater than the symbol table // index of the last local symbol - file_format->getSymTab().setInfo(symbols.numOfLocals() + 1); + file_format->getSymTab().setInfo(symtab_local_cnt); break; } default: { @@ -449,8 +404,7 @@ void MipsGNULDBackend::emitSymbol32(llvm::ELF::Elf32_Sym& pSym, /// /// the size of these tables should be computed before layout /// layout should computes the start offset of these tables -void MipsGNULDBackend::emitDynNamePools(const Module& pModule, - MemoryArea& pOutput) +void MipsGNULDBackend::emitDynNamePools(Module& pModule, MemoryArea& pOutput) { ELFFileFormat* file_format = getOutputFormat(); if (!file_format->hasDynSymTab() || @@ -498,61 +452,14 @@ void MipsGNULDBackend::emitDynNamePools(const Module& pModule, size_t symtabIdx = 1; size_t strtabsize = 1; - // emit of .dynsym, and .dynstr except GOT entries - Module::const_sym_iterator symbol; + // emit .dynsym, and .dynstr (emit LocalDyn and Dynamic category) except GOT + // entries const Module::SymbolTable& symbols = pModule.getSymbolTable(); - // emit symbol in File and Local category if it's dynamic symbol - Module::const_sym_iterator symEnd = symbols.localEnd(); - for (symbol = symbols.localBegin(); symbol != symEnd; ++symbol) { - if (!isDynamicSymbol(**symbol)) - continue; - + Module::const_sym_iterator symbol, symEnd = symbols.dynamicEnd(); + for (symbol = symbols.localDynBegin(); symbol != symEnd; ++symbol) { if (isGlobalGOTSymbol(**symbol)) continue; - - emitSymbol32(symtab32[symtabIdx], **symbol, strtab, strtabsize, - symtabIdx); - - // maintain output's symbol and index map - entry = m_pSymIndexMap->insert(*symbol, sym_exist); - entry->setValue(symtabIdx); - // sum up counters - ++symtabIdx; - if (ResolveInfo::Section != (*symbol)->type() || *symbol == m_pGpDispSymbol) - strtabsize += (*symbol)->nameSize() + 1; - } - - // emit symbols in TLS category, all symbols in TLS category shold be emitited - // directly, except GOT entries - symEnd = symbols.tlsEnd(); - for (symbol = symbols.tlsBegin(); symbol != symEnd; ++symbol) { - if (isGlobalGOTSymbol(**symbol)) - continue; - - emitSymbol32(symtab32[symtabIdx], **symbol, strtab, strtabsize, - symtabIdx); - - // maintain output's symbol and index map - entry = m_pSymIndexMap->insert(*symbol, sym_exist); - entry->setValue(symtabIdx); - // sum up counters - ++symtabIdx; - if (ResolveInfo::Section != (*symbol)->type() || *symbol == m_pGpDispSymbol) - strtabsize += (*symbol)->nameSize() + 1; - } - - // emit the reset of the symbols if the symbol is dynamic symbol - symEnd = pModule.sym_end(); - for (symbol = symbols.tlsEnd(); symbol != symEnd; ++symbol) { - if (!isDynamicSymbol(**symbol)) - continue; - - if (isGlobalGOTSymbol(**symbol)) - continue; - - emitSymbol32(symtab32[symtabIdx], **symbol, strtab, strtabsize, - symtabIdx); - + emitSymbol32(symtab32[symtabIdx], **symbol, strtab, strtabsize, symtabIdx); // maintain output's symbol and index map entry = m_pSymIndexMap->insert(*symbol, sym_exist); entry->setValue(symtabIdx); @@ -566,22 +473,19 @@ void MipsGNULDBackend::emitDynNamePools(const Module& pModule, for (std::vector<LDSymbol*>::const_iterator symbol = m_GlobalGOTSyms.begin(), symbol_end = m_GlobalGOTSyms.end(); symbol != symbol_end; ++symbol) { - // Make sure this golbal GOT entry is a dynamic symbol. // If not, something is wrong earlier when putting this symbol into // global GOT. if (!isDynamicSymbol(**symbol)) fatal(diag::mips_got_symbol) << (*symbol)->name(); - emitSymbol32(symtab32[symtabIdx], **symbol, strtab, strtabsize, - symtabIdx); + emitSymbol32(symtab32[symtabIdx], **symbol, strtab, strtabsize, symtabIdx); // maintain output's symbol and index map entry = m_pSymIndexMap->insert(*symbol, sym_exist); entry->setValue(symtabIdx); - // sum up counters ++symtabIdx; - if (ResolveInfo::Section != (*symbol)->type()) + if (ResolveInfo::Section != (*symbol)->type() || *symbol == m_pGpDispSymbol) strtabsize += (*symbol)->nameSize() + 1; } @@ -614,6 +518,19 @@ void MipsGNULDBackend::emitDynNamePools(const Module& pModule, } // for // emit soname + + if (!config().options().getRpathList().empty()) { + (*dt_need)->setValue(llvm::ELF::DT_RPATH, strtabsize); + ++dt_need; + GeneralOptions::const_rpath_iterator rpath, + rpathEnd = config().options().rpath_end(); + for (rpath = config().options().rpath_begin(); rpath != rpathEnd; ++rpath) { + memcpy((strtab + strtabsize), (*rpath).data(), (*rpath).size()); + strtabsize += (*rpath).size(); + strtab[strtabsize++] = (rpath + 1 == rpathEnd ? '\0' : ':'); + } + } + // initialize value of ELF .dynamic section if (LinkerConfig::DynObj == config().codeGenType()) dynamic().applySoname(strtabsize); @@ -689,7 +606,7 @@ MipsGNULDBackend::getTargetSectionOrder(const LDSection& pSectHdr) const } /// finalizeSymbol - finalize the symbol value -bool MipsGNULDBackend::finalizeTargetSymbols(FragmentLinker& pLinker) +bool MipsGNULDBackend::finalizeTargetSymbols() { if (NULL != m_pGpDispSymbol) m_pGpDispSymbol->setValue(m_pGOT->addr() + 0x7FF0); @@ -704,7 +621,8 @@ bool MipsGNULDBackend::allocateCommonSymbols(Module& pModule) { SymbolCategory& symbol_list = pModule.getSymbolTable(); - if (symbol_list.emptyCommons() && symbol_list.emptyLocals()) + if (symbol_list.emptyCommons() && symbol_list.emptyFiles() && + symbol_list.emptyLocals() && symbol_list.emptyLocalDyns()) return true; SymbolCategory::iterator com_sym, com_end; @@ -796,7 +714,8 @@ bool MipsGNULDBackend::allocateCommonSymbols(Module& pModule) } void MipsGNULDBackend::scanLocalReloc(Relocation& pReloc, - FragmentLinker& pLinker) + IRBuilder& pBuilder, + const LDSection& pSection) { ResolveInfo* rsym = pReloc.symInfo(); @@ -812,6 +731,7 @@ void MipsGNULDBackend::scanLocalReloc(Relocation& pReloc, // 2. Check this condition here. m_pRelDyn->reserveEntry(); rsym->setReserved(rsym->reserved() | ReserveRel); + checkAndSetHasTextRel(*pSection.getLink()); // Remeber this rsym is a local GOT entry (as if it needs an entry). // Actually we don't allocate an GOT entry. @@ -846,6 +766,10 @@ void MipsGNULDBackend::scanLocalReloc(Relocation& pReloc, break; case llvm::ELF::R_MIPS_GOT16: case llvm::ELF::R_MIPS_CALL16: + case llvm::ELF::R_MIPS_GOT_HI16: + case llvm::ELF::R_MIPS_CALL_HI16: + case llvm::ELF::R_MIPS_GOT_LO16: + case llvm::ELF::R_MIPS_CALL_LO16: // For got16 section based relocations, we need to reserve got entries. if (rsym->type() == ResolveInfo::Section) { m_pGOT->reserveLocalEntry(); @@ -864,12 +788,7 @@ void MipsGNULDBackend::scanLocalReloc(Relocation& pReloc, case llvm::ELF::R_MIPS_GPREL32: case llvm::ELF::R_MIPS_GPREL16: case llvm::ELF::R_MIPS_LITERAL: - break; case llvm::ELF::R_MIPS_GOT_DISP: - case llvm::ELF::R_MIPS_GOT_HI16: - case llvm::ELF::R_MIPS_CALL_HI16: - case llvm::ELF::R_MIPS_GOT_LO16: - case llvm::ELF::R_MIPS_CALL_LO16: break; case llvm::ELF::R_MIPS_TLS_DTPMOD32: case llvm::ELF::R_MIPS_TLS_DTPREL32: @@ -892,7 +811,8 @@ void MipsGNULDBackend::scanLocalReloc(Relocation& pReloc, } void MipsGNULDBackend::scanGlobalReloc(Relocation& pReloc, - FragmentLinker& pLinker) + IRBuilder& pBuilder, + const LDSection& pSection) { ResolveInfo* rsym = pReloc.symInfo(); @@ -913,9 +833,10 @@ void MipsGNULDBackend::scanGlobalReloc(Relocation& pReloc, case llvm::ELF::R_MIPS_64: case llvm::ELF::R_MIPS_HI16: case llvm::ELF::R_MIPS_LO16: - if (symbolNeedsDynRel(pLinker, *rsym, false, true)) { + if (symbolNeedsDynRel(*rsym, false, true)) { m_pRelDyn->reserveEntry(); rsym->setReserved(rsym->reserved() | ReserveRel); + checkAndSetHasTextRel(*pSection.getLink()); // Remeber this rsym is a global GOT entry (as if it needs an entry). // Actually we don't allocate an GOT entry. @@ -982,13 +903,12 @@ void MipsGNULDBackend::scanGlobalReloc(Relocation& pReloc, } } -void MipsGNULDBackend::defineGOTSymbol(FragmentLinker& pLinker) +void MipsGNULDBackend::defineGOTSymbol(IRBuilder& pBuilder) { // define symbol _GLOBAL_OFFSET_TABLE_ if ( m_pGOTSymbol != NULL ) { - pLinker.defineSymbol<FragmentLinker::Force, FragmentLinker::Unresolve>( + pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Unresolve>( "_GLOBAL_OFFSET_TABLE_", - false, ResolveInfo::Object, ResolveInfo::Define, ResolveInfo::Local, @@ -998,9 +918,8 @@ void MipsGNULDBackend::defineGOTSymbol(FragmentLinker& pLinker) ResolveInfo::Hidden); } else { - m_pGOTSymbol = pLinker.defineSymbol<FragmentLinker::Force, FragmentLinker::Resolve>( + m_pGOTSymbol = pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Resolve>( "_GLOBAL_OFFSET_TABLE_", - false, ResolveInfo::Object, ResolveInfo::Define, ResolveInfo::Local, @@ -1013,8 +932,7 @@ void MipsGNULDBackend::defineGOTSymbol(FragmentLinker& pLinker) /// doCreateProgramHdrs - backend can implement this function to create the /// target-dependent segments -void MipsGNULDBackend::doCreateProgramHdrs(Module& pModule, - const FragmentLinker& pLinker) +void MipsGNULDBackend::doCreateProgramHdrs(Module& pModule) { // TODO } diff --git a/lib/Target/Mips/MipsLDBackend.h b/lib/Target/Mips/MipsLDBackend.h index b9db410..1933751 100644 --- a/lib/Target/Mips/MipsLDBackend.h +++ b/lib/Target/Mips/MipsLDBackend.h @@ -15,7 +15,6 @@ namespace mcld { class LinkerConfig; -class FragmentLinker; class OutputRelocSection; class SectionMap; class MemoryArea; @@ -43,10 +42,10 @@ public: void initTargetSections(Module& pModule, ObjectBuilder& pBuilder); /// initTargetSymbols - initialize target dependent symbols in output. - void initTargetSymbols(FragmentLinker& pLinker); + void initTargetSymbols(IRBuilder& pBuilder, Module& pModule); /// initRelocator - create and initialize Relocator. - bool initRelocator(const FragmentLinker& pLinker); + bool initRelocator(); /// getRelocator - return relocator. Relocator* getRelocator(); @@ -55,23 +54,15 @@ public: /// create the empty entries if needed. /// For Mips, the GOT, GP, and dynamic relocation entries are check to create. void scanRelocation(Relocation& pReloc, - FragmentLinker& pLinker, + IRBuilder& pBuilder, Module& pModule, - const LDSection& pSection); - - /// flags - the value of ElfXX_Ehdr::e_flags - uint64_t flags() const; - - uint64_t defaultTextSegmentAddr() const; - - /// abiPageSize - the abi page size of the target machine - uint64_t abiPageSize() const; + LDSection& pSection); /// preLayout - Backend can do any needed modification before layout - void doPreLayout(FragmentLinker& pLinker); + void doPreLayout(IRBuilder& pBuilder); - /// postLayout -Backend can do any needed modification after layout - void doPostLayout(Module& pModule, FragmentLinker& pLinker); + /// postLayout - Backend can do any needed modification after layout + void doPostLayout(Module& pModule, IRBuilder& pBuilder); /// dynamic - the dynamic section of the target machine. /// Use co-variant return type to return its own dynamic section. @@ -98,10 +89,10 @@ public: uint64_t emitSectionData(const LDSection& pSection, MemoryRegion& pRegion) const; - void sizeNamePools(const Module& pModule, bool pIsStaticLink); + void sizeNamePools(Module& pModule, bool pIsStaticLink); /// emitNamePools - emit dynamic name pools - .dyntab, .dynstr, .hash - void emitDynNamePools(const Module& pModule, MemoryArea& pOut); + void emitDynNamePools(Module& pModule, MemoryArea& pOut); MipsGOT& getGOT(); @@ -114,18 +105,22 @@ public: unsigned int getTargetSectionOrder(const LDSection& pSectHdr) const; /// finalizeSymbol - finalize the symbol value - bool finalizeTargetSymbols(FragmentLinker& pLinker); + bool finalizeTargetSymbols(); /// allocateCommonSymbols - allocate common symbols in the corresponding /// sections. bool allocateCommonSymbols(Module& pModule); private: - void scanLocalReloc(Relocation& pReloc, FragmentLinker& pLinker); + void scanLocalReloc(Relocation& pReloc, + IRBuilder& pBuilder, + const LDSection& pSection); - void scanGlobalReloc(Relocation& pReloc, FragmentLinker& pLinker); + void scanGlobalReloc(Relocation& pReloc, + IRBuilder& pBuilder, + const LDSection& pSection); - void defineGOTSymbol(FragmentLinker& pLinker); + void defineGOTSymbol(IRBuilder& pBuilder); /// emitSymbol32 - emit an ELF32 symbol, override parent's function void emitSymbol32(llvm::ELF::Elf32_Sym& pSym32, @@ -144,8 +139,7 @@ private: /// doCreateProgramHdrs - backend can implement this function to create the /// target-dependent segments - virtual void doCreateProgramHdrs(Module& pModule, - const FragmentLinker& pLinker); + void doCreateProgramHdrs(Module& pModule); private: Relocator* m_pRelocator; diff --git a/lib/Target/Mips/MipsRelocationFunctions.h b/lib/Target/Mips/MipsRelocationFunctions.h index aad708e..f1461a0 100644 --- a/lib/Target/Mips/MipsRelocationFunctions.h +++ b/lib/Target/Mips/MipsRelocationFunctions.h @@ -23,55 +23,55 @@ DECL_MIPS_APPLY_RELOC_FUNC(gothi16) \ DECL_MIPS_APPLY_RELOC_FUNC(gotlo16) #define DECL_MIPS_APPLY_RELOC_FUNC_PTRS \ - { &none, 0, "R_MIPS_NONE" }, \ - { &none, 1, "R_MIPS_16" }, \ - { &abs32, 2, "R_MIPS_32" }, \ - { &none, 3, "R_MIPS_REL32" }, \ - { &none, 4, "R_MIPS_26" }, \ - { &hi16, 5, "R_MIPS_HI16" }, \ - { &lo16, 6, "R_MIPS_LO16" }, \ - { &none, 7, "R_MIPS_GPREL16" }, \ - { &none, 8, "R_MIPS_LITERAL" }, \ - { &got16, 9, "R_MIPS_GOT16" }, \ - { &none, 10, "R_MIPS_PC16" }, \ - { &call16, 11, "R_MIPS_CALL16" }, \ - { &gprel32, 12, "R_MIPS_GPREL32" }, \ - { &none, 13, "R_MIPS_UNUSED1" }, \ - { &none, 14, "R_MIPS_UNUSED2" }, \ - { &none, 15, "R_MIPS_UNUSED3" }, \ - { &none, 16, "R_MIPS_SHIFT5" }, \ - { &none, 17, "R_MIPS_SHIFT6" }, \ - { &none, 18, "R_MIPS_64" }, \ - { &none, 19, "R_MIPS_GOT_DISP" }, \ - { &none, 20, "R_MIPS_GOT_PAGE" }, \ - { &none, 21, "R_MIPS_GOT_OFST" }, \ - { &gothi16, 22, "R_MIPS_GOT_HI16" }, \ - { &gotlo16, 23, "R_MIPS_GOT_LO16" }, \ - { &none, 24, "R_MIPS_SUB" }, \ - { &none, 25, "R_MIPS_INSERT_A" }, \ - { &none, 26, "R_MIPS_INSERT_B" }, \ - { &none, 27, "R_MIPS_DELETE" }, \ - { &none, 28, "R_MIPS_HIGHER" }, \ - { &none, 29, "R_MIPS_HIGHEST" }, \ - { &gothi16, 30, "R_MIPS_CALL_HI16" }, \ - { &gotlo16, 31, "R_MIPS_CALL_LO16" }, \ - { &none, 32, "R_MIPS_SCN_DISP" }, \ - { &none, 33, "R_MIPS_REL16" }, \ - { &none, 34, "R_MIPS_ADD_IMMEDIATE" }, \ - { &none, 35, "R_MIPS_PJUMP" }, \ - { &none, 36, "R_MIPS_RELGOT" }, \ - { &none, 37, "R_MIPS_JALR" }, \ - { &none, 38, "R_MIPS_TLS_DTPMOD32" }, \ - { &none, 39, "R_MIPS_TLS_DTPREL32" }, \ - { &none, 40, "R_MIPS_TLS_DTPMOD64" }, \ - { &none, 41, "R_MIPS_TLS_DTPREL64" }, \ - { &none, 42, "R_MIPS_TLS_GD" }, \ - { &none, 43, "R_MIPS_TLS_LDM" }, \ - { &none, 44, "R_MIPS_TLS_DTPREL_HI16" }, \ - { &none, 45, "R_MIPS_TLS_DTPREL_LO16" }, \ - { &none, 46, "R_MIPS_TLS_GOTTPREL" }, \ - { &none, 47, "R_MIPS_TLS_TPREL32" }, \ - { &none, 48, "R_MIPS_TLS_TPREL64" }, \ - { &none, 49, "R_MIPS_TLS_TPREL_HI16" }, \ - { &none, 50, "R_MIPS_TLS_TPREL_LO16" }, \ - { &none, 51, "R_MIPS_GLOB_DAT" } + { &none, 0, "R_MIPS_NONE", 0}, \ + { &none, 1, "R_MIPS_16", 16}, \ + { &abs32, 2, "R_MIPS_32", 32}, \ + { &none, 3, "R_MIPS_REL32", 32}, \ + { &none, 4, "R_MIPS_26", 64}, \ + { &hi16, 5, "R_MIPS_HI16", 16}, \ + { &lo16, 6, "R_MIPS_LO16", 16}, \ + { &none, 7, "R_MIPS_GPREL16", 16}, \ + { &none, 8, "R_MIPS_LITERAL", 16}, \ + { &got16, 9, "R_MIPS_GOT16", 16}, \ + { &none, 10, "R_MIPS_PC16", 16}, \ + { &call16, 11, "R_MIPS_CALL16", 16}, \ + { &gprel32, 12, "R_MIPS_GPREL32", 32}, \ + { &none, 13, "R_MIPS_UNUSED1", 0}, \ + { &none, 14, "R_MIPS_UNUSED2", 0}, \ + { &none, 15, "R_MIPS_UNUSED3", 0}, \ + { &none, 16, "R_MIPS_SHIFT5", 32}, \ + { &none, 17, "R_MIPS_SHIFT6", 32}, \ + { &none, 18, "R_MIPS_64", 64}, \ + { &none, 19, "R_MIPS_GOT_DISP", 16}, \ + { &none, 20, "R_MIPS_GOT_PAGE", 16}, \ + { &none, 21, "R_MIPS_GOT_OFST", 16}, \ + { &gothi16, 22, "R_MIPS_GOT_HI16", 16}, \ + { &gotlo16, 23, "R_MIPS_GOT_LO16", 16}, \ + { &none, 24, "R_MIPS_SUB", 64}, \ + { &none, 25, "R_MIPS_INSERT_A", 0}, \ + { &none, 26, "R_MIPS_INSERT_B", 0}, \ + { &none, 27, "R_MIPS_DELETE", 0}, \ + { &none, 28, "R_MIPS_HIGHER", 16}, \ + { &none, 29, "R_MIPS_HIGHEST", 16}, \ + { &gothi16, 30, "R_MIPS_CALL_HI16", 16}, \ + { &gotlo16, 31, "R_MIPS_CALL_LO16", 16}, \ + { &none, 32, "R_MIPS_SCN_DISP", 32}, \ + { &none, 33, "R_MIPS_REL16", 0}, \ + { &none, 34, "R_MIPS_ADD_IMMEDIATE", 0}, \ + { &none, 35, "R_MIPS_PJUMP", 0}, \ + { &none, 36, "R_MIPS_RELGOT", 0}, \ + { &none, 37, "R_MIPS_JALR", 32}, \ + { &none, 38, "R_MIPS_TLS_DTPMOD32", 32}, \ + { &none, 39, "R_MIPS_TLS_DTPREL32", 32}, \ + { &none, 40, "R_MIPS_TLS_DTPMOD64", 0}, \ + { &none, 41, "R_MIPS_TLS_DTPREL64", 0}, \ + { &none, 42, "R_MIPS_TLS_GD", 16}, \ + { &none, 43, "R_MIPS_TLS_LDM", 16}, \ + { &none, 44, "R_MIPS_TLS_DTPREL_HI16", 16}, \ + { &none, 45, "R_MIPS_TLS_DTPREL_LO16", 16}, \ + { &none, 46, "R_MIPS_TLS_GOTTPREL", 16}, \ + { &none, 47, "R_MIPS_TLS_TPREL32", 32}, \ + { &none, 48, "R_MIPS_TLS_TPREL64", 0}, \ + { &none, 49, "R_MIPS_TLS_TPREL_HI16", 16}, \ + { &none, 50, "R_MIPS_TLS_TPREL_LO16", 16}, \ + { &none, 51, "R_MIPS_GLOB_DAT", 0} diff --git a/lib/Target/Mips/MipsRelocator.cpp b/lib/Target/Mips/MipsRelocator.cpp index ad5de22..ec551ae 100644 --- a/lib/Target/Mips/MipsRelocator.cpp +++ b/lib/Target/Mips/MipsRelocator.cpp @@ -9,7 +9,6 @@ #include <llvm/ADT/Twine.h> #include <llvm/Support/ELF.h> -#include <mcld/Fragment/FragmentLinker.h> #include <mcld/Support/MsgHandling.h> #include <mcld/Target/OutputRelocSection.h> @@ -32,6 +31,7 @@ struct ApplyFunctionTriple ApplyFunctionType func; unsigned int type; const char* name; + unsigned int size; }; // declare the table of applying functions @@ -68,9 +68,13 @@ const char* MipsRelocator::getName(Relocation::Type pType) const return ApplyFunctions[pType].name; } +Relocator::Size MipsRelocator::getSize(Relocation::Type pType) const +{ + return ApplyFunctions[pType].size; +} + //===----------------------------------------------------------------------===// // Relocation helper function - //===----------------------------------------------------------------------===// static const char * const GP_DISP_NAME = "_gp_disp"; diff --git a/lib/Target/Mips/MipsRelocator.h b/lib/Target/Mips/MipsRelocator.h index 836b7d2..fcb6af9 100644 --- a/lib/Target/Mips/MipsRelocator.h +++ b/lib/Target/Mips/MipsRelocator.h @@ -48,6 +48,8 @@ public: const char* getName(Relocation::Type pType) const; + Size getSize(Relocation::Type pType) const; + const SymGOTMap& getSymGOTMap() const { return m_SymGOTMap; } SymGOTMap& getSymGOTMap() { return m_SymGOTMap; } diff --git a/lib/Target/OutputRelocSection.cpp b/lib/Target/OutputRelocSection.cpp index 3c1a0ce..2584d13 100644 --- a/lib/Target/OutputRelocSection.cpp +++ b/lib/Target/OutputRelocSection.cpp @@ -71,7 +71,7 @@ size_t OutputRelocSection::numOfRelocs() bool OutputRelocSection::addSymbolToDynSym(LDSymbol& pSymbol) { - m_Module.getSymbolTable().changeLocalToTLS(pSymbol); + m_Module.getSymbolTable().changeLocalToDynamic(pSymbol); return true; } diff --git a/lib/Target/X86/TargetInfo/X86TargetInfo.cpp b/lib/Target/X86/TargetInfo/X86TargetInfo.cpp index 0985c02..3c02314 100644 --- a/lib/Target/X86/TargetInfo/X86TargetInfo.cpp +++ b/lib/Target/X86/TargetInfo/X86TargetInfo.cpp @@ -11,11 +11,13 @@ namespace mcld { -mcld::Target TheX86Target; +mcld::Target TheX86_32Target; +mcld::Target TheX86_64Target; extern "C" void MCLDInitializeX86LDTargetInfo() { // register into mcld::TargetRegistry - mcld::RegisterTarget X(TheX86Target, "x86"); + mcld::RegisterTarget X(TheX86_32Target, "x86"); + mcld::RegisterTarget Y(TheX86_64Target, "x86-64"); } } // namespace of mcld diff --git a/lib/Target/X86/X86.h b/lib/Target/X86/X86.h index 2d07314..0f7d65d 100644 --- a/lib/Target/X86/X86.h +++ b/lib/Target/X86/X86.h @@ -14,7 +14,8 @@ namespace mcld { class TargetLDBackend; -extern mcld::Target TheX86Target; +extern mcld::Target TheX86_32Target; +extern mcld::Target TheX86_64Target; TargetLDBackend *createX86LDBackend(const llvm::Target&, const std::string&); diff --git a/lib/Target/X86/X86Diagnostic.cpp b/lib/Target/X86/X86Diagnostic.cpp index 7191596..9287ca7 100644 --- a/lib/Target/X86/X86Diagnostic.cpp +++ b/lib/Target/X86/X86Diagnostic.cpp @@ -33,6 +33,7 @@ DiagnosticLineInfo* createX86DiagLineInfo(const mcld::Target& pTarget, // InitializeX86Diagnostic extern "C" void MCLDInitializeX86DiagnosticLineInfo() { // Register the linker frontend - mcld::TargetRegistry::RegisterDiagnosticLineInfo(TheX86Target, createX86DiagLineInfo); + mcld::TargetRegistry::RegisterDiagnosticLineInfo(TheX86_32Target, createX86DiagLineInfo); + mcld::TargetRegistry::RegisterDiagnosticLineInfo(TheX86_64Target, createX86DiagLineInfo); } diff --git a/lib/Target/X86/X86Emulation.cpp b/lib/Target/X86/X86Emulation.cpp index 9343583..753d7cc 100644 --- a/lib/Target/X86/X86Emulation.cpp +++ b/lib/Target/X86/X86Emulation.cpp @@ -20,7 +20,17 @@ static bool MCLDEmulateX86ELF(LinkerConfig& pConfig) // set up bitclass and endian pConfig.targets().setEndian(TargetOptions::Little); - pConfig.targets().setBitClass(32); + unsigned int bitclass; + Triple::ArchType arch = pConfig.targets().triple().getArch(); + assert (arch == Triple::x86 || arch == Triple::x86_64); + if (arch == Triple::x86 || + pConfig.targets().triple().getEnvironment() == Triple::GNUX32) { + bitclass = 32; + } + else { + bitclass = 64; + } + pConfig.targets().setBitClass(bitclass); // set up target-dependent constraints of attributes pConfig.attribute().constraint().enableWholeArchive(); @@ -59,6 +69,7 @@ bool emulateX86LD(const std::string& pTriple, LinkerConfig& pConfig) //===----------------------------------------------------------------------===// extern "C" void MCLDInitializeX86Emulation() { // Register the emulation - mcld::TargetRegistry::RegisterEmulation(mcld::TheX86Target, mcld::emulateX86LD); + mcld::TargetRegistry::RegisterEmulation(mcld::TheX86_32Target, mcld::emulateX86LD); + mcld::TargetRegistry::RegisterEmulation(mcld::TheX86_64Target, mcld::emulateX86LD); } diff --git a/lib/Target/X86/X86GNUInfo.h b/lib/Target/X86/X86GNUInfo.h index af548f0..65b0451 100644 --- a/lib/Target/X86/X86GNUInfo.h +++ b/lib/Target/X86/X86GNUInfo.h @@ -14,13 +14,34 @@ namespace mcld { -class X86GNUInfo : public GNUInfo +class X86_32GNUInfo : public GNUInfo { public: - X86GNUInfo(const llvm::Triple& pTriple) : GNUInfo(pTriple) { } + X86_32GNUInfo(const llvm::Triple& pTriple) : GNUInfo(pTriple) { } uint32_t machine() const { return llvm::ELF::EM_386; } + uint64_t defaultTextSegmentAddr() const { return 0x08048000; } + + /// flags - the value of ElfXX_Ehdr::e_flags + /// FIXME + uint64_t flags() const { return 0x0; } + +}; + +class X86_64GNUInfo : public GNUInfo +{ +public: + X86_64GNUInfo(const llvm::Triple& pTriple) : GNUInfo(pTriple) { } + + uint32_t machine() const { return llvm::ELF::EM_X86_64; } + + uint64_t defaultTextSegmentAddr() const { return 0x400000; } + + /// flags - the value of ElfXX_Ehdr::e_flags + /// FIXME + uint64_t flags() const { return 0x0; } + }; } // namespace of mcld diff --git a/lib/Target/X86/X86GOT.cpp b/lib/Target/X86/X86GOT.cpp index e734bb3..b77cfd3 100644 --- a/lib/Target/X86/X86GOT.cpp +++ b/lib/Target/X86/X86GOT.cpp @@ -16,33 +16,64 @@ using namespace mcld; //===----------------------------------------------------------------------===// -// X86GOT +// X86_32GOT //===----------------------------------------------------------------------===// -X86GOT::X86GOT(LDSection& pSection) +X86_32GOT::X86_32GOT(LDSection& pSection) : GOT(pSection), m_pLast(NULL) { } -X86GOT::~X86GOT() +X86_32GOT::~X86_32GOT() { } -void X86GOT::reserve(size_t pNum) +void X86_32GOT::reserve(size_t pNum) { for (size_t i = 0; i < pNum; i++) { - new X86GOTEntry(0, m_SectionData); + new X86_32GOTEntry(0, m_SectionData); } } -X86GOTEntry* X86GOT::consume() +X86_32GOTEntry* X86_32GOT::consume() { if (NULL == m_pLast) { assert(!empty() && "Consume empty GOT entry!"); - m_pLast = llvm::cast<X86GOTEntry>(&m_SectionData->front()); + m_pLast = llvm::cast<X86_32GOTEntry>(&m_SectionData->front()); return m_pLast; } - m_pLast = llvm::cast<X86GOTEntry>(m_pLast->getNextNode()); + m_pLast = llvm::cast<X86_32GOTEntry>(m_pLast->getNextNode()); + return m_pLast; +} + +//===----------------------------------------------------------------------===// +// X86_64GOT +//===----------------------------------------------------------------------===// +X86_64GOT::X86_64GOT(LDSection& pSection) + : GOT(pSection), m_pLast(NULL) +{ +} + +X86_64GOT::~X86_64GOT() +{ +} + +void X86_64GOT::reserve(size_t pNum) +{ + for (size_t i = 0; i < pNum; i++) { + new X86_64GOTEntry(0, m_SectionData); + } +} + +X86_64GOTEntry* X86_64GOT::consume() +{ + if (NULL == m_pLast) { + assert(!empty() && "Consume empty GOT entry!"); + m_pLast = llvm::cast<X86_64GOTEntry>(&m_SectionData->front()); + return m_pLast; + } + + m_pLast = llvm::cast<X86_64GOTEntry>(m_pLast->getNextNode()); return m_pLast; } diff --git a/lib/Target/X86/X86GOT.h b/lib/Target/X86/X86GOT.h index 66967e1..df557f3 100644 --- a/lib/Target/X86/X86GOT.h +++ b/lib/Target/X86/X86GOT.h @@ -19,34 +19,64 @@ namespace mcld { class LDSection; class SectionData; -/** \class X86GOTEntry +/** \class X86_32GOTEntry * \brief GOT Entry with size of 4 bytes */ -class X86GOTEntry : public GOT::Entry<4> +class X86_32GOTEntry : public GOT::Entry<4> { public: - X86GOTEntry(uint64_t pContent, SectionData* pParent) + X86_32GOTEntry(uint64_t pContent, SectionData* pParent) : GOT::Entry<4>(pContent, pParent) {} }; -/** \class X86GOT - * \brief X86 Global Offset Table. +/** \class X86_32GOT + * \brief X86_32 Global Offset Table. */ -class X86GOT : public GOT +class X86_32GOT : public GOT { public: - X86GOT(LDSection& pSection); + X86_32GOT(LDSection& pSection); - ~X86GOT(); + ~X86_32GOT(); void reserve(size_t pNum = 1); - X86GOTEntry* consume(); + X86_32GOTEntry* consume(); private: - X86GOTEntry* m_pLast; ///< the last consumed entry + X86_32GOTEntry* m_pLast; ///< the last consumed entry +}; + +/** \class X86_64GOTEntry + * \brief GOT Entry with size of 8 bytes + */ +class X86_64GOTEntry : public GOT::Entry<8> +{ +public: + X86_64GOTEntry(uint64_t pContent, SectionData* pParent) + : GOT::Entry<8>(pContent, pParent) + {} +}; + +/** \class X86_64GOT + * \brief X86_64 Global Offset Table. + */ + +class X86_64GOT : public GOT +{ +public: + X86_64GOT(LDSection& pSection); + + ~X86_64GOT(); + + void reserve(size_t pNum = 1); + + X86_64GOTEntry* consume(); + +private: + X86_64GOTEntry* m_pLast; ///< the last consumed entry }; } // namespace of mcld diff --git a/lib/Target/X86/X86GOTPLT.cpp b/lib/Target/X86/X86GOTPLT.cpp index b72487e..961e0dc 100644 --- a/lib/Target/X86/X86GOTPLT.cpp +++ b/lib/Target/X86/X86GOTPLT.cpp @@ -18,10 +18,10 @@ namespace mcld { //===----------------------------------------------------------------------===// -// X86GOTPLT +// X86_32GOTPLT //===----------------------------------------------------------------------===// -X86GOTPLT::X86GOTPLT(LDSection& pSection) - : GOT(pSection), m_pLast(NULL) +X86_32GOTPLT::X86_32GOTPLT(LDSection& pSection) + : X86_32GOT(pSection) { // Create GOT0 entries reserve(X86GOTPLT0Num); @@ -32,41 +32,66 @@ X86GOTPLT::X86GOTPLT(LDSection& pSection) } } -X86GOTPLT::~X86GOTPLT() +X86_32GOTPLT::~X86_32GOTPLT() { } -void X86GOTPLT::reserve(size_t pNum) +bool X86_32GOTPLT::hasGOT1() const { - for (size_t i = 0; i < pNum; i++) { - new X86GOTPLTEntry(0, m_SectionData); + return (m_SectionData->size() > X86GOTPLT0Num); +} + +void X86_32GOTPLT::applyGOT0(uint64_t pAddress) +{ + llvm::cast<X86_32GOTEntry> + (*(m_SectionData->getFragmentList().begin())).setValue(pAddress); +} + +void X86_32GOTPLT::applyAllGOTPLT(const X86PLT& pPLT) +{ + iterator it = begin(); + // skip GOT0 + for (size_t i = 0; i < X86GOTPLT0Num; ++i) + ++it; + // address of corresponding plt entry + uint64_t plt_addr = pPLT.addr() + pPLT.getPLT0Size(); + for (; it != end() ; ++it) { + llvm::cast<X86_32GOTEntry>(*it).setValue(plt_addr + 6); + plt_addr += pPLT.getPLT1Size(); } } -X86GOTPLTEntry* X86GOTPLT::consume() +//===----------------------------------------------------------------------===// +// X86_64GOTPLT +//===----------------------------------------------------------------------===// +X86_64GOTPLT::X86_64GOTPLT(LDSection& pSection) + : X86_64GOT(pSection) { - if (NULL == m_pLast) { - assert(!empty() && "Consume empty GOT entry!"); - m_pLast = llvm::cast<X86GOTPLTEntry>(&m_SectionData->front()); - return m_pLast; + // Create GOT0 entries + reserve(X86GOTPLT0Num); + + // Skip GOT0 entries + for (size_t i = 0; i < X86GOTPLT0Num; ++i) { + consume(); } +} - m_pLast = llvm::cast<X86GOTPLTEntry>(m_pLast->getNextNode()); - return m_pLast; +X86_64GOTPLT::~X86_64GOTPLT() +{ } -bool X86GOTPLT::hasGOT1() const +bool X86_64GOTPLT::hasGOT1() const { return (m_SectionData->size() > X86GOTPLT0Num); } -void X86GOTPLT::applyGOT0(uint64_t pAddress) +void X86_64GOTPLT::applyGOT0(uint64_t pAddress) { - llvm::cast<X86GOTPLTEntry> + llvm::cast<X86_64GOTEntry> (*(m_SectionData->getFragmentList().begin())).setValue(pAddress); } -void X86GOTPLT::applyAllGOTPLT(const X86PLT& pPLT) +void X86_64GOTPLT::applyAllGOTPLT(const X86PLT& pPLT) { iterator it = begin(); // skip GOT0 @@ -75,7 +100,7 @@ void X86GOTPLT::applyAllGOTPLT(const X86PLT& pPLT) // address of corresponding plt entry uint64_t plt_addr = pPLT.addr() + pPLT.getPLT0Size(); for (; it != end() ; ++it) { - llvm::cast<X86GOTPLTEntry>(*it).setValue(plt_addr + 6); + llvm::cast<X86_64GOTEntry>(*it).setValue(plt_addr + 6); plt_addr += pPLT.getPLT1Size(); } } diff --git a/lib/Target/X86/X86GOTPLT.h b/lib/Target/X86/X86GOTPLT.h index f288fa4..8e13fac 100644 --- a/lib/Target/X86/X86GOTPLT.h +++ b/lib/Target/X86/X86GOTPLT.h @@ -14,7 +14,7 @@ #include <llvm/ADT/DenseMap.h> -#include <mcld/Target/GOT.h> +#include "X86GOT.h" namespace mcld { @@ -23,27 +23,33 @@ class LDSection; const unsigned int X86GOTPLT0Num = 3; -class X86GOTPLTEntry : public GOT::Entry<4> +/** \class X86_32GOTPLT + * \brief X86_32 .got.plt section. + */ +class X86_32GOTPLT : public X86_32GOT { public: - X86GOTPLTEntry(uint64_t pContent, SectionData* pParent) - : GOT::Entry<4>(pContent, pParent) - {} + X86_32GOTPLT(LDSection &pSection); + + ~X86_32GOTPLT(); + + // hasGOT1 - return if this section has any GOT1 entry + bool hasGOT1() const; + + void applyGOT0(uint64_t pAddress); + + void applyAllGOTPLT(const X86PLT& pPLT); }; -/** \class X86GOTPLT - * \brief X86 .got.plt section. +/** \class X86_64GOTPLT + * \brief X86_64 .got.plt section. */ -class X86GOTPLT : public GOT +class X86_64GOTPLT : public X86_64GOT { public: - X86GOTPLT(LDSection &pSection); + X86_64GOTPLT(LDSection &pSection); - ~X86GOTPLT(); - - void reserve(size_t pNum = 1); - - X86GOTPLTEntry* consume(); + ~X86_64GOTPLT(); // hasGOT1 - return if this section has any GOT1 entry bool hasGOT1() const; @@ -51,9 +57,6 @@ public: void applyGOT0(uint64_t pAddress); void applyAllGOTPLT(const X86PLT& pPLT); - -private: - X86GOTPLTEntry* m_pLast; ///< the last consumed entry }; } // namespace of mcld diff --git a/lib/Target/X86/X86LDBackend.cpp b/lib/Target/X86/X86LDBackend.cpp index a18fedb..e08120e 100644 --- a/lib/Target/X86/X86LDBackend.cpp +++ b/lib/Target/X86/X86LDBackend.cpp @@ -32,79 +32,83 @@ using namespace mcld; //===----------------------------------------------------------------------===// // X86GNULDBackend //===----------------------------------------------------------------------===// -X86GNULDBackend::X86GNULDBackend(const LinkerConfig& pConfig, X86GNUInfo* pInfo) +X86GNULDBackend::X86GNULDBackend(const LinkerConfig& pConfig, + GNUInfo* pInfo, + Relocation::Type pCopyRel) : GNULDBackend(pConfig, pInfo), m_pRelocator(NULL), - m_pGOT(NULL), m_pPLT(NULL), - m_pGOTPLT(NULL), m_pRelDyn(NULL), m_pRelPLT(NULL), m_pDynamic(NULL), - m_pGOTSymbol(NULL) { + m_pGOTSymbol(NULL), + m_CopyRel(pCopyRel) +{ + Triple::ArchType arch = pConfig.targets().triple().getArch(); + assert (arch == Triple::x86 || arch == Triple::x86_64); + if (arch == Triple::x86 || + pConfig.targets().triple().getEnvironment() == Triple::GNUX32) { + m_RelEntrySize = 8; + m_RelaEntrySize = 12; + if (arch == Triple::x86) + m_PointerRel = llvm::ELF::R_386_32; + else + m_PointerRel = llvm::ELF::R_X86_64_32; + } + else { + m_RelEntrySize = 16; + m_RelaEntrySize = 24; + m_PointerRel = llvm::ELF::R_X86_64_64; + } } X86GNULDBackend::~X86GNULDBackend() { delete m_pRelocator; - delete m_pGOT; delete m_pPLT; - delete m_pGOTPLT; delete m_pRelDyn; delete m_pRelPLT; delete m_pDynamic; } -bool X86GNULDBackend::initRelocator(const FragmentLinker& pLinker) -{ - if (NULL == m_pRelocator) { - m_pRelocator = new X86Relocator(*this); - m_pRelocator->setFragmentLinker(pLinker); - } - return true; -} - Relocator* X86GNULDBackend::getRelocator() { assert(NULL != m_pRelocator); return m_pRelocator; } -void X86GNULDBackend::doPreLayout(FragmentLinker& pLinker) +void X86GNULDBackend::doPreLayout(IRBuilder& pBuilder) { - // set .got.plt size + // initialize .dynamic data + if (!config().isCodeStatic() && NULL == m_pDynamic) + m_pDynamic = new X86ELFDynamic(*this, config()); + + // set .got.plt and .got sizes // when building shared object, the .got section is must if (LinkerConfig::Object != config().codeGenType()) { - if (LinkerConfig::DynObj == config().codeGenType() || - m_pGOTPLT->hasGOT1() || - NULL != m_pGOTSymbol) { - m_pGOTPLT->finalizeSectionSize(); - defineGOTSymbol(pLinker); - } - - // set .got size - if (!m_pGOT->empty()) - m_pGOT->finalizeSectionSize(); + setGOTSectionSize(pBuilder); // set .plt size if (m_pPLT->hasPLT1()) m_pPLT->finalizeSectionSize(); - ELFFileFormat* file_format = getOutputFormat(); - // set .rel.dyn size - if (!m_pRelDyn->empty()) - file_format->getRelDyn().setSize( - m_pRelDyn->numOfRelocs() * getRelEntrySize()); - - // set .rel.plt size - if (!m_pRelPLT->empty()) - file_format->getRelPlt().setSize( - m_pRelPLT->numOfRelocs() * getRelEntrySize()); + // set .rel.dyn/.rela.dyn size + if (!m_pRelDyn->empty()) { + assert(!config().isCodeStatic() && + "static linkage should not result in a dynamic relocation section"); + setRelDynSize(); + } + // set .rel.plt/.rela.plt size + if (!m_pRelPLT->empty()) { + assert(!config().isCodeStatic() && + "static linkage should not result in a dynamic relocation section"); + setRelPLTSize(); + } } } void X86GNULDBackend::doPostLayout(Module& pModule, - FragmentLinker& pLinker) + IRBuilder& pBuilder) { } @@ -112,9 +116,7 @@ void X86GNULDBackend::doPostLayout(Module& pModule, /// Use co-variant return type to return its own dynamic section. X86ELFDynamic& X86GNULDBackend::dynamic() { - if (NULL == m_pDynamic) - m_pDynamic = new X86ELFDynamic(*this, config()); - + assert(NULL != m_pDynamic); return *m_pDynamic; } @@ -122,35 +124,34 @@ X86ELFDynamic& X86GNULDBackend::dynamic() /// Use co-variant return type to return its own dynamic section. const X86ELFDynamic& X86GNULDBackend::dynamic() const { - assert( NULL != m_pDynamic); + assert(NULL != m_pDynamic); return *m_pDynamic; } -void X86GNULDBackend::defineGOTSymbol(FragmentLinker& pLinker) +void X86GNULDBackend::defineGOTSymbol(IRBuilder& pBuilder, + Fragment& pFrag) { // define symbol _GLOBAL_OFFSET_TABLE_ if (m_pGOTSymbol != NULL) { - pLinker.defineSymbol<FragmentLinker::Force, FragmentLinker::Unresolve>( + pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Unresolve>( "_GLOBAL_OFFSET_TABLE_", - false, ResolveInfo::Object, ResolveInfo::Define, ResolveInfo::Local, 0x0, // size 0x0, // value - FragmentRef::Create(*(m_pGOTPLT->begin()), 0x0), + FragmentRef::Create(pFrag, 0x0), ResolveInfo::Hidden); } else { - m_pGOTSymbol = pLinker.defineSymbol<FragmentLinker::Force, FragmentLinker::Resolve>( + m_pGOTSymbol = pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Resolve>( "_GLOBAL_OFFSET_TABLE_", - false, ResolveInfo::Object, ResolveInfo::Define, ResolveInfo::Local, 0x0, // size 0x0, // value - FragmentRef::Create(*(m_pGOTPLT->begin()), 0x0), + FragmentRef::Create(pFrag, 0x0), ResolveInfo::Hidden); } } @@ -158,7 +159,7 @@ void X86GNULDBackend::defineGOTSymbol(FragmentLinker& pLinker) void X86GNULDBackend::addCopyReloc(ResolveInfo& pSym) { Relocation& rel_entry = *m_pRelDyn->consumeEntry(); - rel_entry.setType(llvm::ELF::R_386_COPY); + rel_entry.setType(m_CopyRel); assert(pSym.outSymbol()->hasFragRef()); rel_entry.targetRef().assign(*pSym.outSymbol()->fragRef()); rel_entry.setSymInfo(&pSym); @@ -169,7 +170,7 @@ void X86GNULDBackend::addCopyReloc(ResolveInfo& pSym) /// section and all other reference to this symbol should refer to this /// copy. /// @note This is executed at `scan relocation' stage. -LDSymbol& X86GNULDBackend::defineSymbolforCopyReloc(FragmentLinker& pLinker, +LDSymbol& X86GNULDBackend::defineSymbolforCopyReloc(IRBuilder& pBuilder, const ResolveInfo& pSym) { // get or create corresponding BSS LDSection @@ -205,10 +206,8 @@ LDSymbol& X86GNULDBackend::defineSymbolforCopyReloc(FragmentLinker& pLinker, binding = ResolveInfo::Global; // Define the copy symbol in the bss section and resolve it - LDSymbol* cpy_sym = - pLinker.defineSymbol<FragmentLinker::Force, FragmentLinker::Resolve>( + LDSymbol* cpy_sym = pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Resolve>( pSym.name(), - false, (ResolveInfo::Type)pSym.type(), ResolveInfo::Define, binding, @@ -220,10 +219,204 @@ LDSymbol& X86GNULDBackend::defineSymbolforCopyReloc(FragmentLinker& pLinker, return *cpy_sym; } -void X86GNULDBackend::scanLocalReloc(Relocation& pReloc, - FragmentLinker& pLinker, +void X86GNULDBackend::scanRelocation(Relocation& pReloc, + IRBuilder& pLinker, Module& pModule, - const LDSection& pSection) + LDSection& pSection) +{ + if (LinkerConfig::Object == config().codeGenType()) + return; + // rsym - The relocation target symbol + ResolveInfo* rsym = pReloc.symInfo(); + assert(NULL != rsym && + "ResolveInfo of relocation not set while scanRelocation"); + + pReloc.updateAddend(); + assert(NULL != pSection.getLink()); + if (0 == (pSection.getLink()->flag() & llvm::ELF::SHF_ALLOC)) + return; + + // Scan relocation type to determine if the GOT/PLT/Dynamic Relocation + // entries should be created. + if (rsym->isLocal()) // rsym is local + scanLocalReloc(pReloc, pLinker, pModule, pSection); + else // rsym is external + scanGlobalReloc(pReloc, pLinker, pModule, pSection); + + // check if we should issue undefined reference for the relocation target + // symbol + if (rsym->isUndef() && !rsym->isDyn() && !rsym->isWeak() && !rsym->isNull()) + fatal(diag::undefined_reference) << rsym->name(); +} + +uint64_t X86GNULDBackend::emitSectionData(const LDSection& pSection, + MemoryRegion& pRegion) const +{ + assert(pRegion.size() && "Size of MemoryRegion is zero!"); + + const ELFFileFormat* FileFormat = getOutputFormat(); + assert(FileFormat && + "ELFFileFormat is NULL in X86GNULDBackend::emitSectionData!"); + + unsigned int EntrySize = 0; + uint64_t RegionSize = 0; + + if (&pSection == &(FileFormat->getPLT())) { + assert(m_pPLT && "emitSectionData failed, m_pPLT is NULL!"); + + unsigned char* buffer = pRegion.getBuffer(); + + m_pPLT->applyPLT0(); + m_pPLT->applyPLT1(); + X86PLT::iterator it = m_pPLT->begin(); + unsigned int plt0_size = llvm::cast<PLTEntryBase>((*it)).size(); + + memcpy(buffer, llvm::cast<PLTEntryBase>((*it)).getValue(), plt0_size); + RegionSize += plt0_size; + ++it; + + PLTEntryBase* plt1 = 0; + X86PLT::iterator ie = m_pPLT->end(); + while (it != ie) { + plt1 = &(llvm::cast<PLTEntryBase>(*it)); + EntrySize = plt1->size(); + memcpy(buffer + RegionSize, plt1->getValue(), EntrySize); + RegionSize += EntrySize; + ++it; + } + } + + else if (&pSection == &(FileFormat->getGOT())) { + RegionSize += emitGOTSectionData(pRegion); + } + + else if (&pSection == &(FileFormat->getGOTPLT())) { + RegionSize += emitGOTPLTSectionData(pRegion, FileFormat); + } + + else { + fatal(diag::unrecognized_output_sectoin) + << pSection.name() + << "mclinker@googlegroups.com"; + } + return RegionSize; +} + +X86PLT& X86GNULDBackend::getPLT() +{ + assert(NULL != m_pPLT && "PLT section not exist"); + return *m_pPLT; +} + +const X86PLT& X86GNULDBackend::getPLT() const +{ + assert(NULL != m_pPLT && "PLT section not exist"); + return *m_pPLT; +} + +OutputRelocSection& X86GNULDBackend::getRelDyn() +{ + assert(NULL != m_pRelDyn && ".rel.dyn/.rela.dyn section not exist"); + return *m_pRelDyn; +} + +const OutputRelocSection& X86GNULDBackend::getRelDyn() const +{ + assert(NULL != m_pRelDyn && ".rel.dyn/.rela.dyn section not exist"); + return *m_pRelDyn; +} + +OutputRelocSection& X86GNULDBackend::getRelPLT() +{ + assert(NULL != m_pRelPLT && ".rel.plt/.rela.plt section not exist"); + return *m_pRelPLT; +} + +const OutputRelocSection& X86GNULDBackend::getRelPLT() const +{ + assert(NULL != m_pRelPLT && ".rel.plt/.rela.plt section not exist"); + return *m_pRelPLT; +} + +unsigned int +X86GNULDBackend::getTargetSectionOrder(const LDSection& pSectHdr) const +{ + const ELFFileFormat* file_format = getOutputFormat(); + + if (&pSectHdr == &file_format->getGOT()) { + if (config().options().hasNow()) + return SHO_RELRO; + return SHO_RELRO_LAST; + } + + if (&pSectHdr == &file_format->getGOTPLT()) { + if (config().options().hasNow()) + return SHO_RELRO; + return SHO_NON_RELRO_FIRST; + } + + if (&pSectHdr == &file_format->getPLT()) + return SHO_PLT; + + return SHO_UNDEFINED; +} + +void X86GNULDBackend::initTargetSymbols(IRBuilder& pBuilder, Module& pModule) +{ + if (LinkerConfig::Object != config().codeGenType()) { + // Define the symbol _GLOBAL_OFFSET_TABLE_ if there is a symbol with the + // same name in input + m_pGOTSymbol = + pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>( + "_GLOBAL_OFFSET_TABLE_", + ResolveInfo::Object, + ResolveInfo::Define, + ResolveInfo::Local, + 0x0, // size + 0x0, // value + FragmentRef::Null(), // FragRef + ResolveInfo::Hidden); + } +} + +/// finalizeSymbol - finalize the symbol value +bool X86GNULDBackend::finalizeTargetSymbols() +{ + return true; +} + +/// doCreateProgramHdrs - backend can implement this function to create the +/// target-dependent segments +void X86GNULDBackend::doCreateProgramHdrs(Module& pModule) +{ + // TODO +} + +X86_32GNULDBackend::X86_32GNULDBackend(const LinkerConfig& pConfig, + GNUInfo* pInfo) + : X86GNULDBackend(pConfig, pInfo, llvm::ELF::R_386_COPY), + m_pGOT (NULL), + m_pGOTPLT (NULL) { +} + +X86_32GNULDBackend::~X86_32GNULDBackend() +{ + delete m_pGOT; + delete m_pGOTPLT; +} + +bool X86_32GNULDBackend::initRelocator() +{ + if (NULL == m_pRelocator) { + m_pRelocator = new X86_32Relocator(*this); + } + return true; +} + +void X86_32GNULDBackend::scanLocalReloc(Relocation& pReloc, + IRBuilder& pBuilder, + Module& pModule, + LDSection& pSection) { // rsym - The relocation target symbol ResolveInfo* rsym = pReloc.symInfo(); @@ -236,10 +429,11 @@ void X86GNULDBackend::scanLocalReloc(Relocation& pReloc, // If buiding PIC object (shared library or PIC executable), // a dynamic relocations with RELATIVE type to this location is needed. // Reserve an entry in .rel.dyn - if (pLinker.isOutputPIC()) { + if (config().isCodeIndep()) { m_pRelDyn->reserveEntry(); // set Rel bit rsym->setReserved(rsym->reserved() | ReserveRel); + checkAndSetHasTextRel(*pSection.getLink()); } return; @@ -255,6 +449,13 @@ void X86GNULDBackend::scanLocalReloc(Relocation& pReloc, return; // FIXME: check STT_GNU_IFUNC symbol m_pGOT->reserve(); + + // If the GOT is used in statically linked binaries, + // the GOT entry is enough and no relocation is needed. + if (config().isCodeStatic()) { + rsym->setReserved(rsym->reserved() | ReserveGOT); + return; + } // If building shared object or the symbol is undefined, a dynamic // relocation is needed to relocate this GOT entry. Reserve an // entry in .rel.dyn @@ -316,6 +517,11 @@ void X86GNULDBackend::scanLocalReloc(Relocation& pReloc, if (LinkerConfig::DynObj == config().codeGenType()) { m_pRelDyn->reserveEntry(); rsym->setReserved(rsym->reserved() | ReserveRel); + checkAndSetHasTextRel(*pSection.getLink()); + } else { + // for local sym, we can convert ie to le if not building shared object + convertTLSIEtoLE(pReloc, pSection); + return; } if (rsym->reserved() & GOTRel) return; @@ -346,6 +552,7 @@ void X86GNULDBackend::scanLocalReloc(Relocation& pReloc, if (LinkerConfig::DynObj == config().codeGenType()) { m_pRelDyn->reserveEntry(); rsym->setReserved(rsym->reserved() | ReserveRel); + checkAndSetHasTextRel(*pSection.getLink()); // the target symbol of the dynamic relocation is rsym, so we need to // emit it into .dynsym assert(NULL != rsym->outSymbol()); @@ -360,10 +567,10 @@ void X86GNULDBackend::scanLocalReloc(Relocation& pReloc, } // end switch } -void X86GNULDBackend::scanGlobalReloc(Relocation& pReloc, - FragmentLinker& pLinker, - Module& pModule, - const LDSection& pSection) +void X86_32GNULDBackend::scanGlobalReloc(Relocation& pReloc, + IRBuilder& pBuilder, + Module& pModule, + LDSection& pSection) { // rsym - The relocation target symbol ResolveInfo* rsym = pReloc.symInfo(); @@ -374,7 +581,7 @@ void X86GNULDBackend::scanGlobalReloc(Relocation& pReloc, case llvm::ELF::R_386_8: // Absolute relocation type, symbol may needs PLT entry or // dynamic relocation entry - if (symbolNeedsPLT(pLinker, *rsym)) { + if (symbolNeedsPLT(*rsym)) { // create plt for this symbol if it does not have one if (!(rsym->reserved() & ReservePLT)){ // Symbol needs PLT entry, we need to reserve a PLT entry @@ -389,17 +596,17 @@ void X86GNULDBackend::scanGlobalReloc(Relocation& pReloc, } } - if (symbolNeedsDynRel(pLinker, *rsym, (rsym->reserved() & ReservePLT), - true)) { + if (symbolNeedsDynRel(*rsym, (rsym->reserved() & ReservePLT), true)) { // symbol needs dynamic relocation entry, reserve an entry in .rel.dyn m_pRelDyn->reserveEntry(); - if (symbolNeedsCopyReloc(pLinker, pReloc, *rsym)) { - LDSymbol& cpy_sym = defineSymbolforCopyReloc(pLinker, *rsym); + if (symbolNeedsCopyReloc(pReloc, *rsym)) { + LDSymbol& cpy_sym = defineSymbolforCopyReloc(pBuilder, *rsym); addCopyReloc(*cpy_sym.resolveInfo()); } else { // set Rel bit rsym->setReserved(rsym->reserved() | ReserveRel); + checkAndSetHasTextRel(pSection); } } return; @@ -418,7 +625,7 @@ void X86GNULDBackend::scanGlobalReloc(Relocation& pReloc, return; // if the symbol's value can be decided at link time, then no need plt - if (symbolFinalValueIsKnown(pLinker, *rsym)) + if (symbolFinalValueIsKnown(*rsym)) return; // if symbol is defined in the ouput file and it's not @@ -445,6 +652,13 @@ void X86GNULDBackend::scanGlobalReloc(Relocation& pReloc, if (rsym->reserved() & (ReserveGOT | GOTRel)) return; m_pGOT->reserve(); + + // If the GOT is used in statically linked binaries, + // the GOT entry is enough and no relocation is needed. + if (config().isCodeStatic()) { + rsym->setReserved(rsym->reserved() | ReserveGOT); + return; + } // If building shared object or the symbol is undefined, a dynamic // relocation is needed to relocate this GOT entry. Reserve an // entry in .rel.dyn @@ -463,8 +677,8 @@ void X86GNULDBackend::scanGlobalReloc(Relocation& pReloc, case llvm::ELF::R_386_PC16: case llvm::ELF::R_386_PC8: - if (symbolNeedsPLT(pLinker, *rsym) && - LinkerConfig::DynObj != config().codeGenType()) { + if (symbolNeedsPLT(*rsym) && + LinkerConfig::DynObj != config().codeGenType()) { // create plt for this symbol if it does not have one if (!(rsym->reserved() & ReservePLT)){ // Symbol needs PLT entry, we need to reserve a PLT entry @@ -479,17 +693,17 @@ void X86GNULDBackend::scanGlobalReloc(Relocation& pReloc, } } - if (symbolNeedsDynRel(pLinker, *rsym, (rsym->reserved() & ReservePLT), - false)) { + if (symbolNeedsDynRel(*rsym, (rsym->reserved() & ReservePLT), false)) { // symbol needs dynamic relocation entry, reserve an entry in .rel.dyn m_pRelDyn->reserveEntry(); - if (symbolNeedsCopyReloc(pLinker, pReloc, *rsym)) { - LDSymbol& cpy_sym = defineSymbolforCopyReloc(pLinker, *rsym); + if (symbolNeedsCopyReloc(pReloc, *rsym)) { + LDSymbol& cpy_sym = defineSymbolforCopyReloc(pBuilder, *rsym); addCopyReloc(*cpy_sym.resolveInfo()); } else { // set Rel bit rsym->setReserved(rsym->reserved() | ReserveRel); + checkAndSetHasTextRel(pSection); } } return; @@ -519,6 +733,13 @@ void X86GNULDBackend::scanGlobalReloc(Relocation& pReloc, if (LinkerConfig::DynObj == config().codeGenType()) { m_pRelDyn->reserveEntry(); rsym->setReserved(rsym->reserved() | ReserveRel); + checkAndSetHasTextRel(*pSection.getLink()); + } else { + // for global sym, we can convert ie to le if its final value is known + if (symbolFinalValueIsKnown(*rsym)) { + convertTLSIEtoLE(pReloc, pSection); + return; + } } if (rsym->reserved() & GOTRel) return; @@ -547,6 +768,7 @@ void X86GNULDBackend::scanGlobalReloc(Relocation& pReloc, if (LinkerConfig::DynObj == config().codeGenType()) { m_pRelDyn->reserveEntry(); rsym->setReserved(rsym->reserved() | ReserveRel); + checkAndSetHasTextRel(*pSection.getLink()); } return; @@ -558,284 +780,557 @@ void X86GNULDBackend::scanGlobalReloc(Relocation& pReloc, } // end switch } -void X86GNULDBackend::scanRelocation(Relocation& pReloc, - FragmentLinker& pLinker, - Module& pModule, - const LDSection& pSection) +void X86_32GNULDBackend::initTargetSections(Module& pModule, + ObjectBuilder& pBuilder) { - if (LinkerConfig::Object == config().codeGenType()) - return; - // rsym - The relocation target symbol - ResolveInfo* rsym = pReloc.symInfo(); - assert(NULL != rsym && - "ResolveInfo of relocation not set while scanRelocation"); + if (LinkerConfig::Object != config().codeGenType()) { + ELFFileFormat* file_format = getOutputFormat(); + // initialize .got + LDSection& got = file_format->getGOT(); + m_pGOT = new X86_32GOT(got); - pReloc.updateAddend(); - if (0 == (pSection.flag() & llvm::ELF::SHF_ALLOC)) - return; + // initialize .got.plt + LDSection& gotplt = file_format->getGOTPLT(); + m_pGOTPLT = new X86_32GOTPLT(gotplt); - // Scan relocation type to determine if the GOT/PLT/Dynamic Relocation - // entries should be created. - if (rsym->isLocal()) // rsym is local - scanLocalReloc(pReloc, pLinker, pModule, pSection); - else // rsym is external - scanGlobalReloc(pReloc, pLinker, pModule, pSection); + // initialize .plt + LDSection& plt = file_format->getPLT(); + m_pPLT = new X86_32PLT(plt, + *m_pGOTPLT, + config()); - // check if we shoule issue undefined reference for the relocation target - // symbol - if (rsym->isUndef() && !rsym->isDyn() && !rsym->isWeak() && !rsym->isNull()) - fatal(diag::undefined_reference) << rsym->name(); + // initialize .rel.plt + LDSection& relplt = file_format->getRelPlt(); + relplt.setLink(&plt); + m_pRelPLT = new OutputRelocSection(pModule, relplt); + + // initialize .rel.dyn + LDSection& reldyn = file_format->getRelDyn(); + m_pRelDyn = new OutputRelocSection(pModule, reldyn); - if ((rsym->reserved() & ReserveRel) != 0x0) { - // set hasTextRelSection if needed - checkAndSetHasTextRel(pSection); } } -uint64_t X86GNULDBackend::emitSectionData(const LDSection& pSection, - MemoryRegion& pRegion) const +X86_32GOT& X86_32GNULDBackend::getGOT() { - assert(pRegion.size() && "Size of MemoryRegion is zero!"); - - const ELFFileFormat* FileFormat = getOutputFormat(); - assert(FileFormat && - "ELFFileFormat is NULL in X86GNULDBackend::emitSectionData!"); + assert(NULL != m_pGOT); + return *m_pGOT; +} - unsigned int EntrySize = 0; - uint64_t RegionSize = 0; +const X86_32GOT& X86_32GNULDBackend::getGOT() const +{ + assert(NULL != m_pGOT); + return *m_pGOT; +} - if (&pSection == &(FileFormat->getPLT())) { - assert(m_pPLT && "emitSectionData failed, m_pPLT is NULL!"); +X86_32GOTPLT& X86_32GNULDBackend::getGOTPLT() +{ + assert(NULL != m_pGOTPLT); + return *m_pGOTPLT; +} - unsigned char* buffer = pRegion.getBuffer(); +const X86_32GOTPLT& X86_32GNULDBackend::getGOTPLT() const +{ + assert(NULL != m_pGOTPLT); + return *m_pGOTPLT; +} - m_pPLT->applyPLT0(); - m_pPLT->applyPLT1(); - X86PLT::iterator it = m_pPLT->begin(); - unsigned int plt0_size = llvm::cast<PLTEntryBase>((*it)).size(); +void X86_32GNULDBackend::setRelDynSize() +{ + ELFFileFormat* file_format = getOutputFormat(); + file_format->getRelDyn().setSize + (m_pRelDyn->numOfRelocs() * getRelEntrySize()); +} - memcpy(buffer, llvm::cast<PLTEntryBase>((*it)).getValue(), plt0_size); - RegionSize += plt0_size; - ++it; +void X86_32GNULDBackend::setRelPLTSize() +{ + ELFFileFormat* file_format = getOutputFormat(); + file_format->getRelPlt().setSize + (m_pRelPLT->numOfRelocs() * getRelEntrySize()); +} - PLTEntryBase* plt1 = 0; - X86PLT::iterator ie = m_pPLT->end(); - while (it != ie) { - plt1 = &(llvm::cast<PLTEntryBase>(*it)); - EntrySize = plt1->size(); - memcpy(buffer + RegionSize, plt1->getValue(), EntrySize); - RegionSize += EntrySize; - ++it; - } +void X86_32GNULDBackend::setGOTSectionSize(IRBuilder& pBuilder) +{ + // set .got.plt size + if (LinkerConfig::DynObj == config().codeGenType() || + m_pGOTPLT->hasGOT1() || + NULL != m_pGOTSymbol) { + m_pGOTPLT->finalizeSectionSize(); + defineGOTSymbol(pBuilder, *(m_pGOTPLT->begin())); } - else if (&pSection == &(FileFormat->getGOT())) { - assert(m_pGOT && "emitSectionData failed, m_pGOT is NULL!"); + // set .got size + if (!m_pGOT->empty()) + m_pGOT->finalizeSectionSize(); +} - uint32_t* buffer = reinterpret_cast<uint32_t*>(pRegion.getBuffer()); +uint64_t X86_32GNULDBackend::emitGOTSectionData(MemoryRegion& pRegion) const +{ + assert(m_pGOT && "emitGOTSectionData failed, m_pGOT is NULL!"); - X86GOTEntry* got = 0; - EntrySize = X86GOTEntry::EntrySize; + uint32_t* buffer = reinterpret_cast<uint32_t*>(pRegion.getBuffer()); - for (X86GOT::iterator it = m_pGOT->begin(), - ie = m_pGOT->end(); it != ie; ++it, ++buffer) { - got = &(llvm::cast<X86GOTEntry>((*it))); - *buffer = static_cast<uint32_t>(got->getValue()); - RegionSize += EntrySize; - } + X86_32GOTEntry* got = 0; + unsigned int EntrySize = X86_32GOTEntry::EntrySize; + uint64_t RegionSize = 0; + + for (X86_32GOT::iterator it = m_pGOT->begin(), + ie = m_pGOT->end(); it != ie; ++it, ++buffer) { + got = &(llvm::cast<X86_32GOTEntry>((*it))); + *buffer = static_cast<uint32_t>(got->getValue()); + RegionSize += EntrySize; } - else if (&pSection == &(FileFormat->getGOTPLT())) { - assert(m_pGOTPLT && "emitSectionData failed, m_pGOTPLT is NULL!"); - m_pGOTPLT->applyGOT0(FileFormat->getDynamic().addr()); - m_pGOTPLT->applyAllGOTPLT(*m_pPLT); + return RegionSize; +} - uint32_t* buffer = reinterpret_cast<uint32_t*>(pRegion.getBuffer()); +uint64_t X86_32GNULDBackend::emitGOTPLTSectionData(MemoryRegion& pRegion, + const ELFFileFormat* FileFormat) const +{ + assert(m_pGOTPLT && "emitGOTPLTSectionData failed, m_pGOTPLT is NULL!"); + m_pGOTPLT->applyGOT0(FileFormat->getDynamic().addr()); + m_pGOTPLT->applyAllGOTPLT(*m_pPLT); - X86GOTEntry* got = 0; - EntrySize = X86GOTPLTEntry::EntrySize; + uint32_t* buffer = reinterpret_cast<uint32_t*>(pRegion.getBuffer()); - for (X86GOTPLT::iterator it = m_pGOTPLT->begin(), - ie = m_pGOTPLT->end(); it != ie; ++it, ++buffer) { - got = &(llvm::cast<X86GOTEntry>((*it))); - *buffer = static_cast<uint32_t>(got->getValue()); - RegionSize += EntrySize; + X86_32GOTEntry* got = 0; + unsigned int EntrySize = X86_32GOTEntry::EntrySize; + uint64_t RegionSize = 0; + + for (X86_32GOTPLT::iterator it = m_pGOTPLT->begin(), + ie = m_pGOTPLT->end(); it != ie; ++it, ++buffer) { + got = &(llvm::cast<X86_32GOTEntry>((*it))); + *buffer = static_cast<uint32_t>(got->getValue()); + RegionSize += EntrySize; + } + + return RegionSize; +} + +/// convert R_386_TLS_IE to R_386_TLS_LE +void X86_32GNULDBackend::convertTLSIEtoLE(Relocation& pReloc, + LDSection& pSection) +{ + assert(pReloc.type() == llvm::ELF::R_386_TLS_IE); + assert(NULL != pReloc.targetRef().frag()); + + // 1. create the fragment references and new relocs + uint64_t off = pReloc.targetRef().offset(); + if (off >= 4) + off -= 4; + else + off = 0; + + FragmentRef* fragref = FragmentRef::Create(*pReloc.targetRef().frag(), off); + // TODO: add symbols for R_386_TLS_OPT relocs + Relocation* reloc = Relocation::Create(X86_32Relocator::R_386_TLS_OPT, + *fragref, + 0x0); + + // 2. modify the opcodes to the appropriate ones + uint8_t* op = (reinterpret_cast<uint8_t*>(&reloc->target())); + off = pReloc.targetRef().offset() - reloc->targetRef().offset() - 1; + if (op[off] == 0xa1) { + op[off] = 0xb8; + } else { + switch (op[off - 1]) { + case 0x8b: + assert((op[off] & 0xc7) == 0x05); + op[off - 1] = 0xc7; + op[off] = 0xc0 | ((op[off] >> 3) & 7); + break; + case 0x03: + assert((op[off] & 0xc7) == 0x05); + op[off - 1] = 0x81; + op[off] = 0xc0 | ((op[off] >> 3) & 7); + break; + default: + assert(0); + break; } } - else { - fatal(diag::unrecognized_output_sectoin) - << pSection.name() - << "mclinker@googlegroups.com"; + // 3. insert the new relocs "BEFORE" the original reloc. + pSection.getRelocData()->getRelocationList().insert( + RelocData::iterator(pReloc), reloc); + + // 4. change the type of the original reloc + pReloc.setType(llvm::ELF::R_386_TLS_LE); +} + +// Create a GOT entry for the TLS module index +X86_32GOTEntry& X86_32GNULDBackend::getTLSModuleID() +{ + static X86_32GOTEntry* got_entry = NULL; + if (NULL != got_entry) + return *got_entry; + + // Allocate 2 got entries and 1 dynamic reloc for R_386_TLS_LDM + m_pGOT->reserve(2); + got_entry = m_pGOT->consume(); + m_pGOT->consume()->setValue(0x0); + + m_pRelDyn->reserveEntry(); + Relocation* rel_entry = m_pRelDyn->consumeEntry(); + rel_entry->setType(llvm::ELF::R_386_TLS_DTPMOD32); + rel_entry->targetRef().assign(*got_entry, 0x0); + rel_entry->setSymInfo(NULL); + + return *got_entry; +} + +X86_64GNULDBackend::X86_64GNULDBackend(const LinkerConfig& pConfig, + GNUInfo* pInfo) + : X86GNULDBackend(pConfig, pInfo, llvm::ELF::R_X86_64_COPY), + m_pGOT (NULL), + m_pGOTPLT (NULL) { +} + +X86_64GNULDBackend::~X86_64GNULDBackend() +{ + delete m_pGOT; + delete m_pGOTPLT; +} + +bool X86_64GNULDBackend::initRelocator() +{ + if (NULL == m_pRelocator) { + m_pRelocator = new X86_64Relocator(*this); } - return RegionSize; + return true; } -X86GOT& X86GNULDBackend::getGOT() +X86_64GOT& X86_64GNULDBackend::getGOT() { assert(NULL != m_pGOT); return *m_pGOT; } -const X86GOT& X86GNULDBackend::getGOT() const +const X86_64GOT& X86_64GNULDBackend::getGOT() const { assert(NULL != m_pGOT); return *m_pGOT; } -X86GOTPLT& X86GNULDBackend::getGOTPLT() +X86_64GOTPLT& X86_64GNULDBackend::getGOTPLT() { assert(NULL != m_pGOTPLT); return *m_pGOTPLT; } -const X86GOTPLT& X86GNULDBackend::getGOTPLT() const +const X86_64GOTPLT& X86_64GNULDBackend::getGOTPLT() const { assert(NULL != m_pGOTPLT); return *m_pGOTPLT; } -X86PLT& X86GNULDBackend::getPLT() +void X86_64GNULDBackend::setRelDynSize() { - assert(NULL != m_pPLT && "PLT section not exist"); - return *m_pPLT; + ELFFileFormat* file_format = getOutputFormat(); + file_format->getRelaDyn().setSize + (m_pRelDyn->numOfRelocs() * getRelaEntrySize()); } -const X86PLT& X86GNULDBackend::getPLT() const +void X86_64GNULDBackend::setRelPLTSize() { - assert(NULL != m_pPLT && "PLT section not exist"); - return *m_pPLT; + ELFFileFormat* file_format = getOutputFormat(); + file_format->getRelaPlt().setSize + (m_pRelPLT->numOfRelocs() * getRelaEntrySize()); } -OutputRelocSection& X86GNULDBackend::getRelDyn() +void X86_64GNULDBackend::scanLocalReloc(Relocation& pReloc, + IRBuilder& pBuilder, + Module& pModule, + LDSection& pSection) { - assert(NULL != m_pRelDyn && ".rel.dyn section not exist"); - return *m_pRelDyn; -} + // rsym - The relocation target symbol + ResolveInfo* rsym = pReloc.symInfo(); -const OutputRelocSection& X86GNULDBackend::getRelDyn() const -{ - assert(NULL != m_pRelDyn && ".rel.dyn section not exist"); - return *m_pRelDyn; -} + switch(pReloc.type()){ + case llvm::ELF::R_X86_64_64: + case llvm::ELF::R_X86_64_32: + case llvm::ELF::R_X86_64_16: + case llvm::ELF::R_X86_64_8: + case llvm::ELF::R_X86_64_32S: + // If buiding PIC object (shared library or PIC executable), + // a dynamic relocations with RELATIVE type to this location is needed. + // Reserve an entry in .rela.dyn + if (config().isCodeIndep()) { + m_pRelDyn->reserveEntry(); + // set Rel bit + rsym->setReserved(rsym->reserved() | ReserveRel); + checkAndSetHasTextRel(*pSection.getLink()); + } + return; -// Create a GOT entry for the TLS module index -X86GOTEntry& X86GNULDBackend::getTLSModuleID() -{ - static X86GOTEntry* got_entry = NULL; - if (NULL != got_entry) - return *got_entry; + case llvm::ELF::R_X86_64_PC32: + case llvm::ELF::R_X86_64_PC16: + case llvm::ELF::R_X86_64_PC8: + return; - // Allocate 2 got entries and 1 dynamic reloc for R_386_TLS_LDM - m_pGOT->reserve(2); - got_entry = m_pGOT->consume(); - m_pGOT->consume()->setValue(0x0); + case llvm::ELF::R_X86_64_GOTPCREL: + // Symbol needs GOT entry, reserve entry in .got + // return if we already create GOT for this symbol + if (rsym->reserved() & (ReserveGOT | GOTRel)) + return; + m_pGOT->reserve(); - m_pRelDyn->reserveEntry(); - Relocation* rel_entry = m_pRelDyn->consumeEntry(); - rel_entry->setType(llvm::ELF::R_386_TLS_DTPMOD32); - rel_entry->targetRef().assign(*got_entry, 0x0); - rel_entry->setSymInfo(NULL); + // If the GOT is used in statically linked binaries, + // the GOT entry is enough and no relocation is needed. + if (config().isCodeStatic()) { + rsym->setReserved(rsym->reserved() | ReserveGOT); + return; + } + // If building shared object or the symbol is undefined, a dynamic + // relocation is needed to relocate this GOT entry. Reserve an + // entry in .rela.dyn + if (LinkerConfig::DynObj == + config().codeGenType() || rsym->isUndef() || rsym->isDyn()) { + m_pRelDyn->reserveEntry(); + // set GOTRel bit + rsym->setReserved(rsym->reserved() | GOTRel); + return; + } + // set GOT bit + rsym->setReserved(rsym->reserved() | ReserveGOT); + return; - return *got_entry; + default: + fatal(diag::unsupported_relocation) << (int)pReloc.type() + << "mclinker@googlegroups.com"; + break; + } // end switch } -OutputRelocSection& X86GNULDBackend::getRelPLT() +void X86_64GNULDBackend::scanGlobalReloc(Relocation& pReloc, + IRBuilder& pBuilder, + Module& pModule, + LDSection& pSection) { - assert(NULL != m_pRelPLT && ".rel.plt section not exist"); - return *m_pRelPLT; -} + // rsym - The relocation target symbol + ResolveInfo* rsym = pReloc.symInfo(); -const OutputRelocSection& X86GNULDBackend::getRelPLT() const -{ - assert(NULL != m_pRelPLT && ".rel.plt section not exist"); - return *m_pRelPLT; -} + switch(pReloc.type()) { + case llvm::ELF::R_X86_64_64: + case llvm::ELF::R_X86_64_32: + case llvm::ELF::R_X86_64_16: + case llvm::ELF::R_X86_64_8: + case llvm::ELF::R_X86_64_32S: + // Absolute relocation type, symbol may needs PLT entry or + // dynamic relocation entry + if (symbolNeedsPLT(*rsym)) { + // create plt for this symbol if it does not have one + if (!(rsym->reserved() & ReservePLT)){ + // Symbol needs PLT entry, we need to reserve a PLT entry + // and the corresponding GOT and dynamic relocation entry + // in .got and .rela.plt. (GOT entry will be reserved simultaneously + // when calling X86PLT->reserveEntry()) + m_pPLT->reserveEntry(); + m_pGOTPLT->reserve(); + m_pRelPLT->reserveEntry(); + // set PLT bit + rsym->setReserved(rsym->reserved() | ReservePLT); + } + } -unsigned int -X86GNULDBackend::getTargetSectionOrder(const LDSection& pSectHdr) const -{ - const ELFFileFormat* file_format = getOutputFormat(); + if (symbolNeedsDynRel(*rsym, (rsym->reserved() & ReservePLT), true)) { + // symbol needs dynamic relocation entry, reserve an entry in .rela.dyn + m_pRelDyn->reserveEntry(); + if (symbolNeedsCopyReloc(pReloc, *rsym)) { + LDSymbol& cpy_sym = defineSymbolforCopyReloc(pBuilder, *rsym); + addCopyReloc(*cpy_sym.resolveInfo()); + } + else { + // set Rel bit + rsym->setReserved(rsym->reserved() | ReserveRel); + checkAndSetHasTextRel(*pSection.getLink()); + } + } + return; - if (&pSectHdr == &file_format->getGOT()) { - if (config().options().hasNow()) - return SHO_RELRO; - return SHO_RELRO_LAST; - } + case llvm::ELF::R_X86_64_GOTPCREL: + // Symbol needs GOT entry, reserve entry in .got + // return if we already create GOT for this symbol + if (rsym->reserved() & (ReserveGOT | GOTRel)) + return; + m_pGOT->reserve(); - if (&pSectHdr == &file_format->getGOTPLT()) { - if (config().options().hasNow()) - return SHO_RELRO; - return SHO_NON_RELRO_FIRST; - } + // If the GOT is used in statically linked binaries, + // the GOT entry is enough and no relocation is needed. + if (config().isCodeStatic()) { + rsym->setReserved(rsym->reserved() | ReserveGOT); + return; + } + // If building shared object or the symbol is undefined, a dynamic + // relocation is needed to relocate this GOT entry. Reserve an + // entry in .rela.dyn + if (LinkerConfig::DynObj == + config().codeGenType() || rsym->isUndef() || rsym->isDyn()) { + m_pRelDyn->reserveEntry(); + // set GOTRel bit + rsym->setReserved(rsym->reserved() | GOTRel); + return; + } + // set GOT bit + rsym->setReserved(rsym->reserved() | ReserveGOT); + return; - if (&pSectHdr == &file_format->getPLT()) - return SHO_PLT; + case llvm::ELF::R_X86_64_PLT32: + // A PLT entry is needed when building shared library - return SHO_UNDEFINED; + // return if we already create plt for this symbol + if (rsym->reserved() & ReservePLT) + return; + + // if the symbol's value can be decided at link time, then no need plt + if (symbolFinalValueIsKnown(*rsym)) + return; + + // if symbol is defined in the ouput file and it's not + // preemptible, no need plt + if (rsym->isDefine() && !rsym->isDyn() && + !isSymbolPreemptible(*rsym)) { + return; + } + + // Symbol needs PLT entry, we need to reserve a PLT entry + // and the corresponding GOT and dynamic relocation entry + // in .got and .rel.plt. (GOT entry will be reserved simultaneously + // when calling X86PLT->reserveEntry()) + m_pPLT->reserveEntry(); + m_pGOTPLT->reserve(); + m_pRelPLT->reserveEntry(); + // set PLT bit + rsym->setReserved(rsym->reserved() | ReservePLT); + return; + + case llvm::ELF::R_X86_64_PC32: + case llvm::ELF::R_X86_64_PC16: + case llvm::ELF::R_X86_64_PC8: + if (symbolNeedsPLT(*rsym) && + LinkerConfig::DynObj != config().codeGenType()) { + // create plt for this symbol if it does not have one + if (!(rsym->reserved() & ReservePLT)){ + // Symbol needs PLT entry, we need to reserve a PLT entry + // and the corresponding GOT and dynamic relocation entry + // in .got and .rel.plt. (GOT entry will be reserved simultaneously + // when calling X86PLT->reserveEntry()) + m_pPLT->reserveEntry(); + m_pGOTPLT->reserve(); + m_pRelPLT->reserveEntry(); + // set PLT bit + rsym->setReserved(rsym->reserved() | ReservePLT); + } + } + + // Only PC relative relocation against dynamic symbol needs a + // dynamic relocation. Only dynamic copy relocation is allowed + // and PC relative relocation will be resolved to the local copy. + // All other dynamic relocations may lead to run-time relocation + // overflow. + if (isDynamicSymbol(*rsym) && + symbolNeedsDynRel(*rsym, (rsym->reserved() & ReservePLT), false) && + symbolNeedsCopyReloc(pReloc, *rsym)) { + m_pRelDyn->reserveEntry(); + LDSymbol& cpy_sym = defineSymbolforCopyReloc(pBuilder, *rsym); + addCopyReloc(*cpy_sym.resolveInfo()); + } + return; + + default: + fatal(diag::unsupported_relocation) << (int)pReloc.type() + << "mclinker@googlegroups.com"; + break; + } // end switch } -void X86GNULDBackend::initTargetSections(Module& pModule, ObjectBuilder& pBuilder) +void X86_64GNULDBackend::initTargetSections(Module& pModule, + ObjectBuilder& pBuilder) { if (LinkerConfig::Object != config().codeGenType()) { ELFFileFormat* file_format = getOutputFormat(); // initialize .got LDSection& got = file_format->getGOT(); - m_pGOT = new X86GOT(got); + m_pGOT = new X86_64GOT(got); // initialize .got.plt LDSection& gotplt = file_format->getGOTPLT(); - m_pGOTPLT = new X86GOTPLT(gotplt); + m_pGOTPLT = new X86_64GOTPLT(gotplt); // initialize .plt LDSection& plt = file_format->getPLT(); - m_pPLT = new X86PLT(plt, - *m_pGOTPLT, - config()); + m_pPLT = new X86_64PLT(plt, + *m_pGOTPLT, + config()); - // initialize .rel.plt - LDSection& relplt = file_format->getRelPlt(); + // initialize .rela.plt + LDSection& relplt = file_format->getRelaPlt(); relplt.setLink(&plt); m_pRelPLT = new OutputRelocSection(pModule, relplt); - // initialize .rel.dyn - LDSection& reldyn = file_format->getRelDyn(); + // initialize .rela.dyn + LDSection& reldyn = file_format->getRelaDyn(); m_pRelDyn = new OutputRelocSection(pModule, reldyn); } } -void X86GNULDBackend::initTargetSymbols(FragmentLinker& pLinker) +void X86_64GNULDBackend::setGOTSectionSize(IRBuilder& pBuilder) { - if (LinkerConfig::Object != config().codeGenType()) { - // Define the symbol _GLOBAL_OFFSET_TABLE_ if there is a symbol with the - // same name in input - m_pGOTSymbol = - pLinker.defineSymbol<FragmentLinker::AsRefered, - FragmentLinker::Resolve>("_GLOBAL_OFFSET_TABLE_", - false, - ResolveInfo::Object, - ResolveInfo::Define, - ResolveInfo::Local, - 0x0, // size - 0x0, // value - FragmentRef::Null(), // FragRef - ResolveInfo::Hidden); + // set .got.plt size + if (LinkerConfig::DynObj == config().codeGenType() || + m_pGOTPLT->hasGOT1() || + NULL != m_pGOTSymbol) { + m_pGOTPLT->finalizeSectionSize(); + defineGOTSymbol(pBuilder, *(m_pGOTPLT->begin())); } + + // set .got size + if (!m_pGOT->empty()) + m_pGOT->finalizeSectionSize(); } -/// finalizeSymbol - finalize the symbol value -bool X86GNULDBackend::finalizeTargetSymbols(FragmentLinker& pLinker) +uint64_t X86_64GNULDBackend::emitGOTSectionData(MemoryRegion& pRegion) const { - return true; + assert(m_pGOT && "emitGOTSectionData failed, m_pGOT is NULL!"); + + uint64_t* buffer = reinterpret_cast<uint64_t*>(pRegion.getBuffer()); + + X86_64GOTEntry* got = 0; + unsigned int EntrySize = X86_64GOTEntry::EntrySize; + uint64_t RegionSize = 0; + + for (X86_64GOT::iterator it = m_pGOT->begin(), + ie = m_pGOT->end(); it != ie; ++it, ++buffer) { + got = &(llvm::cast<X86_64GOTEntry>((*it))); + *buffer = static_cast<uint64_t>(got->getValue()); + RegionSize += EntrySize; + } + + return RegionSize; } -/// doCreateProgramHdrs - backend can implement this function to create the -/// target-dependent segments -void X86GNULDBackend::doCreateProgramHdrs(Module& pModule, - const FragmentLinker& pLinker) +uint64_t X86_64GNULDBackend::emitGOTPLTSectionData(MemoryRegion& pRegion, + const ELFFileFormat* FileFormat) const { - // TODO + assert(m_pGOTPLT && "emitGOTPLTSectionData failed, m_pGOTPLT is NULL!"); + m_pGOTPLT->applyGOT0(FileFormat->getDynamic().addr()); + m_pGOTPLT->applyAllGOTPLT(*m_pPLT); + + uint64_t* buffer = reinterpret_cast<uint64_t*>(pRegion.getBuffer()); + + X86_64GOTEntry* got = 0; + unsigned int EntrySize = X86_64GOTEntry::EntrySize; + uint64_t RegionSize = 0; + + for (X86_64GOTPLT::iterator it = m_pGOTPLT->begin(), + ie = m_pGOTPLT->end(); it != ie; ++it, ++buffer) { + got = &(llvm::cast<X86_64GOTEntry>((*it))); + *buffer = static_cast<uint64_t>(got->getValue()); + RegionSize += EntrySize; + } + + return RegionSize; } namespace mcld { @@ -862,7 +1357,13 @@ TargetLDBackend* createX86LDBackend(const llvm::Target& pTarget, createX86COFFObjectWriter); **/ } - return new X86GNULDBackend(pConfig, new X86GNUInfo(pConfig.targets().triple())); + Triple::ArchType arch = pConfig.targets().triple().getArch(); + if (arch == Triple::x86) + return new X86_32GNULDBackend(pConfig, + new X86_32GNUInfo(pConfig.targets().triple())); + assert (arch == Triple::x86_64); + return new X86_64GNULDBackend(pConfig, + new X86_64GNUInfo(pConfig.targets().triple())); } } // namespace of mcld @@ -872,5 +1373,6 @@ TargetLDBackend* createX86LDBackend(const llvm::Target& pTarget, //===----------------------------------------------------------------------===// extern "C" void MCLDInitializeX86LDBackend() { // Register the linker backend - mcld::TargetRegistry::RegisterTargetLDBackend(TheX86Target, createX86LDBackend); + mcld::TargetRegistry::RegisterTargetLDBackend(TheX86_32Target, createX86LDBackend); + mcld::TargetRegistry::RegisterTargetLDBackend(TheX86_64Target, createX86LDBackend); } diff --git a/lib/Target/X86/X86LDBackend.h b/lib/Target/X86/X86LDBackend.h index 3f8a626..a008d00 100644 --- a/lib/Target/X86/X86LDBackend.h +++ b/lib/Target/X86/X86LDBackend.h @@ -20,7 +20,7 @@ namespace mcld { class LinkerConfig; -class X86GNUInfo; +class GNUInfo; //===----------------------------------------------------------------------===// /// X86GNULDBackend - linker backend of X86 target of GNU ELF format @@ -72,31 +72,23 @@ public: }; public: - X86GNULDBackend(const LinkerConfig& pConfig, X86GNUInfo* pInfo); + X86GNULDBackend(const LinkerConfig& pConfig, + GNUInfo* pInfo, + Relocation::Type pCopyRel); ~X86GNULDBackend(); uint32_t machine() const; - X86GOT& getGOT(); - - const X86GOT& getGOT() const; - - X86GOTPLT& getGOTPLT(); - - const X86GOTPLT& getGOTPLT() const; - X86PLT& getPLT(); const X86PLT& getPLT() const; - X86GOTEntry& getTLSModuleID(); - /// preLayout - Backend can do any needed modification before layout - void doPreLayout(FragmentLinker& pLinker); + void doPreLayout(IRBuilder& pBuilder); /// postLayout -Backend can do any needed modification after layout - void doPostLayout(Module& pModule, FragmentLinker& pLinker); + void doPostLayout(Module& pModule, IRBuilder& pBuilder); /// dynamic - the dynamic section of the target machine. /// Use co-variant return type to return its own dynamic section. @@ -124,23 +116,15 @@ public: uint64_t emitSectionData(const LDSection& pSection, MemoryRegion& pRegion) const; - /// flags - the value of ElfXX_Ehdr::e_flags - /// FIXME - uint64_t flags() const - { return 0x0; } - - uint64_t defaultTextSegmentAddr() const - { return 0x08048000; } - /// initRelocator - create and initialize Relocator. - bool initRelocator(const FragmentLinker& pLinker); + virtual bool initRelocator() = 0; /// getRelocator - return relocator. Relocator* getRelocator(); - void initTargetSections(Module& pModule, ObjectBuilder& pBuilder); + virtual void initTargetSections(Module& pModule, ObjectBuilder& pBuilder) = 0; - void initTargetSymbols(FragmentLinker& pLinker); + void initTargetSymbols(IRBuilder& pBuilder, Module& pModule); /// scanRelocation - determine the empty entries are needed or not and create /// the empty entries if needed. @@ -149,9 +133,9 @@ public: /// - PLT entry (for .plt section) /// - dynamin relocation entries (for .rel.plt and .rel.dyn sections) void scanRelocation(Relocation& pReloc, - FragmentLinker& pLinker, + IRBuilder& pBuilder, Module& pModule, - const LDSection& pSection); + LDSection& pSection); OutputRelocSection& getRelDyn(); @@ -165,19 +149,24 @@ public: unsigned int getTargetSectionOrder(const LDSection& pSectHdr) const; /// finalizeTargetSymbols - finalize the symbol value - bool finalizeTargetSymbols(FragmentLinker& pLinker); + bool finalizeTargetSymbols(); + + /// getPointerRel - get pointer relocation type. + Relocation::Type getPointerRel() + { return m_PointerRel; } private: - void scanLocalReloc(Relocation& pReloc, - FragmentLinker& pLinker, - Module& pModule, - const LDSection& pSection); + virtual void scanLocalReloc(Relocation& pReloc, + IRBuilder& pBuilder, + Module& pModule, + LDSection& pSection) = 0; - void scanGlobalReloc(Relocation& pReloc, - FragmentLinker& pLinker, - Module& pModule, - const LDSection& pSection); + virtual void scanGlobalReloc(Relocation& pReloc, + IRBuilder& pBuilder, + Module& pModule, + LDSection& pSection) = 0; +protected: /// addCopyReloc - add a copy relocation into .rel.dyn for pSym /// @param pSym - A resolved copy symbol that defined in BSS section void addCopyReloc(ResolveInfo& pSym); @@ -185,29 +174,38 @@ private: /// defineSymbolforCopyReloc - allocate a space in BSS section and /// and force define the copy of pSym to BSS section /// @return the output LDSymbol of the copy symbol - LDSymbol& defineSymbolforCopyReloc(FragmentLinker& pLinker, + LDSymbol& defineSymbolforCopyReloc(IRBuilder& pLinker, const ResolveInfo& pSym); - void defineGOTSymbol(FragmentLinker& pLinker); + void defineGOTSymbol(IRBuilder& pBuilder, Fragment&); +protected: /// getRelEntrySize - the size in BYTE of rel type relocation size_t getRelEntrySize() - { return 8; } + { return m_RelEntrySize; } /// getRelEntrySize - the size in BYTE of rela type relocation size_t getRelaEntrySize() - { return 12; } + { return m_RelaEntrySize; } +private: /// doCreateProgramHdrs - backend can implement this function to create the /// target-dependent segments - virtual void doCreateProgramHdrs(Module& pModule, - const FragmentLinker& pLinker); + void doCreateProgramHdrs(Module& pModule); -private: + virtual void setGOTSectionSize(IRBuilder& pBuilder) = 0; + + virtual uint64_t emitGOTSectionData(MemoryRegion& pRegion) const = 0; + + virtual uint64_t emitGOTPLTSectionData(MemoryRegion& pRegion, + const ELFFileFormat* FileFormat) const = 0; + + virtual void setRelDynSize() = 0; + virtual void setRelPLTSize() = 0; + +protected: Relocator* m_pRelocator; - X86GOT* m_pGOT; X86PLT* m_pPLT; - X86GOTPLT* m_pGOTPLT; /// m_RelDyn - dynamic relocation table of .rel.dyn OutputRelocSection* m_pRelDyn; /// m_RelPLT - dynamic relocation table of .rel.plt @@ -215,25 +213,119 @@ private: X86ELFDynamic* m_pDynamic; LDSymbol* m_pGOTSymbol; + + size_t m_RelEntrySize; + size_t m_RelaEntrySize; + + Relocation::Type m_CopyRel; + Relocation::Type m_PointerRel; +}; + +// +//===----------------------------------------------------------------------===// +/// X86_32GNULDBackend - linker backend of X86-32 target of GNU ELF format +/// +class X86_32GNULDBackend : public X86GNULDBackend +{ +public: + X86_32GNULDBackend(const LinkerConfig& pConfig, GNUInfo* pInfo); + + ~X86_32GNULDBackend(); + + void initTargetSections(Module& pModule, ObjectBuilder& pBuilder); + + X86_32GOT& getGOT(); + + const X86_32GOT& getGOT() const; + + X86_32GOTPLT& getGOTPLT(); + + const X86_32GOTPLT& getGOTPLT() const; + + X86_32GOTEntry& getTLSModuleID(); + +private: + void scanLocalReloc(Relocation& pReloc, + IRBuilder& pBuilder, + Module& pModule, + LDSection& pSection); + + void scanGlobalReloc(Relocation& pReloc, + IRBuilder& pBuilder, + Module& pModule, + LDSection& pSection); + + /// initRelocator - create and initialize Relocator. + bool initRelocator(); + + /// ----- tls optimization ----- /// + /// convert R_386_TLS_IE to R_386_TLS_LE + void convertTLSIEtoLE(Relocation& pReloc, LDSection& pSection); + + void setGOTSectionSize(IRBuilder& pBuilder); + + uint64_t emitGOTSectionData(MemoryRegion& pRegion) const; + + uint64_t emitGOTPLTSectionData(MemoryRegion& pRegion, + const ELFFileFormat* FileFormat) const; + + void setRelDynSize(); + void setRelPLTSize(); + +private: + X86_32GOT* m_pGOT; + X86_32GOTPLT* m_pGOTPLT; }; +// //===----------------------------------------------------------------------===// -/// X86MachOLDBackend - linker backend of X86 target of MachO format +/// X86_64GNULDBackend - linker backend of X86-64 target of GNU ELF format /// -/** -class X86MachOLDBackend : public DarwinX86LDBackend +class X86_64GNULDBackend : public X86GNULDBackend { public: - X86MachOLDBackend(); - ~X86MachOLDBackend(); + X86_64GNULDBackend(const LinkerConfig& pConfig, GNUInfo* pInfo); + + ~X86_64GNULDBackend(); + + void initTargetSections(Module& pModule, ObjectBuilder& pBuilder); + + X86_64GOT& getGOT(); + + const X86_64GOT& getGOT() const; + + X86_64GOTPLT& getGOTPLT(); + + const X86_64GOTPLT& getGOTPLT() const; private: - MCMachOTargetArchiveReader *createTargetArchiveReader() const; - MCMachOTargetObjectReader *createTargetObjectReader() const; - MCMachOTargetObjectWriter *createTargetObjectWriter() const; + void scanLocalReloc(Relocation& pReloc, + IRBuilder& pBuilder, + Module& pModule, + LDSection& pSection); + + void scanGlobalReloc(Relocation& pReloc, + IRBuilder& pBuilder, + Module& pModule, + LDSection& pSection); + + /// initRelocator - create and initialize Relocator. + bool initRelocator(); + + void setGOTSectionSize(IRBuilder& pBuilder); + uint64_t emitGOTSectionData(MemoryRegion& pRegion) const; + + uint64_t emitGOTPLTSectionData(MemoryRegion& pRegion, + const ELFFileFormat* FileFormat) const; + + void setRelDynSize(); + void setRelPLTSize(); + +private: + X86_64GOT* m_pGOT; + X86_64GOTPLT* m_pGOTPLT; }; -**/ } // namespace of mcld #endif diff --git a/lib/Target/X86/X86MCLinker.cpp b/lib/Target/X86/X86MCLinker.cpp index e55add3..bad20a9 100644 --- a/lib/Target/X86/X86MCLinker.cpp +++ b/lib/Target/X86/X86MCLinker.cpp @@ -34,11 +34,7 @@ MCLinker* createX86MCLinker(const std::string &pTriple, return NULL; } - if (theTriple.isArch32Bit()) - return new X86ELFMCLinker(pConfig, pModule, pOutput); - - assert(0 && "X86_64 has not supported yet"); - return NULL; + return new X86ELFMCLinker(pConfig, pModule, pOutput); } } // namespace of mcld @@ -48,6 +44,7 @@ MCLinker* createX86MCLinker(const std::string &pTriple, //===----------------------------------------------------------------------===// extern "C" void MCLDInitializeX86MCLinker() { // Register the linker frontend - mcld::TargetRegistry::RegisterMCLinker(TheX86Target, createX86MCLinker); + mcld::TargetRegistry::RegisterMCLinker(TheX86_32Target, createX86MCLinker); + mcld::TargetRegistry::RegisterMCLinker(TheX86_64Target, createX86MCLinker); } diff --git a/lib/Target/X86/X86PLT.cpp b/lib/Target/X86/X86PLT.cpp index 25eaab9..669a047 100644 --- a/lib/Target/X86/X86PLT.cpp +++ b/lib/Target/X86/X86PLT.cpp @@ -21,23 +21,33 @@ using namespace mcld; //===----------------------------------------------------------------------===// // PLT entry data //===----------------------------------------------------------------------===// -X86DynPLT0::X86DynPLT0(SectionData& pParent) - : PLT::Entry<sizeof(x86_dyn_plt0)>(pParent) +X86_32DynPLT0::X86_32DynPLT0(SectionData& pParent) + : PLT::Entry<sizeof(x86_32_dyn_plt0)>(pParent) { } -X86DynPLT1::X86DynPLT1(SectionData& pParent) - : PLT::Entry<sizeof(x86_dyn_plt1)>(pParent) +X86_32DynPLT1::X86_32DynPLT1(SectionData& pParent) + : PLT::Entry<sizeof(x86_32_dyn_plt1)>(pParent) { } -X86ExecPLT0::X86ExecPLT0(SectionData& pParent) - : PLT::Entry<sizeof(x86_exec_plt0)>(pParent) +X86_32ExecPLT0::X86_32ExecPLT0(SectionData& pParent) + : PLT::Entry<sizeof(x86_32_exec_plt0)>(pParent) { } -X86ExecPLT1::X86ExecPLT1(SectionData& pParent) - : PLT::Entry<sizeof(x86_exec_plt1)>(pParent) +X86_32ExecPLT1::X86_32ExecPLT1(SectionData& pParent) + : PLT::Entry<sizeof(x86_32_exec_plt1)>(pParent) +{ +} + +X86_64PLT0::X86_64PLT0(SectionData& pParent) + : PLT::Entry<sizeof(x86_64_plt0)>(pParent) +{ +} + +X86_64PLT1::X86_64PLT1(SectionData& pParent) + : PLT::Entry<sizeof(x86_64_plt1)>(pParent) { } @@ -45,31 +55,42 @@ X86ExecPLT1::X86ExecPLT1(SectionData& pParent) // X86PLT //===----------------------------------------------------------------------===// X86PLT::X86PLT(LDSection& pSection, - X86GOTPLT &pGOTPLT, - const LinkerConfig& pConfig) + const LinkerConfig& pConfig, + int got_size) : PLT(pSection), - m_GOTPLT(pGOTPLT), m_Config(pConfig) { assert(LinkerConfig::DynObj == m_Config.codeGenType() || LinkerConfig::Exec == m_Config.codeGenType() || LinkerConfig::Binary == m_Config.codeGenType()); - if (LinkerConfig::DynObj == m_Config.codeGenType()) { - m_PLT0 = x86_dyn_plt0; - m_PLT1 = x86_dyn_plt1; - m_PLT0Size = sizeof (x86_dyn_plt0); - m_PLT1Size = sizeof (x86_dyn_plt1); - // create PLT0 - new X86DynPLT0(*m_SectionData); + if (got_size == 32) { + if (LinkerConfig::DynObj == m_Config.codeGenType()) { + m_PLT0 = x86_32_dyn_plt0; + m_PLT1 = x86_32_dyn_plt1; + m_PLT0Size = sizeof (x86_32_dyn_plt0); + m_PLT1Size = sizeof (x86_32_dyn_plt1); + // create PLT0 + new X86_32DynPLT0(*m_SectionData); + } + else { + m_PLT0 = x86_32_exec_plt0; + m_PLT1 = x86_32_exec_plt1; + m_PLT0Size = sizeof (x86_32_exec_plt0); + m_PLT1Size = sizeof (x86_32_exec_plt1); + // create PLT0 + new X86_32ExecPLT0(*m_SectionData); + } } else { - m_PLT0 = x86_exec_plt0; - m_PLT1 = x86_exec_plt1; - m_PLT0Size = sizeof (x86_exec_plt0); - m_PLT1Size = sizeof (x86_exec_plt1); + assert(got_size == 64); + m_PLT0 = x86_64_plt0; + m_PLT1 = x86_64_plt1; + m_PLT0Size = sizeof (x86_64_plt0); + m_PLT1Size = sizeof (x86_64_plt1); // create PLT0 - new X86ExecPLT0(*m_SectionData); + new X86_64PLT0(*m_SectionData); + m_Last = m_SectionData->begin(); } m_Last = m_SectionData->begin(); } @@ -114,9 +135,9 @@ void X86PLT::reserveEntry(size_t pNum) for (size_t i = 0; i < pNum; ++i) { if (LinkerConfig::DynObj == m_Config.codeGenType()) - plt1_entry = new X86DynPLT1(*m_SectionData); + plt1_entry = new X86_32DynPLT1(*m_SectionData); else - plt1_entry = new X86ExecPLT1(*m_SectionData); + plt1_entry = new X86_32ExecPLT1(*m_SectionData); if (NULL == plt1_entry) fatal(diag::fail_allocate_memory_plt); @@ -144,8 +165,18 @@ PLTEntryBase* X86PLT::getPLT0() const return plt0; } +//===----------------------------------------------------------------------===// +// X86_32PLT +//===----------------------------------------------------------------------===// +X86_32PLT::X86_32PLT(LDSection& pSection, + X86_32GOTPLT& pGOTPLT, + const LinkerConfig& pConfig) + : X86PLT(pSection, pConfig, 32), + m_GOTPLT(pGOTPLT) { +} + // FIXME: It only works on little endian machine. -void X86PLT::applyPLT0() +void X86_32PLT::applyPLT0() { PLTEntryBase* plt0 = getPLT0(); @@ -157,7 +188,7 @@ void X86PLT::applyPLT0() memcpy(data, m_PLT0, plt0->size()); - if (m_PLT0 == x86_exec_plt0) { + if (m_PLT0 == x86_32_exec_plt0) { uint32_t *offset = reinterpret_cast<uint32_t*>(data + 2); *offset = m_GOTPLT.addr() + 4; offset = reinterpret_cast<uint32_t*>(data + 8); @@ -168,7 +199,7 @@ void X86PLT::applyPLT0() } // FIXME: It only works on little endian machine. -void X86PLT::applyPLT1() +void X86_32PLT::applyPLT1() { assert(m_Section.addr() && ".plt base address is NULL!"); @@ -176,7 +207,7 @@ void X86PLT::applyPLT1() X86PLT::iterator ie = m_SectionData->end(); assert(it != ie && "FragmentList is empty, applyPLT1 failed!"); - uint64_t GOTEntrySize = X86GOTPLTEntry::EntrySize; + uint64_t GOTEntrySize = X86_32GOTEntry::EntrySize; // Skip GOT0 uint64_t GOTEntryOffset = GOTEntrySize * X86GOTPLT0Num; @@ -220,3 +251,96 @@ void X86PLT::applyPLT1() } } +//===----------------------------------------------------------------------===// +// X86_64PLT +//===----------------------------------------------------------------------===// +X86_64PLT::X86_64PLT(LDSection& pSection, + X86_64GOTPLT& pGOTPLT, + const LinkerConfig& pConfig) + : X86PLT(pSection, pConfig, 64), + m_GOTPLT(pGOTPLT) { +} + +// FIXME: It only works on little endian machine. +void X86_64PLT::applyPLT0() +{ + PLTEntryBase* plt0 = getPLT0(); + + unsigned char* data = 0; + data = static_cast<unsigned char*>(malloc(plt0->size())); + + if (!data) + fatal(diag::fail_allocate_memory_plt); + + memcpy(data, m_PLT0, plt0->size()); + + // pushq GOT + 8(%rip) + uint32_t *offset = reinterpret_cast<uint32_t*>(data + 2); + *offset = m_GOTPLT.addr() - addr() + 8 - 6; + // jmq *GOT + 16(%rip) + offset = reinterpret_cast<uint32_t*>(data + 8); + *offset = m_GOTPLT.addr() - addr() + 16 - 12; + + plt0->setValue(data); +} + +// FIXME: It only works on little endian machine. +void X86_64PLT::applyPLT1() +{ + assert(m_Section.addr() && ".plt base address is NULL!"); + + X86PLT::iterator it = m_SectionData->begin(); + X86PLT::iterator ie = m_SectionData->end(); + assert(it != ie && "FragmentList is empty, applyPLT1 failed!"); + + uint64_t GOTEntrySize = X86_64GOTEntry::EntrySize; + + // compute sym@GOTPCREL of the PLT1 entry. + uint64_t SymGOTPCREL = m_GOTPLT.addr(); + + // Skip GOT0 + SymGOTPCREL += GOTEntrySize * X86GOTPLT0Num; + + // skip PLT0 + uint64_t PLTEntryOffset = m_PLT0Size; + ++it; + + // PC-relative to entry in PLT section. + SymGOTPCREL -= addr() + PLTEntryOffset + 6; + + PLTEntryBase* plt1 = 0; + + uint64_t PLTRelIndex = 0; + + while (it != ie) { + plt1 = &(llvm::cast<PLTEntryBase>(*it)); + unsigned char *data; + data = static_cast<unsigned char*>(malloc(plt1->size())); + + if (!data) + fatal(diag::fail_allocate_memory_plt); + + memcpy(data, m_PLT1, plt1->size()); + + uint32_t* offset; + + // jmpq *sym@GOTPCREL(%rip) + offset = reinterpret_cast<uint32_t*>(data + 2); + *offset = SymGOTPCREL; + SymGOTPCREL += GOTEntrySize - m_PLT1Size; + + // pushq $index + offset = reinterpret_cast<uint32_t*>(data + 7); + *offset = PLTRelIndex; + PLTRelIndex++; + + // jmpq plt0 + offset = reinterpret_cast<uint32_t*>(data + 12); + *offset = -(PLTEntryOffset + 12 + 4); + PLTEntryOffset += m_PLT1Size; + + plt1->setValue(data); + ++it; + } +} + diff --git a/lib/Target/X86/X86PLT.h b/lib/Target/X86/X86PLT.h index 75a72e6..2f4176c 100644 --- a/lib/Target/X86/X86PLT.h +++ b/lib/Target/X86/X86PLT.h @@ -13,63 +13,90 @@ namespace { -const uint8_t x86_dyn_plt0[] = { +const uint8_t x86_32_dyn_plt0[] = { 0xff, 0xb3, 0x04, 0, 0, 0, // pushl 0x4(%ebx) 0xff, 0xa3, 0x08, 0, 0, 0, // jmp *0x8(%ebx) 0x0f, 0x1f, 0x4, 0 // nopl 0(%eax) }; -const uint8_t x86_dyn_plt1[] = { +const uint8_t x86_32_dyn_plt1[] = { 0xff, 0xa3, 0, 0, 0, 0, // jmp *sym@GOT(%ebx) 0x68, 0, 0, 0, 0, // pushl $offset 0xe9, 0, 0, 0, 0 // jmp plt0 }; -const uint8_t x86_exec_plt0[] = { +const uint8_t x86_32_exec_plt0[] = { 0xff, 0x35, 0, 0, 0, 0, // pushl .got + 4 0xff, 0x25, 0, 0, 0, 0, // jmp *(.got + 8) 0x0f, 0x1f, 0x4, 0 // nopl 0(%eax) }; -const uint8_t x86_exec_plt1[] = { +const uint8_t x86_32_exec_plt1[] = { 0xff, 0x25, 0, 0, 0, 0, // jmp *(sym in .got) 0x68, 0, 0, 0, 0, // pushl $offset 0xe9, 0, 0, 0, 0 // jmp plt0 }; +const uint8_t x86_64_plt0[] = { + 0xff, 0x35, 0x8, 0, 0, 0, // pushq GOT + 8(%rip) + 0xff, 0x25, 0x16, 0, 0, 0, // jmq *GOT + 16(%rip) + 0x0f, 0x1f, 0x40, 0 // nopl 0(%rax) +}; + +const uint8_t x86_64_plt1[] = { + 0xff, 0x25, 0, 0, 0, 0, // jmpq *sym@GOTPCREL(%rip) + 0x68, 0, 0, 0, 0, // pushq $index + 0xe9, 0, 0, 0, 0 // jmpq plt0 +}; + } // anonymous namespace namespace mcld { -class X86GOTPLT; +class X86_32GOTPLT; class GOTEntry; class LinkerConfig; //===----------------------------------------------------------------------===// -// X86PLT Entry +// X86_32PLT Entry //===----------------------------------------------------------------------===// -class X86DynPLT0 : public PLT::Entry<sizeof(x86_dyn_plt0)> +class X86_32DynPLT0 : public PLT::Entry<sizeof(x86_32_dyn_plt0)> { public: - X86DynPLT0(SectionData& pParent); + X86_32DynPLT0(SectionData& pParent); }; -class X86DynPLT1 : public PLT::Entry<sizeof(x86_dyn_plt1)> +class X86_32DynPLT1 : public PLT::Entry<sizeof(x86_32_dyn_plt1)> { public: - X86DynPLT1(SectionData& pParent); + X86_32DynPLT1(SectionData& pParent); }; -class X86ExecPLT0 : public PLT::Entry<sizeof(x86_exec_plt0)> +class X86_32ExecPLT0 : public PLT::Entry<sizeof(x86_32_exec_plt0)> { public: - X86ExecPLT0(SectionData& pParent); + X86_32ExecPLT0(SectionData& pParent); }; -class X86ExecPLT1 : public PLT::Entry<sizeof(x86_exec_plt1)> +class X86_32ExecPLT1 : public PLT::Entry<sizeof(x86_32_exec_plt1)> { public: - X86ExecPLT1(SectionData& pParent); + X86_32ExecPLT1(SectionData& pParent); +}; + +//===----------------------------------------------------------------------===// +// X86_64PLT Entry +//===----------------------------------------------------------------------===// +class X86_64PLT0 : public PLT::Entry<sizeof(x86_64_plt0)> +{ +public: + X86_64PLT0(SectionData& pParent); +}; + +class X86_64PLT1 : public PLT::Entry<sizeof(x86_64_plt1)> +{ +public: + X86_64PLT1(SectionData& pParent); }; //===----------------------------------------------------------------------===// @@ -82,8 +109,8 @@ class X86PLT : public PLT { public: X86PLT(LDSection& pSection, - X86GOTPLT& pGOTPLT, - const LinkerConfig& pConfig); + const LinkerConfig& pConfig, + int got_size); ~X86PLT(); // finalizeSectionSize - set LDSection size @@ -96,19 +123,17 @@ public: PLTEntryBase* consume(); - void applyPLT0(); + virtual void applyPLT0() = 0; - void applyPLT1(); + virtual void applyPLT1() = 0; unsigned int getPLT0Size() const { return m_PLT0Size; } unsigned int getPLT1Size() const { return m_PLT1Size; } -private: +protected: PLTEntryBase* getPLT0() const; -private: - X86GOTPLT& m_GOTPLT; - +protected: // the last consumed entry. SectionData::iterator m_Last; @@ -120,6 +145,48 @@ private: const LinkerConfig& m_Config; }; +//===----------------------------------------------------------------------===// +// X86_32PLT +//===----------------------------------------------------------------------===// +/** \class X86_32PLT + * \brief X86_32 Procedure Linkage Table + */ +class X86_32PLT : public X86PLT +{ +public: + X86_32PLT(LDSection& pSection, + X86_32GOTPLT& pGOTPLT, + const LinkerConfig& pConfig); + + void applyPLT0(); + + void applyPLT1(); + +private: + X86_32GOTPLT& m_GOTPLT; +}; + +//===----------------------------------------------------------------------===// +// X86_64PLT +//===----------------------------------------------------------------------===// +/** \class X86_64PLT + * \brief X86_64 Procedure Linkage Table + */ +class X86_64PLT : public X86PLT +{ +public: + X86_64PLT(LDSection& pSection, + X86_64GOTPLT& pGOTPLT, + const LinkerConfig& pConfig); + + void applyPLT0(); + + void applyPLT1(); + +private: + X86_64GOTPLT& m_GOTPLT; +}; + } // namespace of mcld #endif diff --git a/lib/Target/X86/X86RelocationFunctions.h b/lib/Target/X86/X86RelocationFunctions.h index df2e70c..9209242 100644 --- a/lib/Target/X86/X86RelocationFunctions.h +++ b/lib/Target/X86/X86RelocationFunctions.h @@ -7,69 +7,122 @@ // //===----------------------------------------------------------------------===// -#define DECL_X86_APPLY_RELOC_FUNC(Name) \ -static X86Relocator::Result Name (Relocation& pEntry, \ - X86Relocator& pParent); +#define DECL_X86_32_APPLY_RELOC_FUNC(Name) \ +static X86Relocator::Result Name(Relocation& pEntry, X86_32Relocator& pParent); -#define DECL_X86_APPLY_RELOC_FUNCS \ -DECL_X86_APPLY_RELOC_FUNC(none) \ -DECL_X86_APPLY_RELOC_FUNC(abs) \ -DECL_X86_APPLY_RELOC_FUNC(rel) \ -DECL_X86_APPLY_RELOC_FUNC(plt32) \ -DECL_X86_APPLY_RELOC_FUNC(got32) \ -DECL_X86_APPLY_RELOC_FUNC(gotoff32) \ -DECL_X86_APPLY_RELOC_FUNC(gotpc32) \ -DECL_X86_APPLY_RELOC_FUNC(tls_gd) \ -DECL_X86_APPLY_RELOC_FUNC(tls_ie) \ -DECL_X86_APPLY_RELOC_FUNC(tls_gotie) \ -DECL_X86_APPLY_RELOC_FUNC(tls_le) \ -DECL_X86_APPLY_RELOC_FUNC(tls_ldm) \ -DECL_X86_APPLY_RELOC_FUNC(tls_ldo_32) \ -DECL_X86_APPLY_RELOC_FUNC(unsupport) +#define DECL_X86_32_APPLY_RELOC_FUNCS \ +DECL_X86_32_APPLY_RELOC_FUNC(none) \ +DECL_X86_32_APPLY_RELOC_FUNC(abs) \ +DECL_X86_32_APPLY_RELOC_FUNC(rel) \ +DECL_X86_32_APPLY_RELOC_FUNC(plt32) \ +DECL_X86_32_APPLY_RELOC_FUNC(got32) \ +DECL_X86_32_APPLY_RELOC_FUNC(gotoff32) \ +DECL_X86_32_APPLY_RELOC_FUNC(gotpc32) \ +DECL_X86_32_APPLY_RELOC_FUNC(tls_gd) \ +DECL_X86_32_APPLY_RELOC_FUNC(tls_ie) \ +DECL_X86_32_APPLY_RELOC_FUNC(tls_gotie) \ +DECL_X86_32_APPLY_RELOC_FUNC(tls_le) \ +DECL_X86_32_APPLY_RELOC_FUNC(tls_ldm) \ +DECL_X86_32_APPLY_RELOC_FUNC(tls_ldo_32) \ +DECL_X86_32_APPLY_RELOC_FUNC(unsupport) -#define DECL_X86_APPLY_RELOC_FUNC_PTRS \ - { &none, 0, "R_386_NONE" }, \ - { &abs, 1, "R_386_32" }, \ - { &rel, 2, "R_386_PC32" }, \ - { &got32, 3, "R_386_GOT32" }, \ - { &plt32, 4, "R_386_PLT32" }, \ - { &none, 5, "R_386_COPY" }, \ - { &none, 6, "R_386_GLOB_DAT" }, \ - { &none, 7, "R_386_JMP_SLOT" }, \ - { &none, 8, "R_386_RELATIVE" }, \ - { &gotoff32, 9, "R_386_GOTOFF" }, \ - { &gotpc32, 10, "R_386_GOTPC" }, \ - { &unsupport, 11, "R_386_32PLT" }, \ - { &unsupport, 12, "" }, \ - { &unsupport, 13, "" }, \ - { &unsupport, 14, "R_386_TLS_TPOFF" }, \ - { &tls_ie, 15, "R_386_TLS_IE" }, \ - { &tls_gotie, 16, "R_386_TLS_GOTIE" }, \ - { &tls_le, 17, "R_386_TLS_LE" }, \ - { &tls_gd, 18, "R_386_TLS_GD" }, \ - { &tls_ldm, 19, "R_386_TLS_LDM" }, \ - { &abs, 20, "R_386_16" }, \ - { &rel, 21, "R_386_PC16" }, \ - { &abs, 22, "R_386_8" }, \ - { &rel, 23, "R_386_PC8" }, \ - { &unsupport, 24, "R_386_TLS_GD_32" }, \ - { &unsupport, 25, "R_386_TLS_GD_PUSH" }, \ - { &unsupport, 26, "R_386_TLS_GD_CALL" }, \ - { &unsupport, 27, "R_386_TLS_GD_POP" }, \ - { &unsupport, 28, "R_386_TLS_LDM_32" }, \ - { &unsupport, 29, "R_386_TLS_LDM_PUSH" }, \ - { &unsupport, 30, "R_386_TLS_LDM_CALL" }, \ - { &unsupport, 31, "R_386_TLS_LDM_POP" }, \ - { &tls_ldo_32, 32, "R_386_TLS_LDO_32" }, \ - { &unsupport, 33, "R_386_TLS_IE_32" }, \ - { &unsupport, 34, "R_386_TLS_LE_32" }, \ - { &unsupport, 35, "R_386_TLS_DTPMOD32" }, \ - { &unsupport, 36, "R_386_TLS_DTPOFF32" }, \ - { &unsupport, 37, "R_386_TLS_TPOFF32" }, \ - { &unsupport, 38, "" }, \ - { &unsupport, 39, "R_386_TLS_GOTDESC" }, \ - { &unsupport, 40, "R_386_TLS_DESC_CALL" }, \ - { &unsupport, 41, "R_386_TLS_DESC" }, \ - { &unsupport, 42, "R_386_IRELATIVE" }, \ - { &unsupport, 43, "R_386_NUM" } +#define DECL_X86_32_APPLY_RELOC_FUNC_PTRS \ + { &none, 0, "R_386_NONE", 0 }, \ + { &abs, 1, "R_386_32", 32 }, \ + { &rel, 2, "R_386_PC32", 32 }, \ + { &got32, 3, "R_386_GOT32", 32 }, \ + { &plt32, 4, "R_386_PLT32", 32 }, \ + { &none, 5, "R_386_COPY", 0 }, \ + { &none, 6, "R_386_GLOB_DAT", 0 }, \ + { &none, 7, "R_386_JMP_SLOT", 0 }, \ + { &none, 8, "R_386_RELATIVE", 0 }, \ + { &gotoff32, 9, "R_386_GOTOFF", 32 }, \ + { &gotpc32, 10, "R_386_GOTPC", 32 }, \ + { &unsupport, 11, "R_386_32PLT", 0 }, \ + { &unsupport, 12, "", 0 }, \ + { &unsupport, 13, "", 0 }, \ + { &unsupport, 14, "R_386_TLS_TPOFF", 0 }, \ + { &tls_ie, 15, "R_386_TLS_IE", 0 }, \ + { &tls_gotie, 16, "R_386_TLS_GOTIE", 0 }, \ + { &tls_le, 17, "R_386_TLS_LE", 0 }, \ + { &tls_gd, 18, "R_386_TLS_GD", 0 }, \ + { &tls_ldm, 19, "R_386_TLS_LDM", 0 }, \ + { &abs, 20, "R_386_16", 16 }, \ + { &rel, 21, "R_386_PC16", 16 }, \ + { &abs, 22, "R_386_8", 8 }, \ + { &rel, 23, "R_386_PC8", 8 }, \ + { &unsupport, 24, "R_386_TLS_GD_32", 0 }, \ + { &unsupport, 25, "R_386_TLS_GD_PUSH", 0 }, \ + { &unsupport, 26, "R_386_TLS_GD_CALL", 0 }, \ + { &unsupport, 27, "R_386_TLS_GD_POP", 0 }, \ + { &unsupport, 28, "R_386_TLS_LDM_32", 0 }, \ + { &unsupport, 29, "R_386_TLS_LDM_PUSH", 0 }, \ + { &unsupport, 30, "R_386_TLS_LDM_CALL", 0 }, \ + { &unsupport, 31, "R_386_TLS_LDM_POP", 0 }, \ + { &tls_ldo_32, 32, "R_386_TLS_LDO_32", 0 }, \ + { &unsupport, 33, "R_386_TLS_IE_32", 0 }, \ + { &unsupport, 34, "R_386_TLS_LE_32", 0 }, \ + { &unsupport, 35, "R_386_TLS_DTPMOD32", 0 }, \ + { &unsupport, 36, "R_386_TLS_DTPOFF32", 0 }, \ + { &unsupport, 37, "R_386_TLS_TPOFF32", 0 }, \ + { &unsupport, 38, "", 0 }, \ + { &unsupport, 39, "R_386_TLS_GOTDESC", 0 }, \ + { &unsupport, 40, "R_386_TLS_DESC_CALL", 0 }, \ + { &unsupport, 41, "R_386_TLS_DESC", 0 }, \ + { &unsupport, 42, "R_386_IRELATIVE", 0 }, \ + { &unsupport, 43, "R_386_NUM", 0 }, \ + { &none, 44, "R_386_TLS_OPT", 0 } + +#define DECL_X86_64_APPLY_RELOC_FUNC(Name) \ +static X86Relocator::Result Name(Relocation& pEntry, X86_64Relocator& pParent); + +#define DECL_X86_64_APPLY_RELOC_FUNCS \ +DECL_X86_64_APPLY_RELOC_FUNC(none) \ +DECL_X86_64_APPLY_RELOC_FUNC(abs) \ +DECL_X86_64_APPLY_RELOC_FUNC(signed32) \ +DECL_X86_64_APPLY_RELOC_FUNC(gotpcrel) \ +DECL_X86_64_APPLY_RELOC_FUNC(plt32) \ +DECL_X86_64_APPLY_RELOC_FUNC(rel) \ +DECL_X86_64_APPLY_RELOC_FUNC(unsupport) + +#define DECL_X86_64_APPLY_RELOC_FUNC_PTRS \ + { &none, 0, "R_X86_64_NONE", 0 }, \ + { &abs, 1, "R_X86_64_64", 64 }, \ + { &rel, 2, "R_X86_64_PC32", 32 }, \ + { &unsupport, 3, "R_X86_64_GOT32", 32 }, \ + { &plt32, 4, "R_X86_64_PLT32", 32 }, \ + { &none, 5, "R_X86_64_COPY", 0 }, \ + { &none, 6, "R_X86_64_GLOB_DAT", 0 }, \ + { &none, 7, "R_X86_64_JMP_SLOT", 0 }, \ + { &none, 8, "R_X86_64_RELATIVE", 0 }, \ + { &gotpcrel, 9, "R_X86_64_GOTPCREL", 32 }, \ + { &abs, 10, "R_X86_64_32", 32 }, \ + { &signed32, 11, "R_X86_64_32S", 32 }, \ + { &abs, 12, "R_X86_64_16", 16 }, \ + { &rel, 13, "R_X86_64_PC16", 16 }, \ + { &abs, 14, "R_X86_64_8", 8 }, \ + { &rel, 15, "R_X86_64_PC8", 8 }, \ + { &none, 16, "R_X86_64_DTPMOD64", 0 }, \ + { &unsupport, 17, "R_X86_64_DTPOFF64", 0 }, \ + { &none, 18, "R_X86_64_TPOFF64", 0 }, \ + { &unsupport, 19, "R_X86_64_TLSGD", 0 }, \ + { &unsupport, 20, "R_X86_64_TLSLD", 0 }, \ + { &unsupport, 21, "R_X86_64_DTPOFF32", 0 }, \ + { &unsupport, 22, "R_X86_64_GOTTPOFF", 0 }, \ + { &unsupport, 23, "R_X86_64_TPOFF32", 0 }, \ + { &unsupport, 24, "R_X86_64_PC64", 64 }, \ + { &unsupport, 25, "R_X86_64_GOTOFF64", 64 }, \ + { &unsupport, 26, "R_X86_64_GOTPC32", 32 }, \ + { &unsupport, 27, "R_X86_64_GOT64", 64 }, \ + { &unsupport, 28, "R_X86_64_GOTPCREL64", 64 }, \ + { &unsupport, 29, "R_X86_64_GOTPC64", 64 }, \ + { &unsupport, 30, "R_X86_64_GOTPLT64", 64 }, \ + { &unsupport, 31, "R_X86_64_PLTOFF64", 64 }, \ + { &unsupport, 32, "R_X86_64_SIZE32", 32 }, \ + { &unsupport, 33, "R_X86_64_SIZE64", 64 }, \ + { &unsupport, 34, "R_X86_64_GOTPC32_TLSDESC", 0 }, \ + { &unsupport, 35, "R_X86_64_TLSDESC_CALL", 0 }, \ + { &none, 36, "R_X86_64_TLSDESC", 0 }, \ + { &none, 37, "R_X86_64_IRELATIVE", 0 }, \ + { &none, 38, "R_X86_64_RELATIVE64", 0 } diff --git a/lib/Target/X86/X86Relocator.cpp b/lib/Target/X86/X86Relocator.cpp index 3b4d389..a4eac66 100644 --- a/lib/Target/X86/X86Relocator.cpp +++ b/lib/Target/X86/X86Relocator.cpp @@ -6,68 +6,80 @@ // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// +#include "X86Relocator.h" +#include "X86RelocationFunctions.h" + +#include <mcld/Support/MsgHandling.h> +#include <mcld/LD/LDSymbol.h> #include <llvm/ADT/Twine.h> #include <llvm/Support/DataTypes.h> #include <llvm/Support/ELF.h> -#include <mcld/Fragment/FragmentLinker.h> -#include <mcld/Support/MsgHandling.h> - -#include "X86Relocator.h" -#include "X86RelocationFunctions.h" using namespace mcld; //===--------------------------------------------------------------------===// // Relocation Functions and Tables //===--------------------------------------------------------------------===// -DECL_X86_APPLY_RELOC_FUNCS +DECL_X86_32_APPLY_RELOC_FUNCS /// the prototype of applying function -typedef Relocator::Result (*ApplyFunctionType)(Relocation& pReloc, - X86Relocator& pParent); +typedef Relocator::Result (*X86_32ApplyFunctionType)(Relocation& pReloc, + X86_32Relocator& pParent); // the table entry of applying functions -struct ApplyFunctionTriple +struct X86_32ApplyFunctionTriple { - ApplyFunctionType func; + X86_32ApplyFunctionType func; unsigned int type; const char* name; + unsigned int size; }; // declare the table of applying functions -static const ApplyFunctionTriple ApplyFunctions[] = { - DECL_X86_APPLY_RELOC_FUNC_PTRS +static const X86_32ApplyFunctionTriple X86_32ApplyFunctions[] = { + DECL_X86_32_APPLY_RELOC_FUNC_PTRS }; //===--------------------------------------------------------------------===// // X86Relocator //===--------------------------------------------------------------------===// -X86Relocator::X86Relocator(X86GNULDBackend& pParent) - : Relocator(), - m_Target(pParent) { +X86Relocator::X86Relocator() + : Relocator() { } X86Relocator::~X86Relocator() { } +//===--------------------------------------------------------------------===// +// X86_32Relocator +//===--------------------------------------------------------------------===// +X86_32Relocator::X86_32Relocator(X86_32GNULDBackend& pParent) + : X86Relocator(), m_Target(pParent) { +} + Relocator::Result -X86Relocator::applyRelocation(Relocation& pRelocation) +X86_32Relocator::applyRelocation(Relocation& pRelocation) { Relocation::Type type = pRelocation.type(); - if (type >= sizeof (ApplyFunctions) / sizeof (ApplyFunctions[0]) ) { + if (type >= sizeof (X86_32ApplyFunctions) / sizeof (X86_32ApplyFunctions[0]) ) { return Unknown; } // apply the relocation - return ApplyFunctions[type].func(pRelocation, *this); + return X86_32ApplyFunctions[type].func(pRelocation, *this); } -const char* X86Relocator::getName(Relocation::Type pType) const +const char* X86_32Relocator::getName(Relocation::Type pType) const { - return ApplyFunctions[pType].name; + return X86_32ApplyFunctions[pType].name; +} + +Relocator::Size X86_32Relocator::getSize(Relocation::Type pType) const +{ + return X86_32ApplyFunctions[pType].size;; } //===--------------------------------------------------------------------===// @@ -80,9 +92,9 @@ Relocation& helper_DynRel(ResolveInfo* pSym, Fragment& pFrag, uint64_t pOffset, X86Relocator::Type pType, - X86Relocator& pParent) + X86_32Relocator& pParent) { - X86GNULDBackend& ld_backend = pParent.getTarget(); + X86_32GNULDBackend& ld_backend = pParent.getTarget(); Relocation& rel_entry = *ld_backend.getRelDyn().consumeEntry(); rel_entry.setType(pType); rel_entry.targetRef().assign(pFrag, pOffset); @@ -99,7 +111,7 @@ Relocation& helper_DynRel(ResolveInfo* pSym, /// R_386_RELATIVE static bool helper_use_relative_reloc(const ResolveInfo& pSym, - const X86Relocator& pFactory) + const X86_32Relocator& pFactory) { // if symbol is dynamic or undefine or preemptible @@ -111,14 +123,14 @@ helper_use_relative_reloc(const ResolveInfo& pSym, } static -X86GOTEntry& helper_get_GOT_and_init(Relocation& pReloc, - X86Relocator& pParent) +X86_32GOTEntry& helper_get_GOT_and_init(Relocation& pReloc, + X86_32Relocator& pParent) { // rsym - The relocation target symbol ResolveInfo* rsym = pReloc.symInfo(); - X86GNULDBackend& ld_backend = pParent.getTarget(); + X86_32GNULDBackend& ld_backend = pParent.getTarget(); - X86GOTEntry* got_entry = pParent.getSymGOTMap().lookUp(*rsym); + X86_32GOTEntry* got_entry = pParent.getSymGOTMap().lookUp(*rsym); if (NULL != got_entry) return *got_entry; @@ -150,27 +162,28 @@ X86GOTEntry& helper_get_GOT_and_init(Relocation& pReloc, static -X86Relocator::Address helper_GOT_ORG(X86Relocator& pParent) +X86Relocator::Address helper_GOT_ORG(X86_32Relocator& pParent) { return pParent.getTarget().getGOTPLT().addr(); } static -X86Relocator::Address helper_GOT(Relocation& pReloc, X86Relocator& pParent) +X86Relocator::Address helper_GOT(Relocation& pReloc, X86_32Relocator& pParent) { - X86GOTEntry& got_entry = helper_get_GOT_and_init(pReloc, pParent); + X86_32GOTEntry& got_entry = helper_get_GOT_and_init(pReloc, pParent); X86Relocator::Address got_addr = pParent.getTarget().getGOT().addr(); return got_addr + got_entry.getOffset(); } static -PLTEntryBase& helper_get_PLT_and_init(Relocation& pReloc, X86Relocator& pParent) +PLTEntryBase& helper_get_PLT_and_init(Relocation& pReloc, + X86_32Relocator& pParent) { // rsym - The relocation target symbol ResolveInfo* rsym = pReloc.symInfo(); - X86GNULDBackend& ld_backend = pParent.getTarget(); + X86_32GNULDBackend& ld_backend = pParent.getTarget(); PLTEntryBase* plt_entry = pParent.getSymPLTMap().lookUp(*rsym); if (NULL != plt_entry) @@ -181,7 +194,7 @@ PLTEntryBase& helper_get_PLT_and_init(Relocation& pReloc, X86Relocator& pParent) pParent.getSymPLTMap().record(*rsym, *plt_entry); // If we first get this PLT entry, we should initialize it. if (rsym->reserved() & X86GNULDBackend::ReservePLT) { - X86GOTPLTEntry* gotplt_entry = pParent.getSymGOTPLTMap().lookUp(*rsym); + X86_32GOTEntry* gotplt_entry = pParent.getSymGOTPLTMap().lookUp(*rsym); assert(NULL == gotplt_entry && "PLT entry not exist, but DynRel entry exist!"); gotplt_entry = ld_backend.getGOTPLT().consume(); pParent.getSymGOTPLTMap().record(*rsym, *gotplt_entry); @@ -200,14 +213,14 @@ PLTEntryBase& helper_get_PLT_and_init(Relocation& pReloc, X86Relocator& pParent) static -X86Relocator::Address helper_PLT_ORG(X86Relocator& pParent) +X86Relocator::Address helper_PLT_ORG(X86_32Relocator& pParent) { return pParent.getTarget().getPLT().addr(); } static -X86Relocator::Address helper_PLT(Relocation& pReloc, X86Relocator& pParent) +X86Relocator::Address helper_PLT(Relocation& pReloc, X86_32Relocator& pParent) { PLTEntryBase& plt_entry = helper_get_PLT_and_init(pReloc, pParent); return helper_PLT_ORG(pParent) + plt_entry.getOffset(); @@ -219,7 +232,7 @@ X86Relocator::Address helper_PLT(Relocation& pReloc, X86Relocator& pParent) //=========================================// // R_386_NONE -X86Relocator::Result none(Relocation& pReloc, X86Relocator& pParent) +X86Relocator::Result none(Relocation& pReloc, X86_32Relocator& pParent) { return X86Relocator::OK; } @@ -227,13 +240,12 @@ X86Relocator::Result none(Relocation& pReloc, X86Relocator& pParent) // R_386_32: S + A // R_386_16 // R_386_8 -X86Relocator::Result abs(Relocation& pReloc, X86Relocator& pParent) +X86Relocator::Result abs(Relocation& pReloc, X86_32Relocator& pParent) { ResolveInfo* rsym = pReloc.symInfo(); Relocator::DWord A = pReloc.target() + pReloc.addend(); Relocator::DWord S = pReloc.symValue(); bool has_dyn_rel = pParent.getTarget().symbolNeedsDynRel( - pParent.getFragmentLinker(), *rsym, (rsym->reserved() & X86GNULDBackend::ReservePLT), true); @@ -292,7 +304,7 @@ X86Relocator::Result abs(Relocation& pReloc, X86Relocator& pParent) // R_386_PC32: S + A - P // R_386_PC16 // R_386_PC8 -X86Relocator::Result rel(Relocation& pReloc, X86Relocator& pParent) +X86Relocator::Result rel(Relocation& pReloc, X86_32Relocator& pParent) { ResolveInfo* rsym = pReloc.symInfo(); Relocator::DWord A = pReloc.target() + pReloc.addend(); @@ -314,7 +326,6 @@ X86Relocator::Result rel(Relocation& pReloc, X86Relocator& pParent) pReloc.target() = S + A - P; } if (pParent.getTarget().symbolNeedsDynRel( - pParent.getFragmentLinker(), *rsym, (rsym->reserved() & X86GNULDBackend::ReservePLT), false)) { @@ -336,7 +347,7 @@ X86Relocator::Result rel(Relocation& pReloc, X86Relocator& pParent) } // R_386_GOTOFF: S + A - GOT_ORG -X86Relocator::Result gotoff32(Relocation& pReloc, X86Relocator& pParent) +X86Relocator::Result gotoff32(Relocation& pReloc, X86_32Relocator& pParent) { Relocator::DWord A = pReloc.target() + pReloc.addend(); X86Relocator::Address GOT_ORG = helper_GOT_ORG(pParent); @@ -347,7 +358,7 @@ X86Relocator::Result gotoff32(Relocation& pReloc, X86Relocator& pParent) } // R_386_GOTPC: GOT_ORG + A - P -X86Relocator::Result gotpc32(Relocation& pReloc, X86Relocator& pParent) +X86Relocator::Result gotpc32(Relocation& pReloc, X86_32Relocator& pParent) { Relocator::DWord A = pReloc.target() + pReloc.addend(); X86Relocator::Address GOT_ORG = helper_GOT_ORG(pParent); @@ -357,7 +368,7 @@ X86Relocator::Result gotpc32(Relocation& pReloc, X86Relocator& pParent) } // R_386_GOT32: GOT(S) + A - GOT_ORG -X86Relocator::Result got32(Relocation& pReloc, X86Relocator& pParent) +X86Relocator::Result got32(Relocation& pReloc, X86_32Relocator& pParent) { if (!(pReloc.symInfo()->reserved() & (X86GNULDBackend::ReserveGOT |X86GNULDBackend::GOTRel))) { @@ -372,7 +383,7 @@ X86Relocator::Result got32(Relocation& pReloc, X86Relocator& pParent) } // R_386_PLT32: PLT(S) + A - P -X86Relocator::Result plt32(Relocation& pReloc, X86Relocator& pParent) +X86Relocator::Result plt32(Relocation& pReloc, X86_32Relocator& pParent) { // PLT_S depends on if there is a PLT entry. X86Relocator::Address PLT_S; @@ -387,7 +398,7 @@ X86Relocator::Result plt32(Relocation& pReloc, X86Relocator& pParent) } // R_386_TLS_GD: -X86Relocator::Result tls_gd(Relocation& pReloc, X86Relocator& pParent) +X86Relocator::Result tls_gd(Relocation& pReloc, X86_32Relocator& pParent) { // global-dynamic ResolveInfo* rsym = pReloc.symInfo(); @@ -396,19 +407,19 @@ X86Relocator::Result tls_gd(Relocation& pReloc, X86Relocator& pParent) return X86Relocator::BadReloc; } - X86GNULDBackend& ld_backend = pParent.getTarget(); + X86_32GNULDBackend& ld_backend = pParent.getTarget(); ELFFileFormat* file_format = pParent.getTarget().getOutputFormat(); // setup corresponding got and dynamic relocatio entries: // get first got entry, if there is already a got entry for rsym, then apply // this relocation to the got entry directly. If not, setup the corresponding // got and dyn relocation entries - X86GOTEntry* got_entry1 = pParent.getSymGOTMap().lookUp(*rsym); + X86_32GOTEntry* got_entry1 = pParent.getSymGOTMap().lookUp(*rsym); if (NULL == got_entry1) { // get and init two got entries if not exist got_entry1 = ld_backend.getGOT().consume(); pParent.getSymGOTMap().record(*rsym, *got_entry1); - X86GOTEntry* got_entry2 = ld_backend.getGOT().consume(); + X86_32GOTEntry* got_entry2 = ld_backend.getGOT().consume(); got_entry1->setValue(0x0); got_entry2->setValue(0x0); // setup dyn rel for get_entry1 @@ -450,10 +461,10 @@ X86Relocator::Result tls_gd(Relocation& pReloc, X86Relocator& pParent) } // R_386_TLS_LDM -X86Relocator::Result tls_ldm(Relocation& pReloc, X86Relocator& pParent) +X86Relocator::Result tls_ldm(Relocation& pReloc, X86_32Relocator& pParent) { // FIXME: no linker optimization for TLS relocation - const X86GOTEntry& got_entry = pParent.getTarget().getTLSModuleID(); + const X86_32GOTEntry& got_entry = pParent.getTarget().getTLSModuleID(); // All GOT offsets are relative to the end of the GOT. X86Relocator::SWord GOT_S = got_entry.getOffset() - @@ -466,7 +477,7 @@ X86Relocator::Result tls_ldm(Relocation& pReloc, X86Relocator& pParent) } // R_386_TLS_LDO_32 -X86Relocator::Result tls_ldo_32(Relocation& pReloc, X86Relocator& pParent) +X86Relocator::Result tls_ldo_32(Relocation& pReloc, X86_32Relocator& pParent) { // FIXME: no linker optimization for TLS relocation Relocator::DWord A = pReloc.target() + pReloc.addend(); @@ -476,7 +487,7 @@ X86Relocator::Result tls_ldo_32(Relocation& pReloc, X86Relocator& pParent) } // R_X86_TLS_IE -X86Relocator::Result tls_ie(Relocation& pReloc, X86Relocator& pParent) +X86Relocator::Result tls_ie(Relocation& pReloc, X86_32Relocator& pParent) { ResolveInfo* rsym = pReloc.symInfo(); if (!(rsym->reserved() & X86GNULDBackend::GOTRel)) { @@ -490,10 +501,10 @@ X86Relocator::Result tls_ie(Relocation& pReloc, X86Relocator& pParent) } // set up the got and dynamic relocation entries if not exist - X86GOTEntry* got_entry = pParent.getSymGOTMap().lookUp(*rsym); + X86_32GOTEntry* got_entry = pParent.getSymGOTMap().lookUp(*rsym); if (NULL == got_entry) { // set got entry - X86GNULDBackend& ld_backend = pParent.getTarget(); + X86_32GNULDBackend& ld_backend = pParent.getTarget(); got_entry = ld_backend.getGOT().consume(); pParent.getSymGOTMap().record(*rsym, *got_entry); got_entry->setValue(0x0); @@ -515,7 +526,7 @@ X86Relocator::Result tls_ie(Relocation& pReloc, X86Relocator& pParent) } // R_386_TLS_GOTIE -X86Relocator::Result tls_gotie(Relocation& pReloc, X86Relocator& pParent) +X86Relocator::Result tls_gotie(Relocation& pReloc, X86_32Relocator& pParent) { ResolveInfo* rsym = pReloc.symInfo(); if (!(rsym->reserved() & X86GNULDBackend::GOTRel)) { @@ -523,10 +534,10 @@ X86Relocator::Result tls_gotie(Relocation& pReloc, X86Relocator& pParent) } // set up the got and dynamic relocation entries if not exist - X86GOTEntry* got_entry = pParent.getSymGOTMap().lookUp(*rsym); + X86_32GOTEntry* got_entry = pParent.getSymGOTMap().lookUp(*rsym); if (NULL == got_entry) { // set got entry - X86GNULDBackend& ld_backend = pParent.getTarget(); + X86_32GNULDBackend& ld_backend = pParent.getTarget(); got_entry = ld_backend.getGOT().consume(); pParent.getSymGOTMap().record(*rsym, *got_entry); got_entry->setValue(0x0); @@ -547,7 +558,7 @@ X86Relocator::Result tls_gotie(Relocation& pReloc, X86Relocator& pParent) } // R_X86_TLS_LE -X86Relocator::Result tls_le(Relocation& pReloc, X86Relocator& pParent) +X86Relocator::Result tls_le(Relocation& pReloc, X86_32Relocator& pParent) { ResolveInfo* rsym = pReloc.symInfo(); if (pReloc.symInfo()->reserved() & X86GNULDBackend::ReserveRel) { @@ -569,8 +580,375 @@ X86Relocator::Result tls_le(Relocation& pReloc, X86Relocator& pParent) return X86Relocator::OK; } -X86Relocator::Result unsupport(Relocation& pReloc, X86Relocator& pParent) +X86Relocator::Result unsupport(Relocation& pReloc, X86_32Relocator& pParent) { return X86Relocator::Unsupport; } +//===--------------------------------------------------------------------===// +// Relocation Functions and Tables +//===--------------------------------------------------------------------===// +DECL_X86_64_APPLY_RELOC_FUNCS + +/// the prototype of applying function +typedef Relocator::Result (*X86_64ApplyFunctionType)(Relocation& pReloc, + X86_64Relocator& pParent); + +// the table entry of applying functions +struct X86_64ApplyFunctionTriple +{ + X86_64ApplyFunctionType func; + unsigned int type; + const char* name; + unsigned int size; +}; + +// declare the table of applying functions +static const X86_64ApplyFunctionTriple X86_64ApplyFunctions[] = { + DECL_X86_64_APPLY_RELOC_FUNC_PTRS +}; + +//===--------------------------------------------------------------------===// +// X86_64Relocator +//===--------------------------------------------------------------------===// +X86_64Relocator::X86_64Relocator(X86_64GNULDBackend& pParent) + : X86Relocator(), m_Target(pParent) { +} + +Relocator::Result +X86_64Relocator::applyRelocation(Relocation& pRelocation) +{ + Relocation::Type type = pRelocation.type(); + + if (type >= sizeof (X86_64ApplyFunctions) / sizeof (X86_64ApplyFunctions[0]) ) { + return Unknown; + } + + // apply the relocation + return X86_64ApplyFunctions[type].func(pRelocation, *this); +} + +const char* X86_64Relocator::getName(Relocation::Type pType) const +{ + return X86_64ApplyFunctions[pType].name; +} + +Relocator::Size X86_64Relocator::getSize(Relocation::Type pType) const +{ + return X86_64ApplyFunctions[pType].size; +} + +/// helper_DynRel - Get an relocation entry in .rela.dyn +static +Relocation& helper_DynRel(ResolveInfo* pSym, + Fragment& pFrag, + uint64_t pOffset, + X86Relocator::Type pType, + X86_64Relocator& pParent) +{ + X86_64GNULDBackend& ld_backend = pParent.getTarget(); + Relocation& rel_entry = *ld_backend.getRelDyn().consumeEntry(); + rel_entry.setType(pType); + rel_entry.targetRef().assign(pFrag, pOffset); + if (pType == llvm::ELF::R_X86_64_RELATIVE || NULL == pSym) + rel_entry.setSymInfo(0); + else + rel_entry.setSymInfo(pSym); + + return rel_entry; +} + + +/// helper_use_relative_reloc - Check if symbol can use relocation +/// R_X86_64_RELATIVE +static bool +helper_use_relative_reloc(const ResolveInfo& pSym, + const X86_64Relocator& pFactory) + +{ + // if symbol is dynamic or undefine or preemptible + if (pSym.isDyn() || + pSym.isUndef() || + pFactory.getTarget().isSymbolPreemptible(pSym)) + return false; + return true; +} + +static +X86_64GOTEntry& helper_get_GOT_and_init(Relocation& pReloc, + X86_64Relocator& pParent) +{ + // rsym - The relocation target symbol + ResolveInfo* rsym = pReloc.symInfo(); + X86_64GNULDBackend& ld_backend = pParent.getTarget(); + + X86_64GOTEntry* got_entry = pParent.getSymGOTMap().lookUp(*rsym); + if (NULL != got_entry) + return *got_entry; + + // not found + got_entry = ld_backend.getGOT().consume(); + pParent.getSymGOTMap().record(*rsym, *got_entry); + + // If we first get this GOT entry, we should initialize it. + if (rsym->reserved() & X86GNULDBackend::ReserveGOT) { + // No corresponding dynamic relocation, initialize to the symbol value. + got_entry->setValue(pReloc.symValue()); + } + else if (rsym->reserved() & X86GNULDBackend::GOTRel) { + // Initialize got_entry content and the corresponding dynamic relocation. + if (helper_use_relative_reloc(*rsym, pParent)) { + Relocation& rel_entry = helper_DynRel(rsym, *got_entry, 0x0, + llvm::ELF::R_X86_64_RELATIVE, + pParent); + rel_entry.setAddend(pReloc.symValue()); + } + else { + helper_DynRel(rsym, *got_entry, 0x0, llvm::ELF::R_X86_64_GLOB_DAT, + pParent); + } + got_entry->setValue(0); + } + else { + fatal(diag::reserve_entry_number_mismatch_got); + } + return *got_entry; +} + +static +X86Relocator::Address helper_GOT_ORG(X86_64Relocator& pParent) +{ + return pParent.getTarget().getGOT().addr(); +} + +static +X86Relocator::Address helper_GOT(Relocation& pReloc, X86_64Relocator& pParent) +{ + X86_64GOTEntry& got_entry = helper_get_GOT_and_init(pReloc, pParent); + return got_entry.getOffset(); +} + +static +PLTEntryBase& helper_get_PLT_and_init(Relocation& pReloc, + X86_64Relocator& pParent) +{ + // rsym - The relocation target symbol + ResolveInfo* rsym = pReloc.symInfo(); + X86_64GNULDBackend& ld_backend = pParent.getTarget(); + + PLTEntryBase* plt_entry = pParent.getSymPLTMap().lookUp(*rsym); + if (NULL != plt_entry) + return *plt_entry; + + // not found + plt_entry = ld_backend.getPLT().consume(); + pParent.getSymPLTMap().record(*rsym, *plt_entry); + // If we first get this PLT entry, we should initialize it. + if (rsym->reserved() & X86GNULDBackend::ReservePLT) { + X86_64GOTEntry* gotplt_entry = pParent.getSymGOTPLTMap().lookUp(*rsym); + assert(NULL == gotplt_entry && "PLT entry not exist, but DynRel entry exist!"); + gotplt_entry = ld_backend.getGOTPLT().consume(); + pParent.getSymGOTPLTMap().record(*rsym, *gotplt_entry); + // init the corresponding rel entry in .rel.plt + Relocation& rel_entry = *ld_backend.getRelPLT().consumeEntry(); + rel_entry.setType(llvm::ELF::R_X86_64_JUMP_SLOT); + rel_entry.targetRef().assign(*gotplt_entry); + rel_entry.setSymInfo(rsym); + } + else { + fatal(diag::reserve_entry_number_mismatch_plt); + } + + return *plt_entry; +} + +static +X86Relocator::Address helper_PLT_ORG(X86_64Relocator& pParent) +{ + return pParent.getTarget().getPLT().addr(); +} + +static +X86Relocator::Address helper_PLT(Relocation& pReloc, X86_64Relocator& pParent) +{ + PLTEntryBase& plt_entry = helper_get_PLT_and_init(pReloc, pParent); + return helper_PLT_ORG(pParent) + plt_entry.getOffset(); +} + +// +// R_X86_64_NONE +X86Relocator::Result none(Relocation& pReloc, X86_64Relocator& pParent) +{ + return X86Relocator::OK; +} + +// R_X86_64_64: S + A +// R_X86_64_32: +// R_X86_64_16: +// R_X86_64_8 +X86Relocator::Result abs(Relocation& pReloc, X86_64Relocator& pParent) +{ + ResolveInfo* rsym = pReloc.symInfo(); + Relocator::DWord A = pReloc.addend(); + Relocator::DWord S = pReloc.symValue(); + bool has_dyn_rel = pParent.getTarget().symbolNeedsDynRel( + *rsym, + (rsym->reserved() & X86GNULDBackend::ReservePLT), + true); + + LDSection& target_sect = pReloc.targetRef().frag()->getParent()->getSection(); + // If the flag of target section is not ALLOC, we will not scan this relocation + // but perform static relocation. (e.g., applying .debug section) + if (0x0 == (llvm::ELF::SHF_ALLOC & target_sect.flag())) { + pReloc.target() = S + A; + return X86Relocator::OK; + } + + Relocation::Type pointerRel = pParent.getTarget().getPointerRel(); + + // A local symbol may need REL Type dynamic relocation + if (rsym->isLocal() && has_dyn_rel) { + if (pointerRel == pReloc.type()) { + Relocation& rel_entry = helper_DynRel(rsym, *pReloc.targetRef().frag(), + pReloc.targetRef().offset(), + llvm::ELF::R_X86_64_RELATIVE, + pParent); + rel_entry.setAddend(S + A); + } + else { + // FIXME: check Section symbol + Relocation& rel_entry = helper_DynRel(rsym, *pReloc.targetRef().frag(), + pReloc.targetRef().offset(), + pReloc.type(), pParent); + rel_entry.setAddend(S + A); + } + return X86Relocator::OK; + } + + // An external symbol may need PLT and dynamic relocation + if (!rsym->isLocal()) { + // If we generate a dynamic relocation for a place with explicit + // addend, there is no need to perform static relocation on it. + if (has_dyn_rel) { + Relocation& rel_entry = helper_DynRel(rsym, *pReloc.targetRef().frag(), + pReloc.targetRef().offset(), + llvm::ELF::R_X86_64_RELATIVE, + pParent); + // Copy addend. + rel_entry.setAddend(A); + return X86Relocator::OK; + } + else if (rsym->reserved() & X86GNULDBackend::ReservePLT) { + S = helper_PLT(pReloc, pParent); + } + } + + // perform static relocation + pReloc.target() = S + A; + return X86Relocator::OK; +} + +// R_X86_64_32S: S + A +X86Relocator::Result signed32(Relocation& pReloc, X86_64Relocator& pParent) +{ + ResolveInfo* rsym = pReloc.symInfo(); + Relocator::DWord A = pReloc.addend(); + Relocator::DWord S = pReloc.symValue(); + bool has_dyn_rel = pParent.getTarget().symbolNeedsDynRel( + *rsym, + (rsym->reserved() & X86GNULDBackend::ReservePLT), + true); + + // There should be no dynamic relocations for R_X86_64_32S. + if (has_dyn_rel) + return X86Relocator::BadReloc; + + LDSection& target_sect = pReloc.targetRef().frag()->getParent()->getSection(); + // If the flag of target section is not ALLOC, we will not scan this relocation + // but perform static relocation. (e.g., applying .debug section) + // An external symbol may need PLT and dynamic relocation + if (0x0 != (llvm::ELF::SHF_ALLOC & target_sect.flag()) && + !rsym->isLocal() && rsym->reserved() & X86GNULDBackend::ReservePLT) + S = helper_PLT(pReloc, pParent); + + // Check 32-bit signed overflow. + Relocator::SWord V = S + A; + if (V > INT64_C(0x7fffffff) || V < INT64_C(-0x80000000)) + return X86Relocator::Overflow; + + // perform static relocation + pReloc.target() = S + A; + return X86Relocator::OK; +} + +// R_X86_64_GOTPCREL: GOT(S) + GOT_ORG + A - P +X86Relocator::Result gotpcrel(Relocation& pReloc, X86_64Relocator& pParent) +{ + if (!(pReloc.symInfo()->reserved() + & (X86GNULDBackend::ReserveGOT |X86GNULDBackend::GOTRel))) { + return X86Relocator::BadReloc; + } + X86Relocator::Address GOT_S = helper_GOT(pReloc, pParent); + Relocator::DWord A = pReloc.addend(); + X86Relocator::Address GOT_ORG = helper_GOT_ORG(pParent); + // Apply relocation. + pReloc.target() = GOT_S + GOT_ORG + A - pReloc.place(); + return X86Relocator::OK; +} + +// R_X86_64_PLT32: PLT(S) + A - P +X86Relocator::Result plt32(Relocation& pReloc, X86_64Relocator& pParent) +{ + // PLT_S depends on if there is a PLT entry. + X86Relocator::Address PLT_S; + if ((pReloc.symInfo()->reserved() & X86GNULDBackend::ReservePLT)) + PLT_S = helper_PLT(pReloc, pParent); + else + PLT_S = pReloc.symValue(); + Relocator::DWord A = pReloc.addend(); + X86Relocator::Address P = pReloc.place(); + pReloc.target() = PLT_S + A - P; + return X86Relocator::OK; +} + +// R_X86_64_PC32: S + A - P +// R_X86_64_PC16 +// R_X86_64_PC8 +X86Relocator::Result rel(Relocation& pReloc, X86_64Relocator& pParent) +{ + ResolveInfo* rsym = pReloc.symInfo(); + Relocator::DWord A = pReloc.addend(); + Relocator::DWord S = pReloc.symValue(); + Relocator::DWord P = pReloc.place(); + + LDSection& target_sect = pReloc.targetRef().frag()->getParent()->getSection(); + // If the flag of target section is not ALLOC, we will not scan this relocation + // but perform static relocation. (e.g., applying .debug section) + if (0x0 == (llvm::ELF::SHF_ALLOC & target_sect.flag())) { + pReloc.target() = S + A - P; + return X86Relocator::OK; + } + + // An external symbol may need PLT and dynamic relocation + if (!rsym->isLocal()) { + if (rsym->reserved() & X86GNULDBackend::ReservePLT) { + S = helper_PLT(pReloc, pParent); + pReloc.target() = S + A - P; + } + if (pParent.getTarget().symbolNeedsDynRel( + *rsym, + (rsym->reserved() & X86GNULDBackend::ReservePLT), + false)) { + return X86Relocator::Overflow; + } + } + + // perform static relocation + pReloc.target() = S + A - P; + return X86Relocator::OK; +} + +X86Relocator::Result unsupport(Relocation& pReloc, X86_64Relocator& pParent) +{ + return X86Relocator::Unsupport; +} diff --git a/lib/Target/X86/X86Relocator.h b/lib/Target/X86/X86Relocator.h index 7d3c289..922f1f2 100644 --- a/lib/Target/X86/X86Relocator.h +++ b/lib/Target/X86/X86Relocator.h @@ -30,25 +30,50 @@ class X86Relocator : public Relocator { public: typedef SymbolEntryMap<PLTEntryBase> SymPLTMap; - typedef SymbolEntryMap<X86GOTEntry> SymGOTMap; - typedef SymbolEntryMap<X86GOTPLTEntry> SymGOTPLTMap; public: - X86Relocator(X86GNULDBackend& pParent); + X86Relocator(); ~X86Relocator(); + virtual Result applyRelocation(Relocation& pRelocation) = 0; + + virtual const char* getName(Relocation::Type pType) const = 0; + + const SymPLTMap& getSymPLTMap() const { return m_SymPLTMap; } + SymPLTMap& getSymPLTMap() { return m_SymPLTMap; } + +private: + SymPLTMap m_SymPLTMap; +}; + +/** \class X86_32Relocator + * \brief X86_32Relocator creates and destroys the X86-32 relocations. + * + */ +class X86_32Relocator : public X86Relocator +{ +public: + typedef SymbolEntryMap<X86_32GOTEntry> SymGOTMap; + typedef SymbolEntryMap<X86_32GOTEntry> SymGOTPLTMap; + + enum { + R_386_TLS_OPT = 44 // mcld internal relocation type + }; + +public: + X86_32Relocator(X86_32GNULDBackend& pParent); + Result applyRelocation(Relocation& pRelocation); - X86GNULDBackend& getTarget() + X86_32GNULDBackend& getTarget() { return m_Target; } - const X86GNULDBackend& getTarget() const + const X86_32GNULDBackend& getTarget() const { return m_Target; } const char* getName(Relocation::Type pType) const; - const SymPLTMap& getSymPLTMap() const { return m_SymPLTMap; } - SymPLTMap& getSymPLTMap() { return m_SymPLTMap; } + Size getSize(Relocation::Type pType) const; const SymGOTMap& getSymGOTMap() const { return m_SymGOTMap; } SymGOTMap& getSymGOTMap() { return m_SymGOTMap; } @@ -57,8 +82,44 @@ public: SymGOTPLTMap& getSymGOTPLTMap() { return m_SymGOTPLTMap; } private: - X86GNULDBackend& m_Target; - SymPLTMap m_SymPLTMap; + X86_32GNULDBackend& m_Target; + SymGOTMap m_SymGOTMap; + SymGOTPLTMap m_SymGOTPLTMap; +}; + +/** \class X86_64Relocator + * \brief X86_64Relocator creates and destroys the X86-64 relocations. + * + */ +class X86_64Relocator : public X86Relocator +{ +public: + typedef SymbolEntryMap<X86_64GOTEntry> SymGOTMap; + typedef SymbolEntryMap<X86_64GOTEntry> SymGOTPLTMap; + +public: + X86_64Relocator(X86_64GNULDBackend& pParent); + + Result applyRelocation(Relocation& pRelocation); + + X86_64GNULDBackend& getTarget() + { return m_Target; } + + const X86_64GNULDBackend& getTarget() const + { return m_Target; } + + const char* getName(Relocation::Type pType) const; + + Size getSize(Relocation::Type pType) const; + + const SymGOTMap& getSymGOTMap() const { return m_SymGOTMap; } + SymGOTMap& getSymGOTMap() { return m_SymGOTMap; } + + const SymGOTPLTMap& getSymGOTPLTMap() const { return m_SymGOTPLTMap; } + SymGOTPLTMap& getSymGOTPLTMap() { return m_SymGOTPLTMap; } + +private: + X86_64GNULDBackend& m_Target; SymGOTMap m_SymGOTMap; SymGOTPLTMap m_SymGOTPLTMap; }; diff --git a/lib/Target/X86/X86TargetMachine.cpp b/lib/Target/X86/X86TargetMachine.cpp index 9b5a24e..b419fd1 100644 --- a/lib/Target/X86/X86TargetMachine.cpp +++ b/lib/Target/X86/X86TargetMachine.cpp @@ -14,7 +14,8 @@ extern "C" void MCLDInitializeX86LDTarget() { // Register createTargetMachine function pointer to mcld::Target - mcld::RegisterTargetMachine<mcld::X86TargetMachine> X(mcld::TheX86Target); + mcld::RegisterTargetMachine<mcld::X86TargetMachine> X(mcld::TheX86_32Target); + mcld::RegisterTargetMachine<mcld::X86TargetMachine> Y(mcld::TheX86_64Target); } mcld::X86TargetMachine::X86TargetMachine(llvm::TargetMachine& pPM, diff --git a/tools/llvm-mcld/llvm-mcld.cpp b/tools/llvm-mcld/llvm-mcld.cpp index fc0b99f..8daf65f 100644 --- a/tools/llvm-mcld/llvm-mcld.cpp +++ b/tools/llvm-mcld/llvm-mcld.cpp @@ -461,46 +461,6 @@ ArgColor("color", "surround result strings only if the output is a tty"), clEnumValEnd)); -/// @{ -/// @name FIXME: begin of unsupported options -/// @} -static cl::opt<bool> -ArgGCSections("gc-sections", - cl::desc("Enable garbage collection of unused input sections."), - cl::init(false)); - -static cl::opt<bool> -ArgNoGCSections("no-gc-sections", - cl::desc("disable garbage collection of unused input sections."), - cl::init(false)); - -namespace icf { -enum Mode { - None, - All, - Safe -}; -} // namespace of icf - -static cl::opt<icf::Mode> -ArgICF("icf", - cl::desc("Identical Code Folding"), - cl::init(icf::None), - cl::values( - clEnumValN(icf::None, "none", - "do not perform cold folding"), - clEnumValN(icf::All, "all", - "always preform cold folding"), - clEnumValN(icf::Safe, "safe", - "Folds ctors, dtors and functions whose pointers are definitely not taken."), - clEnumValEnd)); - -// FIXME: add this to target options? -static cl::opt<bool> -ArgFIXCA8("fix-cortex-a8", - cl::desc("Enable Cortex-A8 Thumb-2 branch erratum fix"), - cl::init(false)); - static cl::opt<bool> ArgDiscardLocals("discard-locals", cl::desc("Delete all temporary local symbols."), @@ -522,6 +482,26 @@ ArgDiscardAllAlias("x", cl::aliasopt(ArgDiscardAll)); static cl::opt<bool> +ArgStripDebug("strip-debug", + cl::desc("Omit debugger symbol information from the output file."), + cl::init(false)); + +static cl::alias +ArgStripDebugAlias("S", + cl::desc("alias for --strip-debug"), + cl::aliasopt(ArgStripDebug)); + +static cl::opt<bool> +ArgStripAll("strip-all", + cl::desc("Omit all symbol information from the output file."), + cl::init(false)); + +static cl::alias +ArgStripAllAlias("s", + cl::desc("alias for --strip-all"), + cl::aliasopt(ArgStripAll)); + +static cl::opt<bool> ArgNMagic("nmagic", cl::desc("Do not page align data"), cl::init(false)); @@ -541,15 +521,46 @@ ArgOMagicAlias("N", cl::desc("alias for --omagic"), cl::aliasopt(ArgOMagic)); +/// @{ +/// @name FIXME: begin of unsupported options +/// @} +static cl::opt<bool> +ArgGCSections("gc-sections", + cl::desc("Enable garbage collection of unused input sections."), + cl::init(false)); + static cl::opt<bool> -ArgStripDebug("strip-debug", - cl::desc("Omit debugger symbol information from the output file."), +ArgNoGCSections("no-gc-sections", + cl::desc("disable garbage collection of unused input sections."), cl::init(false)); -static cl::alias -ArgStripDebugAlias("S", - cl::desc("alias for --strip-debug"), - cl::aliasopt(ArgStripDebug)); +namespace icf { +enum Mode { + None, + All, + Safe +}; +} // namespace of icf + +static cl::opt<icf::Mode> +ArgICF("icf", + cl::ZeroOrMore, + cl::desc("Identical Code Folding"), + cl::init(icf::None), + cl::values( + clEnumValN(icf::None, "none", + "do not perform cold folding"), + clEnumValN(icf::All, "all", + "always preform cold folding"), + clEnumValN(icf::Safe, "safe", + "Folds ctors, dtors and functions whose pointers are definitely not taken."), + clEnumValEnd)); + +// FIXME: add this to target options? +static cl::opt<bool> +ArgFIXCA8("fix-cortex-a8", + cl::desc("Enable Cortex-A8 Thumb-2 branch erratum fix"), + cl::init(false)); static cl::opt<bool> ArgExportDynamic("export-dynamic", @@ -566,13 +577,9 @@ ArgEmulation("m", cl::desc("Set GNU linker emulation"), cl::value_desc("emulation")); -static cl::opt<std::string> -ArgRuntimePath("rpath", - cl::desc("Add a directory to the runtime library search path"), - cl::value_desc("dir")); - -static cl::opt<std::string> +static cl::list<std::string, bool, llvm::cl::SearchDirParser> ArgRuntimePathLink("rpath-link", + cl::ZeroOrMore, cl::desc("Add a directory to the link time library search path"), cl::value_desc("dir")); @@ -603,25 +610,108 @@ ArgVersionScript("version-script", cl::value_desc("Version script")); static cl::opt<bool> -ArgNoStdLib("nostdlib", - cl::desc("Only search lib dirs explicitly specified on cmdline"), - cl::init(false)); - -static cl::opt<bool> ArgWarnCommon("warn-common", cl::desc("warn common symbol"), cl::init(false)); +static cl::opt<mcld::GeneralOptions::HashStyle> +ArgHashStyle("hash-style", cl::init(mcld::GeneralOptions::SystemV), + cl::desc("Set the type of linker's hash table(s)."), + cl::values( + clEnumValN(mcld::GeneralOptions::SystemV, "sysv", + "classic ELF .hash section"), + clEnumValN(mcld::GeneralOptions::GNU, "gnu", + "new style GNU .gnu.hash section"), + clEnumValN(mcld::GeneralOptions::Both, "both", + "both the classic ELF and new style GNU hash tables"), + clEnumValEnd)); + +static cl::opt<std::string> +ArgFilter("F", + cl::desc("Filter for shared object symbol table"), + cl::value_desc("name")); + +static cl::alias +ArgFilterAlias("filter", + cl::desc("alias for -F"), + cl::aliasopt(ArgFilterAlias)); + +static cl::list<std::string> +ArgAuxiliary("f", + cl::ZeroOrMore, + cl::desc("Auxiliary filter for shared object symbol table"), + cl::value_desc("name")); + +static cl::alias +ArgAuxiliaryAlias("auxiliary", + cl::desc("alias for -f"), + cl::aliasopt(ArgAuxiliary)); + static cl::opt<bool> -ArgFatalWarnings("fatal-warnings", - cl::desc("turn all warnings into errors"), - cl::init(false)); +ArgEB("EB", + cl::desc("Link big-endian objects. This affects the default output format."), + cl::init(false)); + +static cl::opt<bool> +ArgEL("EL", + cl::desc("Link little-endian objects. This affects the default output format."), + cl::init(false)); /// @{ /// @name FIXME: end of unsupported options /// @} static cl::opt<bool> +ArgNoStdlib("nostdlib", + cl::desc("Only search lib dirs explicitly specified on cmdline"), + cl::init(false)); + +static cl::list<std::string, bool, llvm::cl::SearchDirParser> +ArgRuntimePath("rpath", + cl::ZeroOrMore, + cl::desc("Add a directory to the runtime library search path"), + cl::value_desc("dir")); + +static cl::alias +ArgRuntimePathAlias("R", + cl::desc("alias for --rpath"), + cl::aliasopt(ArgRuntimePath), cl::Prefix); + +static cl::opt<bool> +ArgEnableNewDTags("enable-new-dtags", + cl::desc("Enable use of DT_RUNPATH and DT_FLAGS"), + cl::init(false)); + +class FalseParser : public cl::parser<bool> { + const char *ArgStr; +public: + + // parse - Return true on error. + bool parse(cl::Option &O, StringRef ArgName, StringRef Arg, bool &Val) { + if (cl::parser<bool>::parse(O, ArgName, Arg, Val)) + return false; + Val = false; + return false; + } +}; + +static bool ArgFatalWarnings; + +static cl::opt<bool, true, FalseParser> +ArgNoFatalWarnings("no-fatal-warnings", + cl::location(ArgFatalWarnings), + cl::desc("do not turn warnings into errors"), + cl::init(false), + cl::ValueDisallowed); + +static cl::opt<bool, true> +ArgFatalWarnings_("fatal-warnings", + cl::location(ArgFatalWarnings), + cl::desc("turn all warnings into errors"), + cl::init(false), + cl::ValueDisallowed); + +static cl::opt<bool> ArgWarnSharedTextrel("warn-shared-textrel", cl::desc("Warn if adding DT_TEXTREL in a shared object."), cl::init(false)); @@ -895,8 +985,15 @@ static bool ProcessLinkerOptionsFromCommand(mcld::LinkerConfig& pConfig) { // set up soname pConfig.options().setSOName(ArgSOName); + // add all rpath entries + cl::list<std::string>::iterator rp; + cl::list<std::string>::iterator rpEnd = ArgRuntimePath.end(); + for (rp = ArgRuntimePath.begin(); rp != rpEnd; ++rp) { + pConfig.options().getRpathList().push_back(*rp); + } + // --fatal-warnings - pConfig.options().setFatalWarnings(ArgFatalWarnings); + // pConfig.options().setFatalWarnings(ArgFatalWarnings); // -shared or -pie if (true == ArgShared || true == ArgPIE) { @@ -952,10 +1049,22 @@ static bool ProcessLinkerOptionsFromCommand(mcld::LinkerConfig& pConfig) { pConfig.options().setEhFrameHdr(ArgEhFrameHdr); pConfig.options().setNMagic(ArgNMagic); pConfig.options().setOMagic(ArgOMagic); - pConfig.options().setStripDebug(ArgStripDebug); + pConfig.options().setStripDebug(ArgStripDebug || ArgStripAll); pConfig.options().setExportDynamic(ArgExportDynamic); pConfig.options().setWarnSharedTextrel(ArgWarnSharedTextrel); pConfig.options().setDefineCommon(ArgDefineCommon); + pConfig.options().setNewDTags(ArgEnableNewDTags); + pConfig.options().setHashStyle(ArgHashStyle); + pConfig.options().setNoStdlib(ArgNoStdlib); + + if (ArgStripAll) + pConfig.options().setStripSymbols(mcld::GeneralOptions::StripAllSymbols); + else if (ArgDiscardAll) + pConfig.options().setStripSymbols(mcld::GeneralOptions::StripLocals); + else if (ArgDiscardLocals) + pConfig.options().setStripSymbols(mcld::GeneralOptions::StripTemporaries); + else + pConfig.options().setStripSymbols(mcld::GeneralOptions::KeepAllSymbols); // set up rename map, for --wrap cl::list<std::string>::iterator wname; @@ -1034,14 +1143,6 @@ static bool ProcessLinkerOptionsFromCommand(mcld::LinkerConfig& pConfig) { mcld::warning(mcld::diag::warn_unsupported_option) << ArgFIXCA8.ArgStr; } - if (ArgDiscardLocals) { - mcld::warning(mcld::diag::warn_unsupported_option) << ArgDiscardLocals.ArgStr; - } - - if (ArgDiscardAll) { - mcld::warning(mcld::diag::warn_unsupported_option) << ArgDiscardAll.ArgStr; - } - // add address mappings // -Ttext if (-1U != ArgTextSegAddr) { @@ -1079,6 +1180,14 @@ static bool ProcessLinkerOptionsFromCommand(mcld::LinkerConfig& pConfig) { addr_mapping->setValue(address); } + // set up filter/aux filter for shared object + pConfig.options().setFilter(ArgFilter); + + cl::list<std::string>::iterator aux; + cl::list<std::string>::iterator auxEnd = ArgAuxiliary.end(); + for (aux = ArgAuxiliary.begin(); aux != auxEnd; ++aux) + pConfig.options().getAuxiliaryList().push_back(*aux); + return true; } diff --git a/tools/mcld/main.cpp b/tools/mcld/main.cpp index 58a9bb0..968c5e6 100644 --- a/tools/mcld/main.cpp +++ b/tools/mcld/main.cpp @@ -31,7 +31,7 @@ using namespace alone; // Compiler Options //===----------------------------------------------------------------------===// #ifdef TARGET_BUILD -static const std::string OptTargetTripe(DEFAULT_TARGET_TRIPLE_STRING); +static const std::string OptTargetTriple(DEFAULT_TARGET_TRIPLE_STRING); #else static llvm::cl::opt<std::string> OptTargetTriple("mtriple", @@ -253,10 +253,6 @@ bool ConfigLinker(Linker &pLinker, const std::string &pOutputFilename) { config->addSearchDir(*sdir); } - // set up default search directories - config->addSearchDir("=/lib"); - config->addSearchDir("=/usr/lib"); - // 7. Set up output's type. config->setShared(OptShared); diff --git a/unittests/ELFReaderTest.cpp b/unittests/ELFReaderTest.cpp new file mode 100644 index 0000000..fe7dd39 --- /dev/null +++ b/unittests/ELFReaderTest.cpp @@ -0,0 +1,162 @@ +//===- ELFReaderTest.cpp --------------------------------------------------===// +// +// The MCLinker Project +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#include <cstdio> + +#include <llvm/Support/ELF.h> +#include <mcld/IRBuilder.h> +#include <mcld/TargetOptions.h> +#include <mcld/LD/ELFReader.h> +#include <mcld/MC/MCLDInput.h> +#include <mcld/Support/Path.h> +#include <../lib/Target/X86/X86LDBackend.h> +#include <../lib/Target/X86/X86GNUInfo.h> + +#include "ELFReaderTest.h" + +using namespace mcld; +using namespace mcld::sys::fs; +using namespace mcldtest; + +// Constructor can do set-up work for all test here. +ELFReaderTest::ELFReaderTest() + : m_pInput(NULL) +{ + m_pConfig = new LinkerConfig("x86_64-linux-gnueabi"); + m_pConfig->targets().setEndian( TargetOptions::Little ); + m_pConfig->targets().setBitClass( 64 ); + Relocation::SetUp( *m_pConfig ); + + m_pInfo = new X86_64GNUInfo( m_pConfig->targets().triple() ); + m_pLDBackend = new X86_64GNULDBackend( *m_pConfig, m_pInfo ); + m_pELFReader = new ELFReader<64, true>( *m_pLDBackend ); + m_pModule = new Module(); + m_pIRBuilder = new IRBuilder( *m_pModule, *m_pConfig); + m_pELFObjReader = new ELFObjectReader(*m_pLDBackend, + *m_pIRBuilder, + *m_pConfig); +} + +// Destructor can do clean-up work that doesn't throw exceptions here. +ELFReaderTest::~ELFReaderTest() +{ + delete m_pConfig; + delete m_pLDBackend; + delete m_pELFReader; + delete m_pModule; + delete m_pIRBuilder; + delete m_pELFObjReader; +} + +// SetUp() will be called immediately before each test. +void ELFReaderTest::SetUp() +{ + Path path(TOPDIR); + path.append("unittests/test_x86_64.o"); + + m_pInput = m_pIRBuilder->ReadInput("test_x86_64", path); + ASSERT_TRUE(NULL!=m_pInput); + + ASSERT_TRUE(m_pInput->hasMemArea()); + size_t hdr_size = m_pELFReader->getELFHeaderSize(); + MemoryRegion* region = m_pInput->memArea()->request(m_pInput->fileOffset(), + hdr_size); + uint8_t* ELF_hdr = region->start(); + bool shdr_result = m_pELFReader->readSectionHeaders(*m_pInput, ELF_hdr); + m_pInput->memArea()->release(region); + ASSERT_TRUE(shdr_result); +} + +// TearDown() will be called immediately after each test. +void ELFReaderTest::TearDown() +{ +} + +//===----------------------------------------------------------------------===// +// Testcases +//===----------------------------------------------------------------------===// +TEST_F( ELFReaderTest, read_section_headers ) { + ASSERT_EQ(m_pInput->context()->numOfSections(), 13); + LDContext::const_sect_iterator iter = m_pInput->context()->sectBegin(); + ++iter; /// test section[1] + ASSERT_EQ(".text", (*iter)->name()); + ASSERT_EQ(llvm::ELF::SHT_PROGBITS, (*iter)->type()); + ASSERT_EQ(0x40, (*iter)->offset()); + ASSERT_EQ(0x15, (*iter)->size()); + ASSERT_TRUE(llvm::ELF::SHF_ALLOC & (*iter)->flag()); //AX + ASSERT_EQ(0x4, (*iter)->align()); + ASSERT_EQ(NULL, (*iter)->getLink()); + ASSERT_EQ(0, (*iter)->getInfo()); +} + +TEST_F( ELFReaderTest, read_symbol_and_rela ) +{ + ASSERT_TRUE(m_pInput->hasMemArea()); + ASSERT_TRUE(m_pInput->hasContext()); + m_pInput->setType(Input::Object); + + // -- read symbols + LDSection* symtab_shdr = m_pInput->context()->getSection(".symtab"); + ASSERT_TRUE(NULL!=symtab_shdr); + + LDSection* strtab_shdr = symtab_shdr->getLink(); + ASSERT_TRUE(NULL!=strtab_shdr); + + MemoryRegion* symtab_region = m_pInput->memArea()->request( + m_pInput->fileOffset() + symtab_shdr->offset(), + symtab_shdr->size()); + + MemoryRegion* strtab_region = m_pInput->memArea()->request( + m_pInput->fileOffset() + strtab_shdr->offset(), + strtab_shdr->size()); + char* strtab = reinterpret_cast<char*>(strtab_region->start()); + bool result = m_pELFReader->readSymbols(*m_pInput, *m_pIRBuilder, + *symtab_region, strtab); + ASSERT_TRUE(result); + ASSERT_EQ("hello.c", std::string(m_pInput->context()->getSymbol(1)->name())); + ASSERT_EQ("puts", std::string(m_pInput->context()->getSymbol(10)->name())); + ASSERT_TRUE(NULL==m_pInput->context()->getSymbol(11)); + m_pInput->memArea()->release(symtab_region); + m_pInput->memArea()->release(strtab_region); + + // -- read relocations + MemoryArea* mem = m_pInput->memArea(); + LDContext::sect_iterator rs = m_pInput->context()->relocSectBegin(); + ASSERT_TRUE(rs!=m_pInput->context()->relocSectEnd()); + ASSERT_EQ(".rela.text", (*rs)->name()); + + uint64_t offset = m_pInput->fileOffset() + (*rs)->offset(); + uint64_t size = (*rs)->size(); + MemoryRegion* region = mem->request(offset, size); + IRBuilder::CreateRelocData(**rs); /// create relocation data for the header + + ASSERT_EQ(llvm::ELF::SHT_RELA, (*rs)->type()); + ASSERT_TRUE(m_pELFReader->readRela(*m_pInput, **rs, *region)); + mem->release(region); + + const RelocData::RelocationListType &rRelocs = + (*rs)->getRelocData()->getRelocationList(); + RelocData::const_iterator rReloc = rRelocs.begin(); + ASSERT_EQ(2, rRelocs.size()); + ASSERT_TRUE(rRelocs.end()!=rReloc); + ++rReloc; /// test rRelocs[1] + ASSERT_EQ("puts", std::string(rReloc->symInfo()->name())); + ASSERT_EQ(llvm::ELF::R_X86_64_PC32, rReloc->type()); + ASSERT_EQ(0x0, rReloc->symValue()); + ASSERT_EQ(-0x4, rReloc->addend()); +} + +TEST_F( ELFReaderTest, read_regular_sections ) { + ASSERT_TRUE( m_pELFObjReader->readSections(*m_pInput) ); +} + +TEST_F( ELFReaderTest, is_my_format ) { + ASSERT_TRUE( m_pELFObjReader->isMyFormat(*m_pInput) ); +} + + diff --git a/unittests/ELFReaderTest.h b/unittests/ELFReaderTest.h new file mode 100644 index 0000000..c977cfb --- /dev/null +++ b/unittests/ELFReaderTest.h @@ -0,0 +1,56 @@ +//===- ELFReaderTest.h ----------------------------------------------------===// +// +// The MCLinker Project +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#ifndef MCLD_ELFREADER_TEST_H +#define MCLD_ELFREADER_TEST_H + +#include <gtest.h> +#include <mcld/LinkerConfig.h> +#include <mcld/LD/ELFReaderIf.h> +#include <mcld/LD/ELFReader.h> +#include <mcld/LD/ELFObjectReader.h> +#include <mcld/Target/GNULDBackend.h> +#include <mcld/MC/InputBuilder.h> + +namespace mcld { + class ELFReader<64, true>; +} // namespace for mcld + +namespace mcldtest +{ + +class ELFReaderTest : public ::testing::Test +{ +public: + // Constructor can do set-up work for all test here. + ELFReaderTest(); + + // Destructor can do clean-up work that doesn't throw exceptions here. + virtual ~ELFReaderTest(); + + // SetUp() will be called immediately before each test. + virtual void SetUp(); + + // TearDown() will be called immediately after each test. + virtual void TearDown(); + +protected: + mcld::Input *m_pInput; + mcld::LinkerConfig *m_pConfig; + mcld::GNUInfo *m_pInfo; + mcld::GNULDBackend *m_pLDBackend; + mcld::ELFReaderIF *m_pELFReader; + mcld::Module *m_pModule; + mcld::IRBuilder *m_pIRBuilder; + mcld::ELFObjectReader *m_pELFObjReader; +}; + +} // namespace of mcldtest + +#endif + diff --git a/unittests/FileHandleTest.cpp b/unittests/FileHandleTest.cpp index db6f25f..dc9ecdd 100644 --- a/unittests/FileHandleTest.cpp +++ b/unittests/FileHandleTest.cpp @@ -48,6 +48,7 @@ TEST_F(FileHandleTest, open_close) { ASSERT_TRUE(m_pTestee->open(path, FileHandle::ReadOnly)); ASSERT_TRUE(m_pTestee->isOpened()); ASSERT_TRUE(m_pTestee->isGood()); + ASSERT_TRUE(m_pTestee->isOwned()); ASSERT_TRUE(27 == m_pTestee->size()); @@ -67,19 +68,19 @@ TEST_F(FileHandleTest, delegate_close) { ASSERT_TRUE(m_pTestee->delegate(fd, FileHandle::ReadOnly)); ASSERT_TRUE(m_pTestee->isOpened()); ASSERT_TRUE(m_pTestee->isGood()); + ASSERT_FALSE(m_pTestee->isOwned()); ASSERT_TRUE(27 == m_pTestee->size()); ASSERT_TRUE(m_pTestee->close()); ASSERT_FALSE(m_pTestee->isOpened()); ASSERT_TRUE(m_pTestee->isGood()); + ASSERT_TRUE(m_pTestee->isOwned()); ASSERT_TRUE(0 == m_pTestee->size()); int close_result = ::close(fd); - int close_err = errno; - ASSERT_EQ(-1, close_result); - ASSERT_EQ(EBADF, close_err); + ASSERT_EQ(0, close_result); } TEST_F(FileHandleTest, fail_close) { diff --git a/unittests/LinkerTest.cpp b/unittests/LinkerTest.cpp index 00ba23b..ab439cb 100644 --- a/unittests/LinkerTest.cpp +++ b/unittests/LinkerTest.cpp @@ -84,6 +84,11 @@ TEST_F( LinkerTest, plasma) { ///< --mtriple="armv7-none-linux-gnueabi" LinkerConfig config("armv7-none-linux-gnueabi"); + /// -L=${TOPDIR}/test/libs/ARM/Android/android-14 + Path search_dir(TOPDIR); + search_dir.append("test/libs/ARM/Android/android-14"); + config.options().directories().insert(search_dir); + /// To configure linker before setting options. Linker::config sets up /// default target-dependent configuration to LinkerConfig. linker.config(config); @@ -92,11 +97,6 @@ TEST_F( LinkerTest, plasma) { config.options().setSOName("libplasma.so"); ///< --soname=libplasma.so config.options().setBsymbolic(); ///< -Bsymbolic - /// -L=${TOPDIR}/test/libs/ARM/Android/android-14 - Path search_dir(TOPDIR); - search_dir.append("test/libs/ARM/Android/android-14"); - config.options().directories().insert(search_dir); - Module module("libplasma.so"); IRBuilder builder(module, config); @@ -141,6 +141,11 @@ TEST_F( LinkerTest, plasma_twice) { ///< --mtriple="armv7-none-linux-gnueabi" LinkerConfig config1("armv7-none-linux-gnueabi"); + /// -L=${TOPDIR}/test/libs/ARM/Android/android-14 + Path search_dir(TOPDIR); + search_dir.append("test/libs/ARM/Android/android-14"); + config1.options().directories().insert(search_dir); + /// To configure linker before setting options. Linker::config sets up /// default target-dependent configuration to LinkerConfig. linker.config(config1); @@ -149,11 +154,6 @@ TEST_F( LinkerTest, plasma_twice) { config1.options().setSOName("libplasma.once.so"); ///< --soname=libplasma.twice.so config1.options().setBsymbolic(false); ///< -Bsymbolic - /// -L=${TOPDIR}/test/libs/ARM/Android/android-14 - Path search_dir(TOPDIR); - search_dir.append("test/libs/ARM/Android/android-14"); - config1.options().directories().insert(search_dir); - Module module1("libplasma.once.so"); IRBuilder builder1(module1, config1); @@ -191,6 +191,9 @@ TEST_F( LinkerTest, plasma_twice) { ///< --mtriple="armv7-none-linux-gnueabi" LinkerConfig config2("armv7-none-linux-gnueabi"); + /// -L=${TOPDIR}/test/libs/ARM/Android/android-14 + config2.options().directories().insert(search_dir); + /// To configure linker before setting options. Linker::config sets up /// default target-dependent configuration to LinkerConfig. linker.config(config2); @@ -199,9 +202,6 @@ TEST_F( LinkerTest, plasma_twice) { config2.options().setSOName("libplasma.twice.so"); ///< --soname=libplasma.twice.exe config2.options().setBsymbolic(); ///< -Bsymbolic - /// -L=${TOPDIR}/test/libs/ARM/Android/android-14 - config2.options().directories().insert(search_dir); - Module module2("libplasma.so"); IRBuilder builder2(module2, config2); @@ -236,6 +236,11 @@ TEST_F( LinkerTest, plasma_twice_irbuilder_heap) { ///< --mtriple="armv7-none-linux-gnueabi" LinkerConfig config1("armv7-none-linux-gnueabi"); + /// -L=${TOPDIR}/test/libs/ARM/Android/android-14 + Path search_dir(TOPDIR); + search_dir.append("test/libs/ARM/Android/android-14"); + config1.options().directories().insert(search_dir); + /// To configure linker before setting options. Linker::config sets up /// default target-dependent configuration to LinkerConfig. linker.config(config1); @@ -244,11 +249,6 @@ TEST_F( LinkerTest, plasma_twice_irbuilder_heap) { config1.options().setSOName("libplasma.once.so"); ///< --soname=libplasma.twice.so config1.options().setBsymbolic(false); ///< -Bsymbolic - /// -L=${TOPDIR}/test/libs/ARM/Android/android-14 - Path search_dir(TOPDIR); - search_dir.append("test/libs/ARM/Android/android-14"); - config1.options().directories().insert(search_dir); - Module module1("libplasma.once.so"); IRBuilder *builder1 = new IRBuilder(module1, config1); @@ -291,6 +291,9 @@ TEST_F( LinkerTest, plasma_twice_irbuilder_heap) { ///< --mtriple="armv7-none-linux-gnueabi" LinkerConfig config2("armv7-none-linux-gnueabi"); + /// -L=${TOPDIR}/test/libs/ARM/Android/android-14 + config2.options().directories().insert(search_dir); + /// To configure linker before setting options. Linker::config sets up /// default target-dependent configuration to LinkerConfig. linker.config(config2); @@ -299,9 +302,6 @@ TEST_F( LinkerTest, plasma_twice_irbuilder_heap) { config2.options().setSOName("libplasma.twice.so"); ///< --soname=libplasma.twice.exe config2.options().setBsymbolic(); ///< -Bsymbolic - /// -L=${TOPDIR}/test/libs/ARM/Android/android-14 - config2.options().directories().insert(search_dir); - Module module2("libplasma.so"); IRBuilder* builder2 = new IRBuilder(module2, config2); diff --git a/unittests/SymbolCategoryTest.cpp b/unittests/SymbolCategoryTest.cpp index 07f479b..fae146b 100644 --- a/unittests/SymbolCategoryTest.cpp +++ b/unittests/SymbolCategoryTest.cpp @@ -80,13 +80,13 @@ TEST_F(SymbolCategoryTest, upward_test) { ++sym; ASSERT_STREQ("e", (*sym)->name()); - ASSERT_TRUE(2 == m_pTestee->numOfLocals()); + ASSERT_TRUE(1 == m_pTestee->numOfLocals()); ASSERT_TRUE(1 == m_pTestee->numOfCommons()); - ASSERT_TRUE(2 == m_pTestee->numOfRegulars()); + ASSERT_TRUE(2 == m_pTestee->numOfDynamics()); ASSERT_TRUE(5 == m_pTestee->numOfSymbols()); } -TEST_F(SymbolCategoryTest, change_local_to_tls) { +TEST_F(SymbolCategoryTest, change_local_to_dynamic) { ResolveInfo* a = ResolveInfo::Create("a"); ResolveInfo* b = ResolveInfo::Create("b"); ResolveInfo* c = ResolveInfo::Create("c"); @@ -129,7 +129,7 @@ TEST_F(SymbolCategoryTest, change_local_to_tls) { ++sym; ASSERT_STREQ("e", (*sym)->name()); - m_pTestee->changeLocalToTLS(*bb); + m_pTestee->changeLocalToDynamic(*bb); sym = m_pTestee->begin(); ASSERT_STREQ("c", (*sym)->name()); diff --git a/unittests/test b/unittests/test new file mode 100644 index 0000000..d2a5b5d --- /dev/null +++ b/unittests/test @@ -0,0 +1,8 @@ +0x41, 0x1f, 0x00, 0x00, +0x00, 0x61, 0x65, 0x61, +0x62, 0x69, 0x00, 0x01, +0x15, 0x00, 0x00, 0x00, +0x06, 0x02, 0x08, 0x01, +0x09, 0x01, 0x14, 0x01, +0x15, 0x01, 0x17, 0x03, +0x18, 0x01, 0x19, 0x01, diff --git a/unittests/test_x86_64.o b/unittests/test_x86_64.o Binary files differnew file mode 100644 index 0000000..18389aa --- /dev/null +++ b/unittests/test_x86_64.o |