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/SmallString.h" 15 #include "llvm/MC/MCExpr.h" 16 #include "llvm/MC/MCObjectWriter.h" 17 #include "llvm/MC/StringTableBuilder.h" 18 #include "llvm/Support/DataTypes.h" 19 #include "llvm/Support/MachO.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 setLocalDifferenceRelocationType(unsigned Type)41 void setLocalDifferenceRelocationType(unsigned Type) { 42 LocalDifference_RIT = Type; 43 } 44 45 public: 46 virtual ~MCMachObjectTargetWriter(); 47 48 /// @name Lifetime Management 49 /// @{ 50 reset()51 virtual void reset() {}; 52 53 /// @} 54 55 /// @name Accessors 56 /// @{ 57 is64Bit()58 bool is64Bit() const { return Is64Bit; } useAggressiveSymbolFolding()59 bool useAggressiveSymbolFolding() const { return UseAggressiveSymbolFolding; } getCPUType()60 uint32_t getCPUType() const { return CPUType; } getCPUSubtype()61 uint32_t getCPUSubtype() const { return CPUSubtype; } getLocalDifferenceRelocationType()62 unsigned getLocalDifferenceRelocationType() const { 63 return LocalDifference_RIT; 64 } 65 66 /// @} 67 68 /// @name API 69 /// @{ 70 71 virtual void RecordRelocation(MachObjectWriter *Writer, MCAssembler &Asm, 72 const MCAsmLayout &Layout, 73 const MCFragment *Fragment, 74 const MCFixup &Fixup, MCValue Target, 75 uint64_t &FixedValue) = 0; 76 77 /// @} 78 }; 79 80 class MachObjectWriter : public MCObjectWriter { 81 /// MachSymbolData - Helper struct for containing some precomputed information 82 /// on symbols. 83 struct MachSymbolData { 84 MCSymbolData *SymbolData; 85 uint64_t StringIndex; 86 uint8_t SectionIndex; 87 88 // Support lexicographic sorting. 89 bool operator<(const MachSymbolData &RHS) const; 90 }; 91 92 /// The target specific Mach-O writer instance. 93 std::unique_ptr<MCMachObjectTargetWriter> TargetObjectWriter; 94 95 /// @name Relocation Data 96 /// @{ 97 98 struct RelAndSymbol { 99 const MCSymbolData *Sym; 100 MachO::any_relocation_info MRE; RelAndSymbolRelAndSymbol101 RelAndSymbol(const MCSymbolData *Sym, const MachO::any_relocation_info &MRE) 102 : Sym(Sym), MRE(MRE) {} 103 }; 104 105 llvm::DenseMap<const MCSectionData *, std::vector<RelAndSymbol>> Relocations; 106 llvm::DenseMap<const MCSectionData*, unsigned> IndirectSymBase; 107 108 /// @} 109 /// @name Symbol Table Data 110 /// @{ 111 112 StringTableBuilder StringTable; 113 std::vector<MachSymbolData> LocalSymbolData; 114 std::vector<MachSymbolData> ExternalSymbolData; 115 std::vector<MachSymbolData> UndefinedSymbolData; 116 117 /// @} 118 119 MachSymbolData *findSymbolData(const MCSymbol &Sym); 120 121 public: MachObjectWriter(MCMachObjectTargetWriter * MOTW,raw_pwrite_stream & OS,bool IsLittleEndian)122 MachObjectWriter(MCMachObjectTargetWriter *MOTW, raw_pwrite_stream &OS, 123 bool IsLittleEndian) 124 : MCObjectWriter(OS, IsLittleEndian), TargetObjectWriter(MOTW) {} 125 126 /// @name Lifetime management Methods 127 /// @{ 128 129 void reset() override; 130 131 /// @} 132 133 /// @name Utility Methods 134 /// @{ 135 136 bool isFixupKindPCRel(const MCAssembler &Asm, unsigned Kind); 137 138 SectionAddrMap SectionAddress; 139 getSectionAddressMap()140 SectionAddrMap &getSectionAddressMap() { return SectionAddress; } 141 getSectionAddress(const MCSectionData * SD)142 uint64_t getSectionAddress(const MCSectionData* SD) const { 143 return SectionAddress.lookup(SD); 144 } 145 uint64_t getSymbolAddress(const MCSymbolData* SD, 146 const MCAsmLayout &Layout) const; 147 148 uint64_t getFragmentAddress(const MCFragment *Fragment, 149 const MCAsmLayout &Layout) const; 150 151 uint64_t getPaddingSize(const MCSectionData *SD, 152 const MCAsmLayout &Layout) const; 153 154 bool doesSymbolRequireExternRelocation(const MCSymbolData *SD); 155 156 /// @} 157 158 /// @name Target Writer Proxy Accessors 159 /// @{ 160 is64Bit()161 bool is64Bit() const { return TargetObjectWriter->is64Bit(); } isX86_64()162 bool isX86_64() const { 163 uint32_t CPUType = TargetObjectWriter->getCPUType(); 164 return CPUType == MachO::CPU_TYPE_X86_64; 165 } 166 167 /// @} 168 169 void WriteHeader(unsigned NumLoadCommands, unsigned LoadCommandsSize, 170 bool SubsectionsViaSymbols); 171 172 /// WriteSegmentLoadCommand - Write a segment load command. 173 /// 174 /// \param NumSections The number of sections in this segment. 175 /// \param SectionDataSize The total size of the sections. 176 void WriteSegmentLoadCommand(unsigned NumSections, 177 uint64_t VMSize, 178 uint64_t SectionDataStartOffset, 179 uint64_t SectionDataSize); 180 181 void WriteSection(const MCAssembler &Asm, const MCAsmLayout &Layout, 182 const MCSectionData &SD, uint64_t FileOffset, 183 uint64_t RelocationsStart, unsigned NumRelocations); 184 185 void WriteSymtabLoadCommand(uint32_t SymbolOffset, uint32_t NumSymbols, 186 uint32_t StringTableOffset, 187 uint32_t StringTableSize); 188 189 void WriteDysymtabLoadCommand(uint32_t FirstLocalSymbol, 190 uint32_t NumLocalSymbols, 191 uint32_t FirstExternalSymbol, 192 uint32_t NumExternalSymbols, 193 uint32_t FirstUndefinedSymbol, 194 uint32_t NumUndefinedSymbols, 195 uint32_t IndirectSymbolOffset, 196 uint32_t NumIndirectSymbols); 197 198 void WriteNlist(MachSymbolData &MSD, const MCAsmLayout &Layout); 199 200 void WriteLinkeditLoadCommand(uint32_t Type, uint32_t DataOffset, 201 uint32_t DataSize); 202 203 void WriteLinkerOptionsLoadCommand(const std::vector<std::string> &Options); 204 205 // FIXME: We really need to improve the relocation validation. Basically, we 206 // want to implement a separate computation which evaluates the relocation 207 // entry as the linker would, and verifies that the resultant fixup value is 208 // exactly what the encoder wanted. This will catch several classes of 209 // problems: 210 // 211 // - Relocation entry bugs, the two algorithms are unlikely to have the same 212 // exact bug. 213 // 214 // - Relaxation issues, where we forget to relax something. 215 // 216 // - Input errors, where something cannot be correctly encoded. 'as' allows 217 // these through in many cases. 218 219 // Add a relocation to be output in the object file. At the time this is 220 // called, the symbol indexes are not know, so if the relocation refers 221 // to a symbol it should be passed as \p RelSymbol so that it can be updated 222 // afterwards. If the relocation doesn't refer to a symbol, nullptr should be 223 // used. addRelocation(const MCSymbolData * RelSymbol,const MCSectionData * SD,MachO::any_relocation_info & MRE)224 void addRelocation(const MCSymbolData *RelSymbol, const MCSectionData *SD, 225 MachO::any_relocation_info &MRE) { 226 RelAndSymbol P(RelSymbol, MRE); 227 Relocations[SD].push_back(P); 228 } 229 230 void RecordScatteredRelocation(const MCAssembler &Asm, 231 const MCAsmLayout &Layout, 232 const MCFragment *Fragment, 233 const MCFixup &Fixup, MCValue Target, 234 unsigned Log2Size, 235 uint64_t &FixedValue); 236 237 void RecordTLVPRelocation(const MCAssembler &Asm, 238 const MCAsmLayout &Layout, 239 const MCFragment *Fragment, 240 const MCFixup &Fixup, MCValue Target, 241 uint64_t &FixedValue); 242 243 void RecordRelocation(MCAssembler &Asm, const MCAsmLayout &Layout, 244 const MCFragment *Fragment, const MCFixup &Fixup, 245 MCValue Target, bool &IsPCRel, 246 uint64_t &FixedValue) override; 247 248 void BindIndirectSymbols(MCAssembler &Asm); 249 250 /// ComputeSymbolTable - Compute the symbol table data 251 /// 252 void ComputeSymbolTable(MCAssembler &Asm, 253 std::vector<MachSymbolData> &LocalSymbolData, 254 std::vector<MachSymbolData> &ExternalSymbolData, 255 std::vector<MachSymbolData> &UndefinedSymbolData); 256 257 void computeSectionAddresses(const MCAssembler &Asm, 258 const MCAsmLayout &Layout); 259 260 void ExecutePostLayoutBinding(MCAssembler &Asm, 261 const MCAsmLayout &Layout) override; 262 263 bool IsSymbolRefDifferenceFullyResolvedImpl(const MCAssembler &Asm, 264 const MCSymbolData &DataA, 265 const MCSymbolData *DataB, 266 const MCFragment &FB, 267 bool InSet, 268 bool IsPCRel) const override; 269 270 void WriteObject(MCAssembler &Asm, const MCAsmLayout &Layout) override; 271 }; 272 273 274 /// \brief Construct a new Mach-O writer instance. 275 /// 276 /// This routine takes ownership of the target writer subclass. 277 /// 278 /// \param MOTW - The target specific Mach-O writer subclass. 279 /// \param OS - The stream to write to. 280 /// \returns The constructed object writer. 281 MCObjectWriter *createMachObjectWriter(MCMachObjectTargetWriter *MOTW, 282 raw_pwrite_stream &OS, 283 bool IsLittleEndian); 284 285 } // End llvm namespace 286 287 #endif 288