//===- MipsLDBackend.h ----------------------------------------------------===// // // The MCLinker Project // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #ifndef TARGET_MIPS_MIPSLDBACKEND_H_ #define TARGET_MIPS_MIPSLDBACKEND_H_ #include <llvm/Support/ELF.h> #include "mcld/Target/GNULDBackend.h" #include "MipsAbiFlags.h" #include "MipsELFDynamic.h" #include "MipsGOT.h" #include "MipsGOTPLT.h" #include "MipsPLT.h" namespace mcld { class LinkerConfig; class MemoryArea; class MipsGNUInfo; class OutputRelocSection; class SectionMap; /** \class MipsGNULDBackend * \brief Base linker backend of Mips target of GNU ELF format. */ class MipsGNULDBackend : public GNULDBackend { public: typedef std::vector<LDSymbol*> SymbolListType; public: MipsGNULDBackend(const LinkerConfig& pConfig, MipsGNUInfo* pInfo); ~MipsGNULDBackend(); bool needsLA25Stub(Relocation::Type pType, const mcld::ResolveInfo* pSym); void addNonPICBranchSym(ResolveInfo* rsym); bool hasNonPICBranch(const ResolveInfo* rsym) const; public: /// initTargetSections - initialize target dependent sections in output void initTargetSections(Module& pModule, ObjectBuilder& pBuilder); /// initTargetSymbols - initialize target dependent symbols in output. void initTargetSymbols(IRBuilder& pBuilder, Module& pModule); /// getRelocator - return relocator. const Relocator* getRelocator() const; Relocator* getRelocator(); /// 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. MipsELFDynamic& dynamic(); /// dynamic - the dynamic section of the target machine. /// Use co-variant return type to return its own dynamic section. const MipsELFDynamic& 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 SectionData 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 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; /// hasEntryInStrTab - symbol has an entry in a .strtab bool hasEntryInStrTab(const LDSymbol& pSym) const; /// orderSymbolTable - order symbol table before emitting void orderSymbolTable(Module& pModule); /// readSection - read a target dependent section. bool readSection(Input& pInput, SectionData& pSD); MipsGOT& getGOT(); const MipsGOT& getGOT() const; MipsPLT& getPLT(); const MipsPLT& getPLT() const; MipsGOTPLT& getGOTPLT(); const MipsGOTPLT& getGOTPLT() const; OutputRelocSection& getRelPLT(); const OutputRelocSection& getRelPLT() const; OutputRelocSection& getRelDyn(); const OutputRelocSection& getRelDyn() const; LDSymbol* getGOTSymbol() { return m_pGOTSymbol; } const LDSymbol* getGOTSymbol() const { return m_pGOTSymbol; } LDSymbol* getGpDispSymbol() { return m_pGpDispSymbol; } const LDSymbol* getGpDispSymbol() const { return m_pGpDispSymbol; } SymbolListType& getGlobalGOTSyms() { return m_GlobalGOTSyms; } const SymbolListType& getGlobalGOTSyms() const { return m_GlobalGOTSyms; } /// getTargetSectionOrder - compute the layout order of ARM target sections unsigned int getTargetSectionOrder(const LDSection& pSectHdr) const; /// finalizeSymbol - finalize the symbol value bool finalizeTargetSymbols(); /// allocateCommonSymbols - allocate common symbols in the corresponding /// sections. bool allocateCommonSymbols(Module& pModule); /// getTPOffset - return TP_OFFSET against the SHF_TLS /// section in the specified input. uint64_t getTPOffset(const Input& pInput) const; /// getDTPOffset - return DTP_OFFSET against the SHF_TLS /// section in the specified input. uint64_t getDTPOffset(const Input& pInput) const; /// getGP0 - the gp value used to create the relocatable objects /// in the specified input. uint64_t getGP0(const Input& pInput) const; private: void defineGOTSymbol(IRBuilder& pBuilder); void defineGOTPLTSymbol(IRBuilder& pBuilder); bool relaxRelocation(IRBuilder& pBuilder, Relocation& pRel); /// emitSymbol32 - emit an ELF32 symbol, override parent's function void emitSymbol32(llvm::ELF::Elf32_Sym& pSym32, LDSymbol& pSymbol, char* pStrtab, size_t pStrtabsize, size_t pSymtabIdx); /// doCreateProgramHdrs - backend can implement this function to create the /// target-dependent segments void doCreateProgramHdrs(Module& pModule); /// mayRelax - Backends should override this function if they need relaxation bool mayRelax() { return true; } /// doRelax - Backend can orevride this function to add its relaxation /// 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, IRBuilder& pBuilder, bool& pFinished); /// initTargetStubs bool initTargetStubs(); /// readRelocation - read ELF32_Rel entry bool readRelocation(const llvm::ELF::Elf32_Rel& pRel, Relocation::Type& pType, uint32_t& pSymIdx, uint32_t& pOffset) const; /// readRelocation - read ELF32_Rela entry bool readRelocation(const llvm::ELF::Elf32_Rela& pRel, Relocation::Type& pType, uint32_t& pSymIdx, uint32_t& pOffset, int32_t& pAddend) const; /// readRelocation - read ELF64_Rel entry bool readRelocation(const llvm::ELF::Elf64_Rel& pRel, Relocation::Type& pType, uint32_t& pSymIdx, uint64_t& pOffset) const; /// readRel - read ELF64_Rela entry bool readRelocation(const llvm::ELF::Elf64_Rela& pRel, Relocation::Type& pType, uint32_t& pSymIdx, uint64_t& pOffset, int64_t& pAddend) const; /// emitRelocation - write data to the ELF32_Rel entry void emitRelocation(llvm::ELF::Elf32_Rel& pRel, Relocation::Type pType, uint32_t pSymIdx, uint32_t pOffset) const; /// emitRelocation - write data to the ELF32_Rela entry void emitRelocation(llvm::ELF::Elf32_Rela& pRel, Relocation::Type pType, uint32_t pSymIdx, uint32_t pOffset, int32_t pAddend) const; /// emitRelocation - write data to the ELF64_Rel entry void emitRelocation(llvm::ELF::Elf64_Rel& pRel, Relocation::Type pType, uint32_t pSymIdx, uint64_t pOffset) const; /// emitRelocation - write data to the ELF64_Rela entry void emitRelocation(llvm::ELF::Elf64_Rela& pRel, Relocation::Type pType, uint32_t pSymIdx, uint64_t pOffset, int64_t pAddend) const; /// preMergeSections - hooks to be executed before merging sections void preMergeSections(Module& pModule); /// mergeSection - merge target dependent sections bool mergeSection(Module& pModule, const Input& pInput, LDSection& pSection); protected: virtual void mergeFlags(Input& pInput, const char* ELF_hdr); private: typedef llvm::DenseSet<const ResolveInfo*> ResolveInfoSetType; typedef llvm::DenseMap<const Input*, llvm::ELF::Elf64_Addr> InputNumMapType; typedef llvm::DenseMap<const Input*, uint64_t> ElfFlagsMapType; protected: Relocator* m_pRelocator; MipsGOT* m_pGOT; // .got MipsPLT* m_pPLT; // .plt MipsGOTPLT* m_pGOTPLT; // .got.plt private: MipsGNUInfo& m_pInfo; llvm::Optional<MipsAbiFlags> m_pAbiInfo; OutputRelocSection* m_pRelPlt; // .rel.plt OutputRelocSection* m_pRelDyn; // .rel.dyn MipsELFDynamic* m_pDynamic; LDSection* m_psdata; LDSection* m_pAbiFlags; LDSymbol* m_pGOTSymbol; LDSymbol* m_pPLTSymbol; LDSymbol* m_pGpDispSymbol; SymbolListType m_GlobalGOTSyms; ResolveInfoSetType m_HasNonPICBranchSyms; InputNumMapType m_GP0Map; InputNumMapType m_TpOffsetMap; InputNumMapType m_DtpOffsetMap; ElfFlagsMapType m_ElfFlagsMap; void moveSectionData(SectionData& pFrom, SectionData& pTo); void saveTPOffset(const Input& pInput); }; /** \class Mips32GNULDBackend * \brief Base linker backend of Mips 32-bit target of GNU ELF format. */ class Mips32GNULDBackend : public MipsGNULDBackend { public: Mips32GNULDBackend(const LinkerConfig& pConfig, MipsGNUInfo* pInfo); private: // MipsGNULDBackend bool initRelocator(); void initTargetSections(Module& pModule, ObjectBuilder& pBuilder); size_t getRelEntrySize(); size_t getRelaEntrySize(); }; /** \class Mips64GNULDBackend * \brief Base linker backend of Mips 64-bit target of GNU ELF format. */ class Mips64GNULDBackend : public MipsGNULDBackend { public: Mips64GNULDBackend(const LinkerConfig& pConfig, MipsGNUInfo* pInfo); private: // MipsGNULDBackend bool initRelocator(); void initTargetSections(Module& pModule, ObjectBuilder& pBuilder); size_t getRelEntrySize(); size_t getRelaEntrySize(); }; } // namespace mcld #endif // TARGET_MIPS_MIPSLDBACKEND_H_