//===- 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 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 TargetObjectWriter; SmallPtrSet UsedInReloc; SmallPtrSet WeakrefUsedInReloc; DenseMap Renames; llvm::DenseMap > Relocations; DenseMap SectionStringTableIndex; /// @} /// @name Symbol Table Data /// @{ SmallString<256> StringTable; std::vector LocalSymbolData; std::vector ExternalSymbolData; std::vector 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 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 GroupMapTy; // Map from a signature symbol to the group section typedef DenseMap RevGroupMapTy; // Map from a section to the section with the relocations typedef DenseMap RelMapTy; // Map from a section to its offset typedef DenseMap 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 &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