Home | History | Annotate | Download | only in MC
      1 //===-- llvm/MC/MCMachObjectWriter.h - Mach Object Writer -------*- C++ -*-===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 
     10 #ifndef LLVM_MC_MCMACHOBJECTWRITER_H
     11 #define LLVM_MC_MCMACHOBJECTWRITER_H
     12 
     13 #include "llvm/ADT/DenseMap.h"
     14 #include "llvm/ADT/OwningPtr.h"
     15 #include "llvm/ADT/SmallString.h"
     16 #include "llvm/MC/MCExpr.h"
     17 #include "llvm/MC/MCObjectWriter.h"
     18 #include "llvm/Object/MachOFormat.h"
     19 #include "llvm/Support/DataTypes.h"
     20 #include <vector>
     21 
     22 namespace llvm {
     23 
     24 class MCSectionData;
     25 class MachObjectWriter;
     26 
     27 class MCMachObjectTargetWriter {
     28   const unsigned Is64Bit : 1;
     29   const uint32_t CPUType;
     30   const uint32_t CPUSubtype;
     31   // FIXME: Remove this, we should just always use it once we no longer care
     32   // about Darwin 'as' compatibility.
     33   const unsigned UseAggressiveSymbolFolding : 1;
     34   unsigned LocalDifference_RIT;
     35 
     36 protected:
     37   MCMachObjectTargetWriter(bool Is64Bit_, uint32_t CPUType_,
     38                            uint32_t CPUSubtype_,
     39                            bool UseAggressiveSymbolFolding_ = false);
     40 
     41   void setLocalDifferenceRelocationType(unsigned Type) {
     42     LocalDifference_RIT = Type;
     43   }
     44 
     45 public:
     46   virtual ~MCMachObjectTargetWriter();
     47 
     48   /// @name Accessors
     49   /// @{
     50 
     51   bool is64Bit() const { return Is64Bit; }
     52   bool useAggressiveSymbolFolding() const { return UseAggressiveSymbolFolding; }
     53   uint32_t getCPUType() const { return CPUType; }
     54   uint32_t getCPUSubtype() const { return CPUSubtype; }
     55   unsigned getLocalDifferenceRelocationType() const {
     56     return LocalDifference_RIT;
     57   }
     58 
     59   /// @}
     60 
     61   /// @name API
     62   /// @{
     63 
     64   virtual void RecordRelocation(MachObjectWriter *Writer,
     65                                 const MCAssembler &Asm,
     66                                 const MCAsmLayout &Layout,
     67                                 const MCFragment *Fragment,
     68                                 const MCFixup &Fixup,
     69                                 MCValue Target,
     70                                 uint64_t &FixedValue) = 0;
     71 
     72   /// @}
     73 };
     74 
     75 class MachObjectWriter : public MCObjectWriter {
     76   /// MachSymbolData - Helper struct for containing some precomputed information
     77   /// on symbols.
     78   struct MachSymbolData {
     79     MCSymbolData *SymbolData;
     80     uint64_t StringIndex;
     81     uint8_t SectionIndex;
     82 
     83     // Support lexicographic sorting.
     84     bool operator<(const MachSymbolData &RHS) const;
     85   };
     86 
     87   /// The target specific Mach-O writer instance.
     88   llvm::OwningPtr<MCMachObjectTargetWriter> TargetObjectWriter;
     89 
     90   /// @name Relocation Data
     91   /// @{
     92 
     93   llvm::DenseMap<const MCSectionData*,
     94                  std::vector<object::macho::RelocationEntry> > Relocations;
     95   llvm::DenseMap<const MCSectionData*, unsigned> IndirectSymBase;
     96 
     97   /// @}
     98   /// @name Symbol Table Data
     99   /// @{
    100 
    101   SmallString<256> StringTable;
    102   std::vector<MachSymbolData> LocalSymbolData;
    103   std::vector<MachSymbolData> ExternalSymbolData;
    104   std::vector<MachSymbolData> UndefinedSymbolData;
    105 
    106   /// @}
    107 
    108 public:
    109   MachObjectWriter(MCMachObjectTargetWriter *MOTW, raw_ostream &_OS,
    110                    bool _IsLittleEndian)
    111     : MCObjectWriter(_OS, _IsLittleEndian), TargetObjectWriter(MOTW) {
    112   }
    113 
    114   /// @name Utility Methods
    115   /// @{
    116 
    117   bool isFixupKindPCRel(const MCAssembler &Asm, unsigned Kind);
    118 
    119   SectionAddrMap SectionAddress;
    120 
    121   SectionAddrMap &getSectionAddressMap() { return SectionAddress; }
    122 
    123   uint64_t getSectionAddress(const MCSectionData* SD) const {
    124     return SectionAddress.lookup(SD);
    125   }
    126   uint64_t getSymbolAddress(const MCSymbolData* SD,
    127                             const MCAsmLayout &Layout) const;
    128 
    129   uint64_t getFragmentAddress(const MCFragment *Fragment,
    130                               const MCAsmLayout &Layout) const;
    131 
    132   uint64_t getPaddingSize(const MCSectionData *SD,
    133                           const MCAsmLayout &Layout) const;
    134 
    135   bool doesSymbolRequireExternRelocation(const MCSymbolData *SD);
    136 
    137   /// @}
    138 
    139   /// @name Target Writer Proxy Accessors
    140   /// @{
    141 
    142   bool is64Bit() const { return TargetObjectWriter->is64Bit(); }
    143   bool isARM() const {
    144     uint32_t CPUType = TargetObjectWriter->getCPUType() &
    145       ~object::mach::CTFM_ArchMask;
    146     return CPUType == object::mach::CTM_ARM;
    147   }
    148 
    149   /// @}
    150 
    151   void WriteHeader(unsigned NumLoadCommands, unsigned LoadCommandsSize,
    152                    bool SubsectionsViaSymbols);
    153 
    154   /// WriteSegmentLoadCommand - Write a segment load command.
    155   ///
    156   /// \arg NumSections - The number of sections in this segment.
    157   /// \arg SectionDataSize - The total size of the sections.
    158   void WriteSegmentLoadCommand(unsigned NumSections,
    159                                uint64_t VMSize,
    160                                uint64_t SectionDataStartOffset,
    161                                uint64_t SectionDataSize);
    162 
    163   void WriteSection(const MCAssembler &Asm, const MCAsmLayout &Layout,
    164                     const MCSectionData &SD, uint64_t FileOffset,
    165                     uint64_t RelocationsStart, unsigned NumRelocations);
    166 
    167   void WriteSymtabLoadCommand(uint32_t SymbolOffset, uint32_t NumSymbols,
    168                               uint32_t StringTableOffset,
    169                               uint32_t StringTableSize);
    170 
    171   void WriteDysymtabLoadCommand(uint32_t FirstLocalSymbol,
    172                                 uint32_t NumLocalSymbols,
    173                                 uint32_t FirstExternalSymbol,
    174                                 uint32_t NumExternalSymbols,
    175                                 uint32_t FirstUndefinedSymbol,
    176                                 uint32_t NumUndefinedSymbols,
    177                                 uint32_t IndirectSymbolOffset,
    178                                 uint32_t NumIndirectSymbols);
    179 
    180   void WriteNlist(MachSymbolData &MSD, const MCAsmLayout &Layout);
    181 
    182   // FIXME: We really need to improve the relocation validation. Basically, we
    183   // want to implement a separate computation which evaluates the relocation
    184   // entry as the linker would, and verifies that the resultant fixup value is
    185   // exactly what the encoder wanted. This will catch several classes of
    186   // problems:
    187   //
    188   //  - Relocation entry bugs, the two algorithms are unlikely to have the same
    189   //    exact bug.
    190   //
    191   //  - Relaxation issues, where we forget to relax something.
    192   //
    193   //  - Input errors, where something cannot be correctly encoded. 'as' allows
    194   //    these through in many cases.
    195 
    196   void addRelocation(const MCSectionData *SD,
    197                      object::macho::RelocationEntry &MRE) {
    198     Relocations[SD].push_back(MRE);
    199   }
    200 
    201   void RecordScatteredRelocation(const MCAssembler &Asm,
    202                                  const MCAsmLayout &Layout,
    203                                  const MCFragment *Fragment,
    204                                  const MCFixup &Fixup, MCValue Target,
    205                                  unsigned Log2Size,
    206                                  uint64_t &FixedValue);
    207 
    208   void RecordTLVPRelocation(const MCAssembler &Asm,
    209                             const MCAsmLayout &Layout,
    210                             const MCFragment *Fragment,
    211                             const MCFixup &Fixup, MCValue Target,
    212                             uint64_t &FixedValue);
    213 
    214   void RecordRelocation(const MCAssembler &Asm, const MCAsmLayout &Layout,
    215                         const MCFragment *Fragment, const MCFixup &Fixup,
    216                         MCValue Target, uint64_t &FixedValue);
    217 
    218   void BindIndirectSymbols(MCAssembler &Asm);
    219 
    220   /// ComputeSymbolTable - Compute the symbol table data
    221   ///
    222   /// \param StringTable [out] - The string table data.
    223   /// \param StringIndexMap [out] - Map from symbol names to offsets in the
    224   /// string table.
    225   void ComputeSymbolTable(MCAssembler &Asm, SmallString<256> &StringTable,
    226                           std::vector<MachSymbolData> &LocalSymbolData,
    227                           std::vector<MachSymbolData> &ExternalSymbolData,
    228                           std::vector<MachSymbolData> &UndefinedSymbolData);
    229 
    230   void computeSectionAddresses(const MCAssembler &Asm,
    231                                const MCAsmLayout &Layout);
    232 
    233   void ExecutePostLayoutBinding(MCAssembler &Asm, const MCAsmLayout &Layout);
    234 
    235   virtual bool IsSymbolRefDifferenceFullyResolvedImpl(const MCAssembler &Asm,
    236                                                       const MCSymbolData &DataA,
    237                                                       const MCFragment &FB,
    238                                                       bool InSet,
    239                                                       bool IsPCRel) const;
    240 
    241   void WriteObject(MCAssembler &Asm, const MCAsmLayout &Layout);
    242 };
    243 
    244 
    245 /// \brief Construct a new Mach-O writer instance.
    246 ///
    247 /// This routine takes ownership of the target writer subclass.
    248 ///
    249 /// \param MOTW - The target specific Mach-O writer subclass.
    250 /// \param OS - The stream to write to.
    251 /// \returns The constructed object writer.
    252 MCObjectWriter *createMachObjectWriter(MCMachObjectTargetWriter *MOTW,
    253                                        raw_ostream &OS, bool IsLittleEndian);
    254 
    255 } // End llvm namespace
    256 
    257 #endif
    258