MCMachObjectWriter.h 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. #pragma once
  2. #ifdef __GNUC__
  3. #pragma GCC diagnostic push
  4. #pragma GCC diagnostic ignored "-Wunused-parameter"
  5. #endif
  6. //===- llvm/MC/MCMachObjectWriter.h - Mach Object Writer --------*- C++ -*-===//
  7. //
  8. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  9. // See https://llvm.org/LICENSE.txt for license information.
  10. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  11. //
  12. //===----------------------------------------------------------------------===//
  13. #ifndef LLVM_MC_MCMACHOBJECTWRITER_H
  14. #define LLVM_MC_MCMACHOBJECTWRITER_H
  15. #include "llvm/ADT/DenseMap.h"
  16. #include "llvm/ADT/StringRef.h"
  17. #include "llvm/BinaryFormat/MachO.h"
  18. #include "llvm/MC/MCExpr.h"
  19. #include "llvm/MC/MCObjectWriter.h"
  20. #include "llvm/MC/MCSection.h"
  21. #include "llvm/MC/StringTableBuilder.h"
  22. #include "llvm/Support/EndianStream.h"
  23. #include <cstdint>
  24. #include <memory>
  25. #include <string>
  26. #include <vector>
  27. namespace llvm {
  28. class MachObjectWriter;
  29. class MCMachObjectTargetWriter : public MCObjectTargetWriter {
  30. const unsigned Is64Bit : 1;
  31. const uint32_t CPUType;
  32. protected:
  33. uint32_t CPUSubtype;
  34. public:
  35. unsigned LocalDifference_RIT;
  36. protected:
  37. MCMachObjectTargetWriter(bool Is64Bit_, uint32_t CPUType_,
  38. uint32_t CPUSubtype_);
  39. void setLocalDifferenceRelocationType(unsigned Type) {
  40. LocalDifference_RIT = Type;
  41. }
  42. public:
  43. virtual ~MCMachObjectTargetWriter();
  44. Triple::ObjectFormatType getFormat() const override { return Triple::MachO; }
  45. static bool classof(const MCObjectTargetWriter *W) {
  46. return W->getFormat() == Triple::MachO;
  47. }
  48. /// \name Lifetime Management
  49. /// @{
  50. virtual void reset() {}
  51. /// @}
  52. /// \name Accessors
  53. /// @{
  54. bool is64Bit() const { return Is64Bit; }
  55. uint32_t getCPUType() const { return CPUType; }
  56. uint32_t getCPUSubtype() const { return CPUSubtype; }
  57. unsigned getLocalDifferenceRelocationType() const {
  58. return LocalDifference_RIT;
  59. }
  60. /// @}
  61. /// \name API
  62. /// @{
  63. virtual void recordRelocation(MachObjectWriter *Writer, MCAssembler &Asm,
  64. const MCAsmLayout &Layout,
  65. const MCFragment *Fragment,
  66. const MCFixup &Fixup, MCValue Target,
  67. uint64_t &FixedValue) = 0;
  68. /// @}
  69. };
  70. class MachObjectWriter : public MCObjectWriter {
  71. /// Helper struct for containing some precomputed information on symbols.
  72. struct MachSymbolData {
  73. const MCSymbol *Symbol;
  74. uint64_t StringIndex;
  75. uint8_t SectionIndex;
  76. // Support lexicographic sorting.
  77. bool operator<(const MachSymbolData &RHS) const;
  78. };
  79. /// The target specific Mach-O writer instance.
  80. std::unique_ptr<MCMachObjectTargetWriter> TargetObjectWriter;
  81. /// \name Relocation Data
  82. /// @{
  83. struct RelAndSymbol {
  84. const MCSymbol *Sym;
  85. MachO::any_relocation_info MRE;
  86. RelAndSymbol(const MCSymbol *Sym, const MachO::any_relocation_info &MRE)
  87. : Sym(Sym), MRE(MRE) {}
  88. };
  89. DenseMap<const MCSection *, std::vector<RelAndSymbol>> Relocations;
  90. DenseMap<const MCSection *, unsigned> IndirectSymBase;
  91. SectionAddrMap SectionAddress;
  92. /// @}
  93. /// \name Symbol Table Data
  94. /// @{
  95. StringTableBuilder StringTable;
  96. std::vector<MachSymbolData> LocalSymbolData;
  97. std::vector<MachSymbolData> ExternalSymbolData;
  98. std::vector<MachSymbolData> UndefinedSymbolData;
  99. /// @}
  100. MachSymbolData *findSymbolData(const MCSymbol &Sym);
  101. void writeWithPadding(StringRef Str, uint64_t Size);
  102. public:
  103. MachObjectWriter(std::unique_ptr<MCMachObjectTargetWriter> MOTW,
  104. raw_pwrite_stream &OS, bool IsLittleEndian)
  105. : TargetObjectWriter(std::move(MOTW)),
  106. StringTable(TargetObjectWriter->is64Bit() ? StringTableBuilder::MachO64
  107. : StringTableBuilder::MachO),
  108. W(OS, IsLittleEndian ? support::little : support::big) {}
  109. support::endian::Writer W;
  110. const MCSymbol &findAliasedSymbol(const MCSymbol &Sym) const;
  111. /// \name Lifetime management Methods
  112. /// @{
  113. void reset() override;
  114. /// @}
  115. /// \name Utility Methods
  116. /// @{
  117. bool isFixupKindPCRel(const MCAssembler &Asm, unsigned Kind);
  118. SectionAddrMap &getSectionAddressMap() { return SectionAddress; }
  119. uint64_t getSectionAddress(const MCSection *Sec) const {
  120. return SectionAddress.lookup(Sec);
  121. }
  122. uint64_t getSymbolAddress(const MCSymbol &S, const MCAsmLayout &Layout) const;
  123. uint64_t getFragmentAddress(const MCFragment *Fragment,
  124. const MCAsmLayout &Layout) const;
  125. uint64_t getPaddingSize(const MCSection *SD, const MCAsmLayout &Layout) const;
  126. bool doesSymbolRequireExternRelocation(const MCSymbol &S);
  127. /// @}
  128. /// \name Target Writer Proxy Accessors
  129. /// @{
  130. bool is64Bit() const { return TargetObjectWriter->is64Bit(); }
  131. bool isX86_64() const {
  132. uint32_t CPUType = TargetObjectWriter->getCPUType();
  133. return CPUType == MachO::CPU_TYPE_X86_64;
  134. }
  135. /// @}
  136. void writeHeader(MachO::HeaderFileType Type, unsigned NumLoadCommands,
  137. unsigned LoadCommandsSize, bool SubsectionsViaSymbols);
  138. /// Write a segment load command.
  139. ///
  140. /// \param NumSections The number of sections in this segment.
  141. /// \param SectionDataSize The total size of the sections.
  142. void writeSegmentLoadCommand(StringRef Name, unsigned NumSections,
  143. uint64_t VMAddr, uint64_t VMSize,
  144. uint64_t SectionDataStartOffset,
  145. uint64_t SectionDataSize, uint32_t MaxProt,
  146. uint32_t InitProt);
  147. void writeSection(const MCAsmLayout &Layout, const MCSection &Sec,
  148. uint64_t VMAddr, uint64_t FileOffset, unsigned Flags,
  149. uint64_t RelocationsStart, unsigned NumRelocations);
  150. void writeSymtabLoadCommand(uint32_t SymbolOffset, uint32_t NumSymbols,
  151. uint32_t StringTableOffset,
  152. uint32_t StringTableSize);
  153. void writeDysymtabLoadCommand(
  154. uint32_t FirstLocalSymbol, uint32_t NumLocalSymbols,
  155. uint32_t FirstExternalSymbol, uint32_t NumExternalSymbols,
  156. uint32_t FirstUndefinedSymbol, uint32_t NumUndefinedSymbols,
  157. uint32_t IndirectSymbolOffset, uint32_t NumIndirectSymbols);
  158. void writeNlist(MachSymbolData &MSD, const MCAsmLayout &Layout);
  159. void writeLinkeditLoadCommand(uint32_t Type, uint32_t DataOffset,
  160. uint32_t DataSize);
  161. void writeLinkerOptionsLoadCommand(const std::vector<std::string> &Options);
  162. // FIXME: We really need to improve the relocation validation. Basically, we
  163. // want to implement a separate computation which evaluates the relocation
  164. // entry as the linker would, and verifies that the resultant fixup value is
  165. // exactly what the encoder wanted. This will catch several classes of
  166. // problems:
  167. //
  168. // - Relocation entry bugs, the two algorithms are unlikely to have the same
  169. // exact bug.
  170. //
  171. // - Relaxation issues, where we forget to relax something.
  172. //
  173. // - Input errors, where something cannot be correctly encoded. 'as' allows
  174. // these through in many cases.
  175. // Add a relocation to be output in the object file. At the time this is
  176. // called, the symbol indexes are not know, so if the relocation refers
  177. // to a symbol it should be passed as \p RelSymbol so that it can be updated
  178. // afterwards. If the relocation doesn't refer to a symbol, nullptr should be
  179. // used.
  180. void addRelocation(const MCSymbol *RelSymbol, const MCSection *Sec,
  181. MachO::any_relocation_info &MRE) {
  182. RelAndSymbol P(RelSymbol, MRE);
  183. Relocations[Sec].push_back(P);
  184. }
  185. void recordRelocation(MCAssembler &Asm, const MCAsmLayout &Layout,
  186. const MCFragment *Fragment, const MCFixup &Fixup,
  187. MCValue Target, uint64_t &FixedValue) override;
  188. void bindIndirectSymbols(MCAssembler &Asm);
  189. /// Compute the symbol table data.
  190. void computeSymbolTable(MCAssembler &Asm,
  191. std::vector<MachSymbolData> &LocalSymbolData,
  192. std::vector<MachSymbolData> &ExternalSymbolData,
  193. std::vector<MachSymbolData> &UndefinedSymbolData);
  194. void computeSectionAddresses(const MCAssembler &Asm,
  195. const MCAsmLayout &Layout);
  196. void executePostLayoutBinding(MCAssembler &Asm,
  197. const MCAsmLayout &Layout) override;
  198. bool isSymbolRefDifferenceFullyResolvedImpl(const MCAssembler &Asm,
  199. const MCSymbol &A,
  200. const MCSymbol &B,
  201. bool InSet) const override;
  202. bool isSymbolRefDifferenceFullyResolvedImpl(const MCAssembler &Asm,
  203. const MCSymbol &SymA,
  204. const MCFragment &FB, bool InSet,
  205. bool IsPCRel) const override;
  206. uint64_t writeObject(MCAssembler &Asm, const MCAsmLayout &Layout) override;
  207. };
  208. /// Construct a new Mach-O writer instance.
  209. ///
  210. /// This routine takes ownership of the target writer subclass.
  211. ///
  212. /// \param MOTW - The target specific Mach-O writer subclass.
  213. /// \param OS - The stream to write to.
  214. /// \returns The constructed object writer.
  215. std::unique_ptr<MCObjectWriter>
  216. createMachObjectWriter(std::unique_ptr<MCMachObjectTargetWriter> MOTW,
  217. raw_pwrite_stream &OS, bool IsLittleEndian);
  218. } // end namespace llvm
  219. #endif // LLVM_MC_MCMACHOBJECTWRITER_H
  220. #ifdef __GNUC__
  221. #pragma GCC diagnostic pop
  222. #endif