//===- GNULDBackend.h -----------------------------------------------------===// // // The MCLinker Project // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #ifndef MCLD_TARGET_GNU_LDBACKEND_H #define MCLD_TARGET_GNU_LDBACKEND_H #ifdef ENABLE_UNITTEST #include <gtest.h> #endif #include <mcld/Target/TargetLDBackend.h> #include <llvm/Support/ELF.h> #include <mcld/ADT/HashTable.h> #include <mcld/ADT/HashEntry.h> #include <mcld/LD/ELFDynObjFileFormat.h> #include <mcld/LD/ELFExecFileFormat.h> #include <mcld/LD/ELFObjectFileFormat.h> #include <mcld/LD/GNUArchiveReader.h> #include <mcld/LD/ELFObjectReader.h> #include <mcld/LD/ELFDynObjReader.h> #include <mcld/LD/ELFBinaryReader.h> #include <mcld/LD/ELFObjectWriter.h> #include <mcld/LD/ELFSegment.h> #include <mcld/LD/ELFSegmentFactory.h> #include <mcld/Target/ELFDynamic.h> #include <mcld/Target/GNUInfo.h> #include <mcld/Support/GCFactory.h> #include <mcld/Module.h> namespace mcld { class Module; class LinkerConfig; class IRBuilder; class Layout; class EhFrameHdr; class BranchIslandFactory; class StubFactory; class GNUInfo; /** \class GNULDBackend * \brief GNULDBackend provides a common interface for all GNU Unix-OS * LDBackend. */ class GNULDBackend : public TargetLDBackend { protected: GNULDBackend(const LinkerConfig& pConfig, GNUInfo* pInfo); public: virtual ~GNULDBackend(); // ----- readers/writers ----- // GNUArchiveReader* createArchiveReader(Module& pModule); ELFObjectReader* createObjectReader(IRBuilder& pBuilder); ELFDynObjReader* createDynObjReader(IRBuilder& pBuilder); ELFBinaryReader* createBinaryReader(IRBuilder& pBuilder); ELFObjectWriter* createWriter(); // ----- output sections ----- // /// initStdSections - initialize standard sections of the output file. bool initStdSections(ObjectBuilder& pBuilder); /// getOutputFormat - get the sections of the output file. const ELFFileFormat* getOutputFormat() const; ELFFileFormat* getOutputFormat(); // ----- target symbols ----- // /// 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. 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(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() { return (finalizeStandardSymbols() && finalizeTargetSymbols()); } /// finalizeStandardSymbols - set the value of standard symbols virtual bool finalizeStandardSymbols(); /// finalizeTargetSymbols - set the value of target symbols virtual bool finalizeTargetSymbols() = 0; /// finalizeTLSSymbol - set the value of a TLS symbol virtual bool finalizeTLSSymbol(LDSymbol& pSymbol); size_t sectionStartOffset() const; const GNUInfo& getInfo() const { return *m_pInfo; } GNUInfo& getInfo() { return *m_pInfo; } bool hasTextRel() const { return m_bHasTextRel; } bool hasStaticTLS() const { return m_bHasStaticTLS; } /// getSegmentStartAddr - this function returns the start address of the segment uint64_t getSegmentStartAddr(const LinkerScript& pScript) const; /// 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(Module& pModule); /// 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); /// emitNamePools - emit dynamic name pools - .dyntab, .dynstr, .hash 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 virtual void sizeInterp(); /// emitInterp - emit the .interp virtual void emitInterp(MemoryArea& pOutput); /// hasEntryInStrTab - symbol has an entry in a .strtab virtual bool hasEntryInStrTab(const LDSymbol& pSym) const; /// orderSymbolTable - order symbol table before emitting virtual void orderSymbolTable(Module& pModule); void setHasStaticTLS(bool pVal = true) { m_bHasStaticTLS = pVal; } /// getSectionOrder - compute the layout order of the section /// Layout calls this function to get the default order of the pSectHdr. /// If the pSectHdr.type() is LDFileFormat::Target, then getSectionOrder() /// will call getTargetSectionOrder(). /// /// If targets favors certain order for general sections, please override /// this function. /// /// @see getTargetSectionOrder virtual unsigned int getSectionOrder(const LDSection& pSectHdr) const; /// getTargetSectionOrder - compute the layout order of target section /// If the target favors certain order for the given gSectHdr, please /// override this function. /// /// By default, this function returns the maximun order, and pSectHdr /// will be the last section to be laid out. virtual unsigned int getTargetSectionOrder(const LDSection& pSectHdr) const { return (unsigned int)-1; } /// numOfSegments - return the number of segments /// if the target favors other ways to emit program header, please override /// this function size_t numOfSegments() const { return m_ELFSegmentTable.size(); } /// elfSegmentTable - return the reference of the elf segment table ELFSegmentFactory& elfSegmentTable() { return m_ELFSegmentTable; } /// elfSegmentTable - return the reference of the elf segment table const ELFSegmentFactory& elfSegmentTable() const { return m_ELFSegmentTable; } /// commonPageSize - the common page size of the target machine uint64_t commonPageSize() 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(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); /// symbolNeedsPLT - return whether the symbol needs a PLT entry /// @ref Google gold linker, symtab.h:596 bool symbolNeedsPLT(const ResolveInfo& pSym) const; /// symbolNeedsCopyReloc - return whether the symbol needs a copy relocation bool symbolNeedsCopyReloc(const Relocation& pReloc, const ResolveInfo& pSym) const; /// symbolNeedsDynRel - return whether the symbol needs a dynamic relocation /// @ref Google gold linker, symtab.h:645 bool symbolNeedsDynRel(const ResolveInfo& pSym, bool pSymHasPLT, bool isAbsReloc) const; /// isSymbolPreemtible - whether the symbol can be preemted by other /// link unit /// @ref Google gold linker, symtab.h:551 bool isSymbolPreemptible(const ResolveInfo& pSym) const; /// symbolHasFinalValue - return true if the symbol's value can be decided at /// link time bool symbolFinalValueIsKnown(const ResolveInfo& pSym) const; /// isDynamicSymbol /// @ref Google gold linker: symtab.cc:311 bool isDynamicSymbol(const LDSymbol& pSymbol); /// isDynamicSymbol /// @ref Google gold linker: symtab.cc:311 bool isDynamicSymbol(const ResolveInfo& pResolveInfo); virtual ResolveInfo::Desc getSymDesc(uint16_t pShndx) const { return ResolveInfo::Define; } bool hasTDATASymbol() const { return (NULL != f_pTDATA); } bool hasTBSSSymbol() const { return (NULL != f_pTBSS); } void setTDATASymbol(LDSymbol& pTDATA) { f_pTDATA = &pTDATA; } void setTBSSSymbol(LDSymbol& pTBSS) { f_pTBSS = &pTBSS; } // getTDATASymbol - get section symbol of .tdata LDSymbol& getTDATASymbol(); const LDSymbol& getTDATASymbol() const; /// getTBSSSymbol - get section symbol of .tbss LDSymbol& getTBSSSymbol(); const LDSymbol& getTBSSSymbol() const; // ----- relaxation ----- // /// initBRIslandFactory - initialize the branch island factory for relaxation bool initBRIslandFactory(); /// initStubFactory - initialize the stub factory for relaxation bool initStubFactory(); /// getBRIslandFactory BranchIslandFactory* getBRIslandFactory() { return m_pBRIslandFactory; } /// getStubFactory StubFactory* getStubFactory() { return m_pStubFactory; } /// maxBranchOffset - return the max (forward) branch offset of the backend. /// Target can override this function if needed. virtual uint64_t maxBranchOffset() { return (uint64_t)-1; } /// checkAndSetHasTextRel - check pSection flag to set HasTextRel void checkAndSetHasTextRel(const LDSection& pSection); protected: uint64_t getSymbolSize(const LDSymbol& pSymbol) const; uint64_t getSymbolInfo(const LDSymbol& pSymbol) const; uint64_t getSymbolValue(const LDSymbol& pSymbol) const; 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; /// emitSymbol32 - emit an ELF32 symbol void emitSymbol32(llvm::ELF::Elf32_Sym& pSym32, LDSymbol& pSymbol, char* pStrtab, size_t pStrtabsize, size_t pSymtabIdx); /// emitSymbol64 - emit an ELF64 symbol void emitSymbol64(llvm::ELF::Elf64_Sym& pSym64, LDSymbol& pSymbol, char* pStrtab, size_t pStrtabsize, size_t pSymtabIdx); private: /// createProgramHdrs - base on output sections to create the program headers void createProgramHdrs(Module& pModule); /// doCreateProgramHdrs - backend can implement this function to create the /// target-dependent segments 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 LinkerScript& pScript); /// getSegmentFlag - give a section flag and return the corresponding segment /// flag inline uint32_t getSegmentFlag(const uint32_t pSectionFlag) { uint32_t flag = llvm::ELF::PF_R; if (0 != (pSectionFlag & llvm::ELF::SHF_WRITE)) flag |= llvm::ELF::PF_W; if (0 != (pSectionFlag & llvm::ELF::SHF_EXECINSTR)) flag |= llvm::ELF::PF_X; return flag; } /// setupGNUStackInfo - setup the section flag of .note.GNU-stack in output void setupGNUStackInfo(Module& pModule); /// setupRelro - setup the offset constraint of PT_RELRO void setupRelro(Module& pModule); /// setOutputSectionOffset - helper function to set a group of output sections' /// offset, and set pSectBegin to pStartOffset if pStartOffset is not -1U. void setOutputSectionOffset(Module& pModule, Module::iterator pSectBegin, Module::iterator pSectEnd, uint64_t pStartOffset = -1U); /// setOutputSectionOffset - helper function to set output sections' address. void setOutputSectionAddress(Module& pModule, Module::iterator pSectBegin, Module::iterator pSectEnd); /// layout - layout method void layout(Module& pModule); /// preLayout - Backend can do any needed modification before layout void preLayout(Module& pModule, IRBuilder& pBuilder); /// postLayout -Backend can do any needed modification after layout void postLayout(Module& pModule, IRBuilder& pBuilder); /// preLayout - Backend can do any needed modification before layout virtual void doPreLayout(IRBuilder& pBuilder) = 0; /// postLayout -Backend can do any needed modification after layout virtual void doPostLayout(Module& pModule, IRBuilder& pLinker) = 0; /// postProcessing - Backend can do any needed modification in the final stage void postProcessing(MemoryArea& pOutput); /// dynamic - the dynamic section of the target machine. virtual ELFDynamic& dynamic() = 0; /// dynamic - the dynamic section of the target machine. virtual const ELFDynamic& dynamic() const = 0; /// relax - the relaxation pass bool relax(Module& pModule, IRBuilder& pBuilder); /// mayRelax - Backends should override this function if they need relaxation virtual bool mayRelax() { return false; } /// 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. virtual bool doRelax(Module& pModule, IRBuilder& pBuilder, bool& pFinished) { return false; } /// getRelEntrySize - the size in BYTE of rel type relocation virtual size_t getRelEntrySize() = 0; /// getRelEntrySize - the size in BYTE of rela type relocation virtual size_t getRelaEntrySize() = 0; protected: // Based on Kind in LDFileFormat to define basic section orders for ELF, and // refer gold linker to add more enumerations to handle Regular and BSS kind enum SectionOrder { SHO_INTERP = 1, // .interp SHO_RO_NOTE, // .note.ABI-tag, .note.gnu.build-id SHO_NAMEPOOL, // *.hash, .dynsym, .dynstr SHO_RELOCATION, // .rel.*, .rela.* SHO_REL_PLT, // .rel.plt should come after other .rel.* SHO_INIT, // .init SHO_PLT, // .plt SHO_TEXT, // .text SHO_FINI, // .fini SHO_RO, // .rodata SHO_EXCEPTION, // .eh_frame_hdr, .eh_frame, .gcc_except_table SHO_TLS_DATA, // .tdata SHO_TLS_BSS, // .tbss SHO_RELRO_LOCAL, // .data.rel.ro.local SHO_RELRO, // .data.rel.ro, SHO_RELRO_LAST, // for x86 to adjust .got if needed SHO_NON_RELRO_FIRST, // for x86 to adjust .got.plt if needed SHO_DATA, // .data SHO_LARGE_DATA, // .ldata SHO_RW_NOTE, // SHO_SMALL_DATA, // .sdata SHO_SMALL_BSS, // .sbss SHO_BSS, // .bss SHO_LARGE_BSS, // .lbss SHO_UNDEFINED, // default order SHO_STRTAB // .strtab }; typedef std::pair<LDSection*, unsigned int> SHOEntry; struct SHOCompare { bool operator()(const SHOEntry& X, const SHOEntry& Y) const { return X.second < Y.second; } }; struct SymCompare { bool operator()(const LDSymbol* X, const LDSymbol* Y) const { 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 { return (unsigned((uintptr_t)pKey) >> 4) ^ (unsigned((uintptr_t)pKey) >> 9); } }; typedef HashEntry<LDSymbol*, size_t, SymCompare> SymHashEntryType; typedef HashTable<SymHashEntryType, SymPtrHash, EntryFactory<SymHashEntryType> > HashTableType; protected: ELFObjectReader* m_pObjectReader; // ----- file formats ----- // ELFDynObjFileFormat* m_pDynObjFileFormat; ELFExecFileFormat* m_pExecFileFormat; ELFObjectFileFormat* m_pObjectFileFormat; // GNUInfo GNUInfo* m_pInfo; // ELF segment factory ELFSegmentFactory m_ELFSegmentTable; // branch island factory BranchIslandFactory* m_pBRIslandFactory; // stub factory StubFactory* m_pStubFactory; // map the LDSymbol to its index in the output symbol table HashTableType* m_pSymIndexMap; // section .eh_frame_hdr EhFrameHdr* m_pEhFrameHdr; // ----- dynamic flags ----- // // DF_TEXTREL of DT_FLAGS bool m_bHasTextRel; // DF_STATIC_TLS of DT_FLAGS bool m_bHasStaticTLS; // ----- standard symbols ----- // // section symbols LDSymbol* f_pPreInitArrayStart; LDSymbol* f_pPreInitArrayEnd; LDSymbol* f_pInitArrayStart; LDSymbol* f_pInitArrayEnd; LDSymbol* f_pFiniArrayStart; LDSymbol* f_pFiniArrayEnd; LDSymbol* f_pStack; LDSymbol* f_pDynamic; // section symbols for .tdata and .tbss LDSymbol* f_pTDATA; LDSymbol* f_pTBSS; // segment symbols LDSymbol* f_pExecutableStart; LDSymbol* f_pEText; LDSymbol* f_p_EText; LDSymbol* f_p__EText; LDSymbol* f_pEData; LDSymbol* f_p_EData; LDSymbol* f_pBSSStart; LDSymbol* f_pEnd; LDSymbol* f_p_End; }; } // namespace of mcld #endif