| //===- 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_GNULDBACKEND_H_ |
| #define MCLD_TARGET_GNULDBACKEND_H_ |
| |
| #include "mcld/Module.h" |
| #include "mcld/LD/ELFBinaryReader.h" |
| #include "mcld/LD/ELFDynObjReader.h" |
| #include "mcld/LD/ELFObjectReader.h" |
| #include "mcld/LD/ELFObjectWriter.h" |
| #include "mcld/LD/GNUArchiveReader.h" |
| #include "mcld/Target/TargetLDBackend.h" |
| |
| #include <llvm/Support/ELF.h> |
| |
| #include <cstdint> |
| |
| namespace mcld { |
| |
| class BranchIslandFactory; |
| class EhFrameHdr; |
| class ELFAttribute; |
| class ELFDynamic; |
| class ELFDynObjFileFormat; |
| class ELFExecFileFormat; |
| class ELFFileFormat; |
| class ELFObjectFileFormat; |
| class ELFSegmentFactory; |
| class GNUInfo; |
| class IRBuilder; |
| class Layout; |
| class LinkerConfig; |
| class LinkerScript; |
| class Module; |
| class Relocation; |
| class StubFactory; |
| |
| /** \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 - return the start address of the segment |
| uint64_t getSegmentStartAddr(const LinkerScript& pScript) const; |
| |
| /// sizeShstrtab - compute the size of .shstrtab |
| void sizeShstrtab(Module& pModule); |
| |
| /// 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, |
| FileOutputBuffer& pOutput); |
| |
| /// emitNamePools - emit dynamic name pools - .dyntab, .dynstr, .hash |
| virtual void emitDynNamePools(Module& pModule, FileOutputBuffer& pOutput); |
| |
| /// emitELFHashTab - emit .hash |
| virtual void emitELFHashTab(const Module::SymbolTable& pSymtab, |
| FileOutputBuffer& pOutput); |
| |
| /// emitGNUHashTab - emit .gnu.hash |
| virtual void emitGNUHashTab(Module::SymbolTable& pSymtab, |
| FileOutputBuffer& 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(FileOutputBuffer& 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; |
| } |
| |
| /// elfSegmentTable - return the reference of the elf segment table |
| ELFSegmentFactory& elfSegmentTable(); |
| |
| /// elfSegmentTable - return the reference of the elf segment table |
| const ELFSegmentFactory& elfSegmentTable() const; |
| |
| /// 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); |
| |
| /// mergeFlags - update set of ELF header flags |
| virtual void mergeFlags(Input& pInput, const char* ELF_hdr) {} |
| |
| /// 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); |
| |
| /// readRelocation - read ELF32_Rel entry |
| virtual bool readRelocation(const llvm::ELF::Elf32_Rel& pRel, |
| uint32_t& pType, |
| uint32_t& pSymIdx, |
| uint32_t& pOffset) const; |
| |
| /// readRelocation - read ELF32_Rela entry |
| virtual bool readRelocation(const llvm::ELF::Elf32_Rela& pRel, |
| uint32_t& pType, |
| uint32_t& pSymIdx, |
| uint32_t& pOffset, |
| int32_t& pAddend) const; |
| |
| /// readRelocation - read ELF64_Rel entry |
| virtual bool readRelocation(const llvm::ELF::Elf64_Rel& pRel, |
| uint32_t& pType, |
| uint32_t& pSymIdx, |
| uint64_t& pOffset) const; |
| |
| /// readRel - read ELF64_Rela entry |
| virtual bool readRelocation(const llvm::ELF::Elf64_Rela& pRel, |
| uint32_t& pType, |
| uint32_t& pSymIdx, |
| uint64_t& pOffset, |
| int64_t& pAddend) const; |
| |
| /// emitRelocation - write data to the ELF32_Rel entry |
| virtual void emitRelocation(llvm::ELF::Elf32_Rel& pRel, |
| uint32_t pType, |
| uint32_t pSymIdx, |
| uint32_t pOffset) const; |
| |
| /// emitRelocation - write data to the ELF32_Rela entry |
| virtual void emitRelocation(llvm::ELF::Elf32_Rela& pRel, |
| uint32_t pType, |
| uint32_t pSymIdx, |
| uint32_t pOffset, |
| int32_t pAddend) const; |
| |
| /// emitRelocation - write data to the ELF64_Rel entry |
| virtual void emitRelocation(llvm::ELF::Elf64_Rel& pRel, |
| uint32_t pType, |
| uint32_t pSymIdx, |
| uint64_t pOffset) const; |
| |
| /// emitRelocation - write data to the ELF64_Rela entry |
| virtual void emitRelocation(llvm::ELF::Elf64_Rela& pRel, |
| uint32_t pType, |
| uint32_t pSymIdx, |
| uint64_t pOffset, |
| int64_t pAddend) const; |
| |
| /// symbolNeedsPLT - return whether the symbol needs a PLT entry |
| 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 |
| bool symbolNeedsDynRel(const ResolveInfo& pSym, |
| bool pSymHasPLT, |
| bool isAbsReloc) const; |
| |
| /// isSymbolPreemptible - whether the symbol can be preemted by other link |
| /// units |
| 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 |
| bool isDynamicSymbol(const LDSymbol& pSymbol) const; |
| |
| /// isDynamicSymbol |
| bool isDynamicSymbol(const ResolveInfo& pResolveInfo) const; |
| |
| virtual ResolveInfo::Desc getSymDesc(uint16_t pShndx) const { |
| return ResolveInfo::Define; |
| } |
| |
| bool hasTDATASymbol() const { return (f_pTDATA != NULL); } |
| bool hasTBSSSymbol() const { return (f_pTBSS != NULL); } |
| |
| 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; |
| |
| /// getEntry - get the entry point name |
| llvm::StringRef getEntry(const Module& pModule) 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; } |
| |
| /// maxFwdBranchOffset - return the max forward branch offset of the backend. |
| /// Target can override this function if needed. |
| virtual int64_t maxFwdBranchOffset() const { return INT64_MAX; } |
| |
| /// maxBwdBranchOffset - return the max backward branch offset of the backend. |
| /// Target can override this function if needed. |
| virtual int64_t maxBwdBranchOffset() const { return 0; } |
| |
| /// stubGroupSize - return the group size to place stubs between sections. |
| virtual unsigned stubGroupSize() const; |
| |
| /// checkAndSetHasTextRel - check pSection flag to set HasTextRel |
| void checkAndSetHasTextRel(const LDSection& pSection); |
| |
| /// sortRelocation - sort the dynamic relocations to let dynamic linker |
| /// process relocations more efficiently |
| void sortRelocation(LDSection& pSection); |
| |
| /// createAndSizeEhFrameHdr - This is seperated since we may add eh_frame |
| /// entry in the middle |
| void createAndSizeEhFrameHdr(Module& pModule); |
| |
| /// attribute - the attribute section data. |
| ELFAttribute& attribute() { return *m_pAttribute; } |
| |
| /// attribute - the attribute section data. |
| const ELFAttribute& attribute() const { return *m_pAttribute; } |
| |
| /// mayHaveUnsafeFunctionPointerAccess - check if the section may have unsafe |
| /// function pointer access |
| bool mayHaveUnsafeFunctionPointerAccess(const LDSection& pSection) const; |
| |
| protected: |
| /// 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; |
| |
| 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. |
| static unsigned getHashBucketCount(unsigned pNumOfSymbols, bool pIsGNUStyle); |
| |
| /// getGNUHashMaskbitslog2 - calculate the number of mask bits in log2 |
| 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); |
| |
| protected: |
| /// 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); |
| |
| /// setupGNUStackInfo - setup the section flag of .note.GNU-stack in output |
| void setupGNUStackInfo(Module& pModule); |
| |
| /// setOutputSectionOffset - helper function to set output sections' offset. |
| void setOutputSectionOffset(Module& pModule); |
| |
| /// setOutputSectionAddress - helper function to set output sections' address. |
| void setOutputSectionAddress(Module& pModule); |
| |
| /// placeOutputSections - place output sections based on SectionMap |
| void placeOutputSections(Module& pModule); |
| |
| /// 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(FileOutputBuffer& 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 |
| virtual 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; |
| } |
| |
| protected: |
| // Based on Kind in LDFileFormat to define basic section orders for ELF. |
| enum SectionOrder { |
| SHO_NULL = 0, // NULL |
| SHO_INTERP, // .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 |
| }; |
| |
| // for -z combreloc |
| struct RelocCompare { |
| explicit RelocCompare(const GNULDBackend& pBackend) : m_Backend(pBackend) {} |
| bool operator()(const Relocation& X, const Relocation& Y) const; |
| |
| private: |
| const GNULDBackend& m_Backend; |
| }; |
| |
| // for gnu style hash table |
| struct DynsymCompare { |
| bool needGNUHash(const LDSymbol& X) const; |
| |
| bool operator()(const LDSymbol* X, const LDSymbol* Y) const; |
| }; |
| |
| struct SymCompare { |
| bool operator()(const LDSymbol* X, const LDSymbol* Y) const { |
| return (X == Y); |
| } |
| }; |
| |
| 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_pELFSegmentTable; |
| |
| // 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; |
| |
| // attribute section |
| ELFAttribute* m_pAttribute; |
| |
| // ----- 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 mcld |
| |
| #endif // MCLD_TARGET_GNULDBACKEND_H_ |