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
22namespace llvm {
23
24class MCSectionData;
25class MachObjectWriter;
26
27class 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
36protected:
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
45public:
46  virtual ~MCMachObjectTargetWriter();
47
48  /// @name Lifetime Management
49  /// @{
50
51  virtual void reset() {};
52
53  /// @}
54
55  /// @name Accessors
56  /// @{
57
58  bool is64Bit() const { return Is64Bit; }
59  bool useAggressiveSymbolFolding() const { return UseAggressiveSymbolFolding; }
60  uint32_t getCPUType() const { return CPUType; }
61  uint32_t getCPUSubtype() const { return CPUSubtype; }
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
80class 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;
101    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
121public:
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
140  SectionAddrMap &getSectionAddressMap() { return SectionAddress; }
141
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
161  bool is64Bit() const { return TargetObjectWriter->is64Bit(); }
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.
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.
281MCObjectWriter *createMachObjectWriter(MCMachObjectTargetWriter *MOTW,
282                                       raw_pwrite_stream &OS,
283                                       bool IsLittleEndian);
284
285} // End llvm namespace
286
287#endif
288