| //===-- llvm/MC/MCMachObjectWriter.h - Mach Object Writer -------*- C++ -*-===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef LLVM_MC_MCMACHOBJECTWRITER_H |
| #define LLVM_MC_MCMACHOBJECTWRITER_H |
| |
| #include "llvm/ADT/DenseMap.h" |
| #include "llvm/ADT/OwningPtr.h" |
| #include "llvm/ADT/SmallString.h" |
| #include "llvm/MC/MCExpr.h" |
| #include "llvm/MC/MCObjectWriter.h" |
| #include "llvm/Object/MachOFormat.h" |
| #include "llvm/Support/DataTypes.h" |
| #include <vector> |
| |
| namespace llvm { |
| |
| class MCSectionData; |
| class MachObjectWriter; |
| |
| class MCMachObjectTargetWriter { |
| const unsigned Is64Bit : 1; |
| const uint32_t CPUType; |
| const uint32_t CPUSubtype; |
| // FIXME: Remove this, we should just always use it once we no longer care |
| // about Darwin 'as' compatibility. |
| const unsigned UseAggressiveSymbolFolding : 1; |
| unsigned LocalDifference_RIT; |
| |
| protected: |
| MCMachObjectTargetWriter(bool Is64Bit_, uint32_t CPUType_, |
| uint32_t CPUSubtype_, |
| bool UseAggressiveSymbolFolding_ = false); |
| |
| void setLocalDifferenceRelocationType(unsigned Type) { |
| LocalDifference_RIT = Type; |
| } |
| |
| public: |
| virtual ~MCMachObjectTargetWriter(); |
| |
| /// @name Accessors |
| /// @{ |
| |
| bool is64Bit() const { return Is64Bit; } |
| bool useAggressiveSymbolFolding() const { return UseAggressiveSymbolFolding; } |
| uint32_t getCPUType() const { return CPUType; } |
| uint32_t getCPUSubtype() const { return CPUSubtype; } |
| unsigned getLocalDifferenceRelocationType() const { |
| return LocalDifference_RIT; |
| } |
| |
| /// @} |
| |
| /// @name API |
| /// @{ |
| |
| virtual void RecordRelocation(MachObjectWriter *Writer, |
| const MCAssembler &Asm, |
| const MCAsmLayout &Layout, |
| const MCFragment *Fragment, |
| const MCFixup &Fixup, |
| MCValue Target, |
| uint64_t &FixedValue) = 0; |
| |
| /// @} |
| }; |
| |
| class MachObjectWriter : public MCObjectWriter { |
| /// MachSymbolData - Helper struct for containing some precomputed information |
| /// on symbols. |
| struct MachSymbolData { |
| MCSymbolData *SymbolData; |
| uint64_t StringIndex; |
| uint8_t SectionIndex; |
| |
| // Support lexicographic sorting. |
| bool operator<(const MachSymbolData &RHS) const; |
| }; |
| |
| /// The target specific Mach-O writer instance. |
| llvm::OwningPtr<MCMachObjectTargetWriter> TargetObjectWriter; |
| |
| /// @name Relocation Data |
| /// @{ |
| |
| llvm::DenseMap<const MCSectionData*, |
| std::vector<object::macho::RelocationEntry> > Relocations; |
| llvm::DenseMap<const MCSectionData*, unsigned> IndirectSymBase; |
| |
| /// @} |
| /// @name Symbol Table Data |
| /// @{ |
| |
| SmallString<256> StringTable; |
| std::vector<MachSymbolData> LocalSymbolData; |
| std::vector<MachSymbolData> ExternalSymbolData; |
| std::vector<MachSymbolData> UndefinedSymbolData; |
| |
| /// @} |
| |
| public: |
| MachObjectWriter(MCMachObjectTargetWriter *MOTW, raw_ostream &_OS, |
| bool _IsLittleEndian) |
| : MCObjectWriter(_OS, _IsLittleEndian), TargetObjectWriter(MOTW) { |
| } |
| |
| /// @name Utility Methods |
| /// @{ |
| |
| bool isFixupKindPCRel(const MCAssembler &Asm, unsigned Kind); |
| |
| SectionAddrMap SectionAddress; |
| |
| SectionAddrMap &getSectionAddressMap() { return SectionAddress; } |
| |
| uint64_t getSectionAddress(const MCSectionData* SD) const { |
| return SectionAddress.lookup(SD); |
| } |
| uint64_t getSymbolAddress(const MCSymbolData* SD, |
| const MCAsmLayout &Layout) const; |
| |
| uint64_t getFragmentAddress(const MCFragment *Fragment, |
| const MCAsmLayout &Layout) const; |
| |
| uint64_t getPaddingSize(const MCSectionData *SD, |
| const MCAsmLayout &Layout) const; |
| |
| bool doesSymbolRequireExternRelocation(const MCSymbolData *SD); |
| |
| /// @} |
| |
| /// @name Target Writer Proxy Accessors |
| /// @{ |
| |
| bool is64Bit() const { return TargetObjectWriter->is64Bit(); } |
| bool isARM() const { |
| uint32_t CPUType = TargetObjectWriter->getCPUType() & |
| ~object::mach::CTFM_ArchMask; |
| return CPUType == object::mach::CTM_ARM; |
| } |
| |
| /// @} |
| |
| void WriteHeader(unsigned NumLoadCommands, unsigned LoadCommandsSize, |
| bool SubsectionsViaSymbols); |
| |
| /// WriteSegmentLoadCommand - Write a segment load command. |
| /// |
| /// \arg NumSections - The number of sections in this segment. |
| /// \arg SectionDataSize - The total size of the sections. |
| void WriteSegmentLoadCommand(unsigned NumSections, |
| uint64_t VMSize, |
| uint64_t SectionDataStartOffset, |
| uint64_t SectionDataSize); |
| |
| void WriteSection(const MCAssembler &Asm, const MCAsmLayout &Layout, |
| const MCSectionData &SD, uint64_t FileOffset, |
| uint64_t RelocationsStart, unsigned NumRelocations); |
| |
| void WriteSymtabLoadCommand(uint32_t SymbolOffset, uint32_t NumSymbols, |
| uint32_t StringTableOffset, |
| uint32_t StringTableSize); |
| |
| void WriteDysymtabLoadCommand(uint32_t FirstLocalSymbol, |
| uint32_t NumLocalSymbols, |
| uint32_t FirstExternalSymbol, |
| uint32_t NumExternalSymbols, |
| uint32_t FirstUndefinedSymbol, |
| uint32_t NumUndefinedSymbols, |
| uint32_t IndirectSymbolOffset, |
| uint32_t NumIndirectSymbols); |
| |
| void WriteNlist(MachSymbolData &MSD, const MCAsmLayout &Layout); |
| |
| // FIXME: We really need to improve the relocation validation. Basically, we |
| // want to implement a separate computation which evaluates the relocation |
| // entry as the linker would, and verifies that the resultant fixup value is |
| // exactly what the encoder wanted. This will catch several classes of |
| // problems: |
| // |
| // - Relocation entry bugs, the two algorithms are unlikely to have the same |
| // exact bug. |
| // |
| // - Relaxation issues, where we forget to relax something. |
| // |
| // - Input errors, where something cannot be correctly encoded. 'as' allows |
| // these through in many cases. |
| |
| void addRelocation(const MCSectionData *SD, |
| object::macho::RelocationEntry &MRE) { |
| Relocations[SD].push_back(MRE); |
| } |
| |
| void RecordScatteredRelocation(const MCAssembler &Asm, |
| const MCAsmLayout &Layout, |
| const MCFragment *Fragment, |
| const MCFixup &Fixup, MCValue Target, |
| unsigned Log2Size, |
| uint64_t &FixedValue); |
| |
| void RecordTLVPRelocation(const MCAssembler &Asm, |
| const MCAsmLayout &Layout, |
| const MCFragment *Fragment, |
| const MCFixup &Fixup, MCValue Target, |
| uint64_t &FixedValue); |
| |
| void RecordRelocation(const MCAssembler &Asm, const MCAsmLayout &Layout, |
| const MCFragment *Fragment, const MCFixup &Fixup, |
| MCValue Target, uint64_t &FixedValue); |
| |
| void BindIndirectSymbols(MCAssembler &Asm); |
| |
| /// 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. |
| void ComputeSymbolTable(MCAssembler &Asm, SmallString<256> &StringTable, |
| std::vector<MachSymbolData> &LocalSymbolData, |
| std::vector<MachSymbolData> &ExternalSymbolData, |
| std::vector<MachSymbolData> &UndefinedSymbolData); |
| |
| void computeSectionAddresses(const MCAssembler &Asm, |
| const MCAsmLayout &Layout); |
| |
| void ExecutePostLayoutBinding(MCAssembler &Asm, const MCAsmLayout &Layout); |
| |
| virtual bool IsSymbolRefDifferenceFullyResolvedImpl(const MCAssembler &Asm, |
| const MCSymbolData &DataA, |
| const MCFragment &FB, |
| bool InSet, |
| bool IsPCRel) const; |
| |
| void WriteObject(MCAssembler &Asm, const MCAsmLayout &Layout); |
| }; |
| |
| |
| /// \brief Construct a new Mach-O writer instance. |
| /// |
| /// This routine takes ownership of the target writer subclass. |
| /// |
| /// \param MOTW - The target specific Mach-O writer subclass. |
| /// \param OS - The stream to write to. |
| /// \returns The constructed object writer. |
| MCObjectWriter *createMachObjectWriter(MCMachObjectTargetWriter *MOTW, |
| raw_ostream &OS, bool IsLittleEndian); |
| |
| } // End llvm namespace |
| |
| #endif |