//===- MipsGOT.h ----------------------------------------------------------===// // // The MCLinker Project // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #ifndef TARGET_MIPS_MIPSGOT_H #define TARGET_MIPS_MIPSGOT_H #include #include #include #include #include #include #include #include #include namespace mcld { class Input; class LDSection; class LDSymbol; class OutputRelocSection; /** \class MipsGOT * \brief Mips Global Offset Table. */ class MipsGOT : public GOT { public: MipsGOT(LDSection& pSection); /// Assign value to the GOT entry. virtual void setEntryValue(Fragment* entry, uint64_t pValue) = 0; /// Emit the global offset table. virtual uint64_t emit(MemoryRegion& pRegion) = 0; /// Address of _gp_disp symbol. uint64_t getGPDispAddress() const; void initializeScan(const Input& pInput); void finalizeScan(const Input& pInput); bool reserveLocalEntry(ResolveInfo& pInfo, int reloc, Relocation::DWord pAddend); bool reserveGlobalEntry(ResolveInfo& pInfo); size_t getLocalNum() const; ///< number of local symbols in primary GOT size_t getGlobalNum() const; ///< total number of global symbols bool isPrimaryGOTConsumed(); Fragment* consumeLocal(); Fragment* consumeGlobal(); uint64_t getGPAddr(const Input& pInput) const; uint64_t getGPRelOffset(const Input& pInput, const Fragment& pEntry) const; void recordGlobalEntry(const ResolveInfo* pInfo, Fragment* pEntry); Fragment* lookupGlobalEntry(const ResolveInfo* pInfo); void recordLocalEntry(const ResolveInfo* pInfo, Relocation::DWord pAddend, Fragment* pEntry); Fragment* lookupLocalEntry(const ResolveInfo* pInfo, Relocation::DWord pAddend); /// hasGOT1 - return if this got section has any GOT1 entry bool hasGOT1() const; bool hasMultipleGOT() const; /// Create GOT entries and reserve dynrel entries. void finalizeScanning(OutputRelocSection& pRelDyn); /// Compare two symbols to define order in the .dynsym. bool dynSymOrderCompare(const LDSymbol* pX, const LDSymbol* pY) const; protected: /// Create GOT entry. virtual Fragment* createEntry(uint64_t pValue, SectionData* pParent) = 0; /// Size of GOT entry. virtual size_t getEntrySize() const = 0; /// Reserve GOT header entries. virtual void reserveHeader() = 0; private: /** \class GOTMultipart * \brief GOTMultipart counts local and global entries in the GOT. */ struct GOTMultipart { GOTMultipart(size_t local = 0, size_t global = 0); typedef llvm::DenseSet InputSetType; size_t m_LocalNum; ///< number of reserved local entries size_t m_GlobalNum; ///< number of reserved global entries size_t m_ConsumedLocal; ///< consumed local entries size_t m_ConsumedGlobal; ///< consumed global entries Fragment* m_pLastLocal; ///< the last consumed local entry Fragment* m_pLastGlobal; ///< the last consumed global entry InputSetType m_Inputs; bool isConsumed() const; void consumeLocal(); void consumeGlobal(); }; /** \class LocalEntry * \brief LocalEntry local GOT entry descriptor. */ struct LocalEntry { const ResolveInfo* m_pInfo; Relocation::DWord m_Addend; bool m_IsGot16; LocalEntry(const ResolveInfo* pInfo, Relocation::DWord addend, bool isGot16); bool operator<(const LocalEntry &O) const; }; typedef std::vector MultipartListType; // Set of global symbols. typedef llvm::DenseSet SymbolSetType; // Map of symbols. If value is true, the symbol is referenced // in the current input only. If value is false, the symbol // is referenced in the other modules merged to the current GOT. typedef llvm::DenseMap SymbolUniqueMapType; // Set of local symbols. typedef std::set LocalSymbolSetType; MultipartListType m_MultipartList; ///< list of GOT's descriptors const Input* m_pInput; ///< current input // Global symbols merged to the current GOT // except symbols from the current input. SymbolSetType m_MergedGlobalSymbols; // Global symbols from the current input. SymbolUniqueMapType m_InputGlobalSymbols; // Local symbols merged to the current GOT // except symbols from the current input. LocalSymbolSetType m_MergedLocalSymbols; // Local symbols from the current input. LocalSymbolSetType m_InputLocalSymbols; size_t m_CurrentGOTPart; typedef llvm::DenseMap SymbolOrderMapType; SymbolOrderMapType m_SymbolOrderMap; void initGOTList(); void changeInput(); bool isGOTFull() const; void split(); void reserve(size_t pNum); private: struct GotEntryKey { size_t m_GOTPage; const ResolveInfo* m_pInfo; Relocation::DWord m_Addend; bool operator<(const GotEntryKey& key) const { if (m_GOTPage != key.m_GOTPage) return m_GOTPage < key.m_GOTPage; if (m_pInfo != key.m_pInfo) return m_pInfo < key.m_pInfo; return m_Addend < key.m_Addend; } }; typedef std::map GotEntryMapType; GotEntryMapType m_GotLocalEntriesMap; GotEntryMapType m_GotGlobalEntriesMap; }; /** \class Mips32GOT * \brief Mips 32-bit Global Offset Table. */ class Mips32GOT : public MipsGOT { public: Mips32GOT(LDSection& pSection); private: typedef GOT::Entry<4> Mips32GOTEntry; // MipsGOT virtual void setEntryValue(Fragment* entry, uint64_t pValue); virtual uint64_t emit(MemoryRegion& pRegion); virtual Fragment* createEntry(uint64_t pValue, SectionData* pParent); virtual size_t getEntrySize() const; virtual void reserveHeader(); }; /** \class Mips64GOT * \brief Mips 64-bit Global Offset Table. */ class Mips64GOT : public MipsGOT { public: Mips64GOT(LDSection& pSection); private: typedef GOT::Entry<8> Mips64GOTEntry; // MipsGOT virtual void setEntryValue(Fragment* entry, uint64_t pValue); virtual uint64_t emit(MemoryRegion& pRegion); virtual Fragment* createEntry(uint64_t pValue, SectionData* pParent); virtual size_t getEntrySize() const; virtual void reserveHeader(); }; } // namespace of mcld #endif