| //===- lib/MC/ELFObjectWriter.h - ELF File Writer -------------------------===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file implements ELF object file writer information. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef LLVM_MC_ELFOBJECTWRITER_H |
| #define LLVM_MC_ELFOBJECTWRITER_H |
| |
| #include "MCELF.h" |
| #include "llvm/ADT/OwningPtr.h" |
| #include "llvm/ADT/SmallPtrSet.h" |
| #include "llvm/ADT/SmallString.h" |
| #include "llvm/ADT/STLExtras.h" |
| #include "llvm/MC/MCAssembler.h" |
| #include "llvm/MC/MCELFObjectWriter.h" |
| #include "llvm/MC/MCELFSymbolFlags.h" |
| #include "llvm/MC/MCObjectWriter.h" |
| #include "llvm/MC/MCExpr.h" |
| #include "llvm/MC/MCSymbol.h" |
| |
| #include <vector> |
| |
| namespace llvm { |
| |
| class MCSection; |
| class MCDataFragment; |
| class MCSectionELF; |
| |
| class ELFObjectWriter : public MCObjectWriter { |
| protected: |
| |
| static bool isFixupKindPCRel(const MCAssembler &Asm, unsigned Kind); |
| static bool RelocNeedsGOT(MCSymbolRefExpr::VariantKind Variant); |
| static uint64_t SymbolValue(MCSymbolData &Data, const MCAsmLayout &Layout); |
| static bool isInSymtab(const MCAssembler &Asm, const MCSymbolData &Data, |
| bool Used, bool Renamed); |
| static bool isLocal(const MCSymbolData &Data, bool isSignature, |
| bool isUsedInReloc); |
| static bool IsELFMetaDataSection(const MCSectionData &SD); |
| static uint64_t DataSectionSize(const MCSectionData &SD); |
| static uint64_t GetSectionFileSize(const MCAsmLayout &Layout, |
| const MCSectionData &SD); |
| static uint64_t GetSectionAddressSize(const MCAsmLayout &Layout, |
| const MCSectionData &SD); |
| |
| void WriteDataSectionData(MCAssembler &Asm, |
| const MCAsmLayout &Layout, |
| const MCSectionELF &Section); |
| |
| /*static bool isFixupKindX86RIPRel(unsigned Kind) { |
| return Kind == X86::reloc_riprel_4byte || |
| Kind == X86::reloc_riprel_4byte_movq_load; |
| }*/ |
| |
| /// ELFSymbolData - Helper struct for containing some precomputed |
| /// information on symbols. |
| struct ELFSymbolData { |
| MCSymbolData *SymbolData; |
| uint64_t StringIndex; |
| uint32_t SectionIndex; |
| |
| // Support lexicographic sorting. |
| bool operator<(const ELFSymbolData &RHS) const { |
| if (MCELF::GetType(*SymbolData) == ELF::STT_FILE) |
| return true; |
| if (MCELF::GetType(*RHS.SymbolData) == ELF::STT_FILE) |
| return false; |
| return SymbolData->getSymbol().getName() < |
| RHS.SymbolData->getSymbol().getName(); |
| } |
| }; |
| |
| /// @name Relocation Data |
| /// @{ |
| |
| struct ELFRelocationEntry { |
| // Make these big enough for both 32-bit and 64-bit |
| uint64_t r_offset; |
| int Index; |
| unsigned Type; |
| const MCSymbol *Symbol; |
| uint64_t r_addend; |
| |
| ELFRelocationEntry() |
| : r_offset(0), Index(0), Type(0), Symbol(0), r_addend(0) {} |
| |
| ELFRelocationEntry(uint64_t RelocOffset, int Idx, |
| unsigned RelType, const MCSymbol *Sym, |
| uint64_t Addend) |
| : r_offset(RelocOffset), Index(Idx), Type(RelType), |
| Symbol(Sym), r_addend(Addend) {} |
| |
| // Support lexicographic sorting. |
| bool operator<(const ELFRelocationEntry &RE) const { |
| return RE.r_offset < r_offset; |
| } |
| }; |
| |
| /// The target specific ELF writer instance. |
| llvm::OwningPtr<MCELFObjectTargetWriter> TargetObjectWriter; |
| |
| SmallPtrSet<const MCSymbol *, 16> UsedInReloc; |
| SmallPtrSet<const MCSymbol *, 16> WeakrefUsedInReloc; |
| DenseMap<const MCSymbol *, const MCSymbol *> Renames; |
| |
| llvm::DenseMap<const MCSectionData*, |
| std::vector<ELFRelocationEntry> > Relocations; |
| DenseMap<const MCSection*, uint64_t> SectionStringTableIndex; |
| |
| /// @} |
| /// @name Symbol Table Data |
| /// @{ |
| |
| SmallString<256> StringTable; |
| std::vector<ELFSymbolData> LocalSymbolData; |
| std::vector<ELFSymbolData> ExternalSymbolData; |
| std::vector<ELFSymbolData> UndefinedSymbolData; |
| |
| /// @} |
| |
| bool NeedsGOT; |
| |
| bool NeedsSymtabShndx; |
| |
| // This holds the symbol table index of the last local symbol. |
| unsigned LastLocalSymbolIndex; |
| // This holds the .strtab section index. |
| unsigned StringTableIndex; |
| // This holds the .symtab section index. |
| unsigned SymbolTableIndex; |
| |
| unsigned ShstrtabIndex; |
| |
| |
| virtual const MCSymbol *SymbolToReloc(const MCAssembler &Asm, |
| const MCValue &Target, |
| const MCFragment &F, |
| const MCFixup &Fixup, |
| bool IsPCRel) const; |
| |
| // For arch-specific emission of explicit reloc symbol |
| virtual const MCSymbol *ExplicitRelSym(const MCAssembler &Asm, |
| const MCValue &Target, |
| const MCFragment &F, |
| const MCFixup &Fixup, |
| bool IsPCRel) const { |
| return NULL; |
| } |
| |
| bool is64Bit() const { return TargetObjectWriter->is64Bit(); } |
| bool hasRelocationAddend() const { |
| return TargetObjectWriter->hasRelocationAddend(); |
| } |
| |
| public: |
| ELFObjectWriter(MCELFObjectTargetWriter *MOTW, |
| raw_ostream &_OS, bool IsLittleEndian) |
| : MCObjectWriter(_OS, IsLittleEndian), |
| TargetObjectWriter(MOTW), |
| NeedsGOT(false), NeedsSymtabShndx(false){ |
| } |
| |
| virtual ~ELFObjectWriter(); |
| |
| void WriteWord(uint64_t W) { |
| if (is64Bit()) |
| Write64(W); |
| else |
| Write32(W); |
| } |
| |
| void StringLE16(char *buf, uint16_t Value) { |
| buf[0] = char(Value >> 0); |
| buf[1] = char(Value >> 8); |
| } |
| |
| void StringLE32(char *buf, uint32_t Value) { |
| StringLE16(buf, uint16_t(Value >> 0)); |
| StringLE16(buf + 2, uint16_t(Value >> 16)); |
| } |
| |
| void StringLE64(char *buf, uint64_t Value) { |
| StringLE32(buf, uint32_t(Value >> 0)); |
| StringLE32(buf + 4, uint32_t(Value >> 32)); |
| } |
| |
| void StringBE16(char *buf ,uint16_t Value) { |
| buf[0] = char(Value >> 8); |
| buf[1] = char(Value >> 0); |
| } |
| |
| void StringBE32(char *buf, uint32_t Value) { |
| StringBE16(buf, uint16_t(Value >> 16)); |
| StringBE16(buf + 2, uint16_t(Value >> 0)); |
| } |
| |
| void StringBE64(char *buf, uint64_t Value) { |
| StringBE32(buf, uint32_t(Value >> 32)); |
| StringBE32(buf + 4, uint32_t(Value >> 0)); |
| } |
| |
| void String8(MCDataFragment &F, uint8_t Value) { |
| char buf[1]; |
| buf[0] = Value; |
| F.getContents() += StringRef(buf, 1); |
| } |
| |
| void String16(MCDataFragment &F, uint16_t Value) { |
| char buf[2]; |
| if (isLittleEndian()) |
| StringLE16(buf, Value); |
| else |
| StringBE16(buf, Value); |
| F.getContents() += StringRef(buf, 2); |
| } |
| |
| void String32(MCDataFragment &F, uint32_t Value) { |
| char buf[4]; |
| if (isLittleEndian()) |
| StringLE32(buf, Value); |
| else |
| StringBE32(buf, Value); |
| F.getContents() += StringRef(buf, 4); |
| } |
| |
| void String64(MCDataFragment &F, uint64_t Value) { |
| char buf[8]; |
| if (isLittleEndian()) |
| StringLE64(buf, Value); |
| else |
| StringBE64(buf, Value); |
| F.getContents() += StringRef(buf, 8); |
| } |
| |
| virtual void WriteHeader(uint64_t SectionDataSize, unsigned NumberOfSections); |
| |
| /// Default e_flags = 0 |
| virtual void WriteEFlags() { Write32(0); } |
| |
| virtual void WriteSymbolEntry(MCDataFragment *SymtabF, MCDataFragment *ShndxF, |
| uint64_t name, uint8_t info, |
| uint64_t value, uint64_t size, |
| uint8_t other, uint32_t shndx, |
| bool Reserved); |
| |
| virtual void WriteSymbol(MCDataFragment *SymtabF, MCDataFragment *ShndxF, |
| ELFSymbolData &MSD, |
| const MCAsmLayout &Layout); |
| |
| typedef DenseMap<const MCSectionELF*, uint32_t> SectionIndexMapTy; |
| virtual void WriteSymbolTable(MCDataFragment *SymtabF, MCDataFragment *ShndxF, |
| const MCAssembler &Asm, |
| const MCAsmLayout &Layout, |
| const SectionIndexMapTy &SectionIndexMap); |
| |
| virtual void RecordRelocation(const MCAssembler &Asm, const MCAsmLayout &Layout, |
| const MCFragment *Fragment, const MCFixup &Fixup, |
| MCValue Target, uint64_t &FixedValue); |
| |
| virtual uint64_t getSymbolIndexInSymbolTable(const MCAssembler &Asm, |
| const MCSymbol *S); |
| |
| // Map from a group section to the signature symbol |
| typedef DenseMap<const MCSectionELF*, const MCSymbol*> GroupMapTy; |
| // Map from a signature symbol to the group section |
| typedef DenseMap<const MCSymbol*, const MCSectionELF*> RevGroupMapTy; |
| // Map from a section to the section with the relocations |
| typedef DenseMap<const MCSectionELF*, const MCSectionELF*> RelMapTy; |
| // Map from a section to its offset |
| typedef DenseMap<const MCSectionELF*, uint64_t> SectionOffsetMapTy; |
| |
| /// ComputeSymbolTable - Compute the symbol table data |
| /// |
| /// \param StringTable [out] - The string table data. |
| /// \param StringIndexMap [out] - Map from symbol names to offsets in the |
| /// string table. |
| virtual void ComputeSymbolTable(MCAssembler &Asm, |
| const SectionIndexMapTy &SectionIndexMap, |
| RevGroupMapTy RevGroupMap, |
| unsigned NumRegularSections); |
| |
| virtual void ComputeIndexMap(MCAssembler &Asm, |
| SectionIndexMapTy &SectionIndexMap, |
| const RelMapTy &RelMap); |
| |
| void CreateRelocationSections(MCAssembler &Asm, MCAsmLayout &Layout, |
| RelMapTy &RelMap); |
| |
| void WriteRelocations(MCAssembler &Asm, MCAsmLayout &Layout, |
| const RelMapTy &RelMap); |
| |
| virtual void CreateMetadataSections(MCAssembler &Asm, MCAsmLayout &Layout, |
| SectionIndexMapTy &SectionIndexMap, |
| const RelMapTy &RelMap); |
| |
| // Create the sections that show up in the symbol table. Currently |
| // those are the .note.GNU-stack section and the group sections. |
| virtual void CreateIndexedSections(MCAssembler &Asm, MCAsmLayout &Layout, |
| GroupMapTy &GroupMap, |
| RevGroupMapTy &RevGroupMap, |
| SectionIndexMapTy &SectionIndexMap, |
| const RelMapTy &RelMap); |
| |
| virtual void ExecutePostLayoutBinding(MCAssembler &Asm, |
| const MCAsmLayout &Layout); |
| |
| void WriteSectionHeader(MCAssembler &Asm, const GroupMapTy &GroupMap, |
| const MCAsmLayout &Layout, |
| const SectionIndexMapTy &SectionIndexMap, |
| const SectionOffsetMapTy &SectionOffsetMap); |
| |
| void ComputeSectionOrder(MCAssembler &Asm, |
| std::vector<const MCSectionELF*> &Sections); |
| |
| virtual void WriteSecHdrEntry(uint32_t Name, uint32_t Type, uint64_t Flags, |
| uint64_t Address, uint64_t Offset, |
| uint64_t Size, uint32_t Link, uint32_t Info, |
| uint64_t Alignment, uint64_t EntrySize); |
| |
| virtual void WriteRelocationsFragment(const MCAssembler &Asm, |
| MCDataFragment *F, |
| const MCSectionData *SD); |
| |
| virtual bool |
| IsSymbolRefDifferenceFullyResolvedImpl(const MCAssembler &Asm, |
| const MCSymbolData &DataA, |
| const MCFragment &FB, |
| bool InSet, |
| bool IsPCRel) const; |
| |
| virtual void WriteObject(MCAssembler &Asm, const MCAsmLayout &Layout); |
| virtual void WriteSection(MCAssembler &Asm, |
| const SectionIndexMapTy &SectionIndexMap, |
| uint32_t GroupSymbolIndex, |
| uint64_t Offset, uint64_t Size, uint64_t Alignment, |
| const MCSectionELF &Section); |
| |
| protected: |
| virtual unsigned GetRelocType(const MCValue &Target, const MCFixup &Fixup, |
| bool IsPCRel, bool IsRelocWithSymbol, |
| int64_t Addend) = 0; |
| virtual void adjustFixupOffset(const MCFixup &Fixup, uint64_t &RelocOffset) { } |
| }; |
| |
| //===- X86ELFObjectWriter -------------------------------------------===// |
| |
| class X86ELFObjectWriter : public ELFObjectWriter { |
| public: |
| X86ELFObjectWriter(MCELFObjectTargetWriter *MOTW, |
| raw_ostream &_OS, |
| bool IsLittleEndian); |
| |
| virtual ~X86ELFObjectWriter(); |
| protected: |
| virtual unsigned GetRelocType(const MCValue &Target, const MCFixup &Fixup, |
| bool IsPCRel, bool IsRelocWithSymbol, |
| int64_t Addend); |
| }; |
| |
| |
| //===- ARMELFObjectWriter -------------------------------------------===// |
| |
| class ARMELFObjectWriter : public ELFObjectWriter { |
| public: |
| // FIXME: MCAssembler can't yet return the Subtarget, |
| enum { DefaultEABIVersion = 0x05000000U }; |
| |
| ARMELFObjectWriter(MCELFObjectTargetWriter *MOTW, |
| raw_ostream &_OS, |
| bool IsLittleEndian); |
| |
| virtual ~ARMELFObjectWriter(); |
| |
| virtual void WriteEFlags(); |
| protected: |
| virtual const MCSymbol *ExplicitRelSym(const MCAssembler &Asm, |
| const MCValue &Target, |
| const MCFragment &F, |
| const MCFixup &Fixup, |
| bool IsPCRel) const; |
| |
| virtual unsigned GetRelocType(const MCValue &Target, const MCFixup &Fixup, |
| bool IsPCRel, bool IsRelocWithSymbol, |
| int64_t Addend); |
| private: |
| unsigned GetRelocTypeInner(const MCValue &Target, |
| const MCFixup &Fixup, bool IsPCRel) const; |
| |
| }; |
| |
| //===- PPCELFObjectWriter -------------------------------------------===// |
| |
| class PPCELFObjectWriter : public ELFObjectWriter { |
| public: |
| PPCELFObjectWriter(MCELFObjectTargetWriter *MOTW, |
| raw_ostream &_OS, |
| bool IsLittleEndian); |
| |
| virtual ~PPCELFObjectWriter(); |
| protected: |
| virtual unsigned GetRelocType(const MCValue &Target, const MCFixup &Fixup, |
| bool IsPCRel, bool IsRelocWithSymbol, |
| int64_t Addend); |
| virtual void adjustFixupOffset(const MCFixup &Fixup, uint64_t &RelocOffset); |
| }; |
| |
| //===- MBlazeELFObjectWriter -------------------------------------------===// |
| |
| class MBlazeELFObjectWriter : public ELFObjectWriter { |
| public: |
| MBlazeELFObjectWriter(MCELFObjectTargetWriter *MOTW, |
| raw_ostream &_OS, |
| bool IsLittleEndian); |
| |
| virtual ~MBlazeELFObjectWriter(); |
| protected: |
| virtual unsigned GetRelocType(const MCValue &Target, const MCFixup &Fixup, |
| bool IsPCRel, bool IsRelocWithSymbol, |
| int64_t Addend); |
| }; |
| |
| //===- MipsELFObjectWriter -------------------------------------------===// |
| |
| class MipsELFObjectWriter : public ELFObjectWriter { |
| public: |
| MipsELFObjectWriter(MCELFObjectTargetWriter *MOTW, |
| raw_ostream &_OS, |
| bool IsLittleEndian); |
| |
| virtual ~MipsELFObjectWriter(); |
| protected: |
| virtual unsigned GetRelocType(const MCValue &Target, const MCFixup &Fixup, |
| bool IsPCRel, bool IsRelocWithSymbol, |
| int64_t Addend); |
| }; |
| } |
| |
| #endif |