1 //===- llvm/MC/MCMachObjectWriter.h - Mach Object Writer --------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #ifndef LLVM_MC_MCMACHOBJECTWRITER_H 10 #define LLVM_MC_MCMACHOBJECTWRITER_H 11 12 #include "llvm/ADT/DenseMap.h" 13 #include "llvm/ADT/StringRef.h" 14 #include "llvm/BinaryFormat/MachO.h" 15 #include "llvm/MC/MCDirectives.h" 16 #include "llvm/MC/MCExpr.h" 17 #include "llvm/MC/MCLinkerOptimizationHint.h" 18 #include "llvm/MC/MCObjectWriter.h" 19 #include "llvm/MC/MCSection.h" 20 #include "llvm/MC/StringTableBuilder.h" 21 #include "llvm/Support/EndianStream.h" 22 #include "llvm/Support/VersionTuple.h" 23 #include <cstdint> 24 #include <memory> 25 #include <string> 26 #include <vector> 27 28 namespace llvm { 29 30 class MachObjectWriter; 31 32 class MCMachObjectTargetWriter : public MCObjectTargetWriter { 33 const unsigned Is64Bit : 1; 34 const uint32_t CPUType; 35 protected: 36 uint32_t CPUSubtype; 37 public: 38 unsigned LocalDifference_RIT = 0; 39 40 protected: 41 MCMachObjectTargetWriter(bool Is64Bit_, uint32_t CPUType_, 42 uint32_t CPUSubtype_); 43 setLocalDifferenceRelocationType(unsigned Type)44 void setLocalDifferenceRelocationType(unsigned Type) { 45 LocalDifference_RIT = Type; 46 } 47 48 public: 49 virtual ~MCMachObjectTargetWriter(); 50 getFormat()51 Triple::ObjectFormatType getFormat() const override { return Triple::MachO; } classof(const MCObjectTargetWriter * W)52 static bool classof(const MCObjectTargetWriter *W) { 53 return W->getFormat() == Triple::MachO; 54 } 55 56 /// \name Lifetime Management 57 /// @{ 58 reset()59 virtual void reset() {} 60 61 /// @} 62 63 /// \name Accessors 64 /// @{ 65 is64Bit()66 bool is64Bit() const { return Is64Bit; } getCPUType()67 uint32_t getCPUType() const { return CPUType; } getCPUSubtype()68 uint32_t getCPUSubtype() const { return CPUSubtype; } getLocalDifferenceRelocationType()69 unsigned getLocalDifferenceRelocationType() const { 70 return LocalDifference_RIT; 71 } 72 73 /// @} 74 75 /// \name API 76 /// @{ 77 78 virtual void recordRelocation(MachObjectWriter *Writer, MCAssembler &Asm, 79 const MCFragment *Fragment, 80 const MCFixup &Fixup, MCValue Target, 81 uint64_t &FixedValue) = 0; 82 83 /// @} 84 }; 85 86 class MachObjectWriter : public MCObjectWriter { 87 public: 88 struct DataRegionData { 89 MachO::DataRegionType Kind; 90 MCSymbol *Start; 91 MCSymbol *End; 92 }; 93 94 // A Major version of 0 indicates that no version information was supplied 95 // and so the corresponding load command should not be emitted. 96 using VersionInfoType = struct { 97 bool EmitBuildVersion; 98 union { 99 MCVersionMinType Type; ///< Used when EmitBuildVersion==false. 100 MachO::PlatformType Platform; ///< Used when EmitBuildVersion==true. 101 } TypeOrPlatform; 102 unsigned Major; 103 unsigned Minor; 104 unsigned Update; 105 /// An optional version of the SDK that was used to build the source. 106 VersionTuple SDKVersion; 107 }; 108 109 private: 110 /// Helper struct for containing some precomputed information on symbols. 111 struct MachSymbolData { 112 const MCSymbol *Symbol; 113 uint64_t StringIndex; 114 uint8_t SectionIndex; 115 116 // Support lexicographic sorting. 117 bool operator<(const MachSymbolData &RHS) const; 118 }; 119 120 struct IndirectSymbolData { 121 MCSymbol *Symbol; 122 MCSection *Section; 123 }; 124 125 /// The target specific Mach-O writer instance. 126 std::unique_ptr<MCMachObjectTargetWriter> TargetObjectWriter; 127 128 /// \name Relocation Data 129 /// @{ 130 131 struct RelAndSymbol { 132 const MCSymbol *Sym; 133 MachO::any_relocation_info MRE; RelAndSymbolRelAndSymbol134 RelAndSymbol(const MCSymbol *Sym, const MachO::any_relocation_info &MRE) 135 : Sym(Sym), MRE(MRE) {} 136 }; 137 138 DenseMap<const MCSection *, std::vector<RelAndSymbol>> Relocations; 139 std::vector<IndirectSymbolData> IndirectSymbols; 140 DenseMap<const MCSection *, unsigned> IndirectSymBase; 141 142 std::vector<DataRegionData> DataRegions; 143 144 SectionAddrMap SectionAddress; 145 146 // List of sections in layout order. Virtual sections are after non-virtual 147 // sections. 148 SmallVector<MCSection *, 0> SectionOrder; 149 150 /// @} 151 /// \name Symbol Table Data 152 /// @{ 153 154 StringTableBuilder StringTable; 155 std::vector<MachSymbolData> LocalSymbolData; 156 std::vector<MachSymbolData> ExternalSymbolData; 157 std::vector<MachSymbolData> UndefinedSymbolData; 158 159 /// @} 160 161 // Used to communicate Linker Optimization Hint information. 162 MCLOHContainer LOHContainer; 163 164 VersionInfoType VersionInfo{}; 165 VersionInfoType TargetVariantVersionInfo{}; 166 167 // The list of linker options for LC_LINKER_OPTION. 168 std::vector<std::vector<std::string>> LinkerOptions; 169 170 MachSymbolData *findSymbolData(const MCSymbol &Sym); 171 172 void writeWithPadding(StringRef Str, uint64_t Size); 173 174 public: MachObjectWriter(std::unique_ptr<MCMachObjectTargetWriter> MOTW,raw_pwrite_stream & OS,bool IsLittleEndian)175 MachObjectWriter(std::unique_ptr<MCMachObjectTargetWriter> MOTW, 176 raw_pwrite_stream &OS, bool IsLittleEndian) 177 : TargetObjectWriter(std::move(MOTW)), 178 StringTable(TargetObjectWriter->is64Bit() ? StringTableBuilder::MachO64 179 : StringTableBuilder::MachO), 180 W(OS, 181 IsLittleEndian ? llvm::endianness::little : llvm::endianness::big) {} 182 183 support::endian::Writer W; 184 185 const MCSymbol &findAliasedSymbol(const MCSymbol &Sym) const; 186 187 /// \name Lifetime management Methods 188 /// @{ 189 190 void reset() override; 191 192 /// @} 193 194 /// \name Utility Methods 195 /// @{ 196 197 bool isFixupKindPCRel(const MCAssembler &Asm, unsigned Kind); 198 getIndirectSymbols()199 std::vector<IndirectSymbolData> &getIndirectSymbols() { 200 return IndirectSymbols; 201 } getDataRegions()202 std::vector<DataRegionData> &getDataRegions() { return DataRegions; } getSectionOrder()203 const llvm::SmallVectorImpl<MCSection *> &getSectionOrder() const { 204 return SectionOrder; 205 } getSectionAddressMap()206 SectionAddrMap &getSectionAddressMap() { return SectionAddress; } getLOHContainer()207 MCLOHContainer &getLOHContainer() { return LOHContainer; } 208 getSectionAddress(const MCSection * Sec)209 uint64_t getSectionAddress(const MCSection *Sec) const { 210 return SectionAddress.lookup(Sec); 211 } 212 uint64_t getSymbolAddress(const MCSymbol &S, const MCAssembler &Asm) const; 213 214 uint64_t getFragmentAddress(const MCAssembler &Asm, 215 const MCFragment *Fragment) const; 216 217 uint64_t getPaddingSize(const MCAssembler &Asm, const MCSection *SD) const; 218 219 const MCSymbol *getAtom(const MCSymbol &S) const; 220 221 bool doesSymbolRequireExternRelocation(const MCSymbol &S); 222 223 /// Mach-O deployment target version information. 224 void setVersionMin(MCVersionMinType Type, unsigned Major, unsigned Minor, 225 unsigned Update, 226 VersionTuple SDKVersion = VersionTuple()) { 227 VersionInfo.EmitBuildVersion = false; 228 VersionInfo.TypeOrPlatform.Type = Type; 229 VersionInfo.Major = Major; 230 VersionInfo.Minor = Minor; 231 VersionInfo.Update = Update; 232 VersionInfo.SDKVersion = SDKVersion; 233 } 234 void setBuildVersion(MachO::PlatformType Platform, unsigned Major, 235 unsigned Minor, unsigned Update, 236 VersionTuple SDKVersion = VersionTuple()) { 237 VersionInfo.EmitBuildVersion = true; 238 VersionInfo.TypeOrPlatform.Platform = Platform; 239 VersionInfo.Major = Major; 240 VersionInfo.Minor = Minor; 241 VersionInfo.Update = Update; 242 VersionInfo.SDKVersion = SDKVersion; 243 } setTargetVariantBuildVersion(MachO::PlatformType Platform,unsigned Major,unsigned Minor,unsigned Update,VersionTuple SDKVersion)244 void setTargetVariantBuildVersion(MachO::PlatformType Platform, 245 unsigned Major, unsigned Minor, 246 unsigned Update, VersionTuple SDKVersion) { 247 TargetVariantVersionInfo.EmitBuildVersion = true; 248 TargetVariantVersionInfo.TypeOrPlatform.Platform = Platform; 249 TargetVariantVersionInfo.Major = Major; 250 TargetVariantVersionInfo.Minor = Minor; 251 TargetVariantVersionInfo.Update = Update; 252 TargetVariantVersionInfo.SDKVersion = SDKVersion; 253 } 254 getLinkerOptions()255 std::vector<std::vector<std::string>> &getLinkerOptions() { 256 return LinkerOptions; 257 } 258 259 /// @} 260 261 /// \name Target Writer Proxy Accessors 262 /// @{ 263 is64Bit()264 bool is64Bit() const { return TargetObjectWriter->is64Bit(); } isX86_64()265 bool isX86_64() const { 266 uint32_t CPUType = TargetObjectWriter->getCPUType(); 267 return CPUType == MachO::CPU_TYPE_X86_64; 268 } 269 270 /// @} 271 272 void writeHeader(MachO::HeaderFileType Type, unsigned NumLoadCommands, 273 unsigned LoadCommandsSize, bool SubsectionsViaSymbols); 274 275 /// Write a segment load command. 276 /// 277 /// \param NumSections The number of sections in this segment. 278 /// \param SectionDataSize The total size of the sections. 279 void writeSegmentLoadCommand(StringRef Name, unsigned NumSections, 280 uint64_t VMAddr, uint64_t VMSize, 281 uint64_t SectionDataStartOffset, 282 uint64_t SectionDataSize, uint32_t MaxProt, 283 uint32_t InitProt); 284 285 void writeSection(const MCAssembler &Asm, const MCSection &Sec, 286 uint64_t VMAddr, uint64_t FileOffset, unsigned Flags, 287 uint64_t RelocationsStart, unsigned NumRelocations); 288 289 void writeSymtabLoadCommand(uint32_t SymbolOffset, uint32_t NumSymbols, 290 uint32_t StringTableOffset, 291 uint32_t StringTableSize); 292 293 void writeDysymtabLoadCommand( 294 uint32_t FirstLocalSymbol, uint32_t NumLocalSymbols, 295 uint32_t FirstExternalSymbol, uint32_t NumExternalSymbols, 296 uint32_t FirstUndefinedSymbol, uint32_t NumUndefinedSymbols, 297 uint32_t IndirectSymbolOffset, uint32_t NumIndirectSymbols); 298 299 void writeNlist(MachSymbolData &MSD, const MCAssembler &Asm); 300 301 void writeLinkeditLoadCommand(uint32_t Type, uint32_t DataOffset, 302 uint32_t DataSize); 303 304 void writeLinkerOptionsLoadCommand(const std::vector<std::string> &Options); 305 306 // FIXME: We really need to improve the relocation validation. Basically, we 307 // want to implement a separate computation which evaluates the relocation 308 // entry as the linker would, and verifies that the resultant fixup value is 309 // exactly what the encoder wanted. This will catch several classes of 310 // problems: 311 // 312 // - Relocation entry bugs, the two algorithms are unlikely to have the same 313 // exact bug. 314 // 315 // - Relaxation issues, where we forget to relax something. 316 // 317 // - Input errors, where something cannot be correctly encoded. 'as' allows 318 // these through in many cases. 319 320 // Add a relocation to be output in the object file. At the time this is 321 // called, the symbol indexes are not know, so if the relocation refers 322 // to a symbol it should be passed as \p RelSymbol so that it can be updated 323 // afterwards. If the relocation doesn't refer to a symbol, nullptr should be 324 // used. addRelocation(const MCSymbol * RelSymbol,const MCSection * Sec,MachO::any_relocation_info & MRE)325 void addRelocation(const MCSymbol *RelSymbol, const MCSection *Sec, 326 MachO::any_relocation_info &MRE) { 327 RelAndSymbol P(RelSymbol, MRE); 328 Relocations[Sec].push_back(P); 329 } 330 331 void recordRelocation(MCAssembler &Asm, const MCFragment *Fragment, 332 const MCFixup &Fixup, MCValue Target, 333 uint64_t &FixedValue) override; 334 335 void bindIndirectSymbols(MCAssembler &Asm); 336 337 /// Compute the symbol table data. 338 void computeSymbolTable(MCAssembler &Asm, 339 std::vector<MachSymbolData> &LocalSymbolData, 340 std::vector<MachSymbolData> &ExternalSymbolData, 341 std::vector<MachSymbolData> &UndefinedSymbolData); 342 343 void computeSectionAddresses(const MCAssembler &Asm); 344 345 void executePostLayoutBinding(MCAssembler &Asm) override; 346 347 bool isSymbolRefDifferenceFullyResolvedImpl(const MCAssembler &Asm, 348 const MCSymbol &SymA, 349 const MCFragment &FB, bool InSet, 350 bool IsPCRel) const override; 351 352 void populateAddrSigSection(MCAssembler &Asm); 353 354 uint64_t writeObject(MCAssembler &Asm) override; 355 }; 356 357 /// Construct a new Mach-O writer instance. 358 /// 359 /// This routine takes ownership of the target writer subclass. 360 /// 361 /// \param MOTW - The target specific Mach-O writer subclass. 362 /// \param OS - The stream to write to. 363 /// \returns The constructed object writer. 364 std::unique_ptr<MCObjectWriter> 365 createMachObjectWriter(std::unique_ptr<MCMachObjectTargetWriter> MOTW, 366 raw_pwrite_stream &OS, bool IsLittleEndian); 367 368 } // end namespace llvm 369 370 #endif // LLVM_MC_MCMACHOBJECTWRITER_H 371