reference, declarationdefinition
definition → references, declarations, derived classes, virtual overrides
reference to multiple definitions → definitions
unreferenced
    1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146
  147
  148
  149
  150
  151
  152
  153
  154
  155
  156
  157
  158
  159
  160
  161
  162
  163
  164
  165
  166
  167
  168
  169
  170
  171
  172
  173
  174
  175
  176
  177
  178
  179
  180
  181
  182
  183
  184
  185
  186
  187
  188
  189
  190
  191
  192
  193
  194
  195
  196
  197
  198
  199
  200
  201
  202
  203
  204
  205
  206
  207
  208
  209
  210
  211
  212
  213
  214
  215
  216
  217
  218
  219
  220
  221
  222
  223
  224
  225
  226
  227
  228
  229
  230
  231
  232
  233
  234
  235
  236
  237
  238
  239
  240
  241
  242
  243
  244
  245
  246
  247
  248
  249
  250
  251
  252
  253
  254
  255
  256
  257
  258
  259
  260
  261
  262
  263
  264
  265
  266
  267
  268
  269
  270
  271
  272
  273
  274
  275
  276
  277
  278
  279
  280
  281
  282
  283
  284
  285
  286
  287
//===- llvm/MC/MCMachObjectWriter.h - Mach Object Writer --------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_MC_MCMACHOBJECTWRITER_H
#define LLVM_MC_MCMACHOBJECTWRITER_H

#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/BinaryFormat/MachO.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCObjectWriter.h"
#include "llvm/MC/MCSection.h"
#include "llvm/MC/StringTableBuilder.h"
#include <cstdint>
#include <memory>
#include <string>
#include <vector>

namespace llvm {

class MachObjectWriter;

class MCMachObjectTargetWriter : public MCObjectTargetWriter {
  const unsigned Is64Bit : 1;
  const uint32_t CPUType;
  const uint32_t CPUSubtype;
  unsigned LocalDifference_RIT;

protected:
  MCMachObjectTargetWriter(bool Is64Bit_, uint32_t CPUType_,
                           uint32_t CPUSubtype_);

  void setLocalDifferenceRelocationType(unsigned Type) {
    LocalDifference_RIT = Type;
  }

public:
  virtual ~MCMachObjectTargetWriter();

  virtual Triple::ObjectFormatType getFormat() const { return Triple::MachO; }
  static bool classof(const MCObjectTargetWriter *W) {
    return W->getFormat() == Triple::MachO;
  }

  /// \name Lifetime Management
  /// @{

  virtual void reset() {}

  /// @}

  /// \name Accessors
  /// @{

  bool is64Bit() const { return Is64Bit; }
  uint32_t getCPUType() const { return CPUType; }
  uint32_t getCPUSubtype() const { return CPUSubtype; }
  unsigned getLocalDifferenceRelocationType() const {
    return LocalDifference_RIT;
  }

  /// @}

  /// \name API
  /// @{

  virtual void recordRelocation(MachObjectWriter *Writer, MCAssembler &Asm,
                                const MCAsmLayout &Layout,
                                const MCFragment *Fragment,
                                const MCFixup &Fixup, MCValue Target,
                                uint64_t &FixedValue) = 0;

  /// @}
};

class MachObjectWriter : public MCObjectWriter {
  /// Helper struct for containing some precomputed information on symbols.
  struct MachSymbolData {
    const MCSymbol *Symbol;
    uint64_t StringIndex;
    uint8_t SectionIndex;

    // Support lexicographic sorting.
    bool operator<(const MachSymbolData &RHS) const;
  };

  /// The target specific Mach-O writer instance.
  std::unique_ptr<MCMachObjectTargetWriter> TargetObjectWriter;

  /// \name Relocation Data
  /// @{

  struct RelAndSymbol {
    const MCSymbol *Sym;
    MachO::any_relocation_info MRE;
    RelAndSymbol(const MCSymbol *Sym, const MachO::any_relocation_info &MRE)
        : Sym(Sym), MRE(MRE) {}
  };

  DenseMap<const MCSection *, std::vector<RelAndSymbol>> Relocations;
  DenseMap<const MCSection *, unsigned> IndirectSymBase;

  SectionAddrMap SectionAddress;

  /// @}
  /// \name Symbol Table Data
  /// @{

  StringTableBuilder StringTable{StringTableBuilder::MachO};
  std::vector<MachSymbolData> LocalSymbolData;
  std::vector<MachSymbolData> ExternalSymbolData;
  std::vector<MachSymbolData> UndefinedSymbolData;

  /// @}

  MachSymbolData *findSymbolData(const MCSymbol &Sym);

  void writeWithPadding(StringRef Str, uint64_t Size);

public:
  MachObjectWriter(std::unique_ptr<MCMachObjectTargetWriter> MOTW,
                   raw_pwrite_stream &OS, bool IsLittleEndian)
      : TargetObjectWriter(std::move(MOTW)),
        W(OS, IsLittleEndian ? support::little : support::big) {}

  support::endian::Writer W;

  const MCSymbol &findAliasedSymbol(const MCSymbol &Sym) const;

  /// \name Lifetime management Methods
  /// @{

  void reset() override;

  /// @}

  /// \name Utility Methods
  /// @{

  bool isFixupKindPCRel(const MCAssembler &Asm, unsigned Kind);

  SectionAddrMap &getSectionAddressMap() { return SectionAddress; }

  uint64_t getSectionAddress(const MCSection *Sec) const {
    return SectionAddress.lookup(Sec);
  }
  uint64_t getSymbolAddress(const MCSymbol &S, const MCAsmLayout &Layout) const;

  uint64_t getFragmentAddress(const MCFragment *Fragment,
                              const MCAsmLayout &Layout) const;

  uint64_t getPaddingSize(const MCSection *SD, const MCAsmLayout &Layout) const;

  bool doesSymbolRequireExternRelocation(const MCSymbol &S);

  /// @}

  /// \name Target Writer Proxy Accessors
  /// @{

  bool is64Bit() const { return TargetObjectWriter->is64Bit(); }
  bool isX86_64() const {
    uint32_t CPUType = TargetObjectWriter->getCPUType();
    return CPUType == MachO::CPU_TYPE_X86_64;
  }

  /// @}

  void writeHeader(MachO::HeaderFileType Type, unsigned NumLoadCommands,
                   unsigned LoadCommandsSize, bool SubsectionsViaSymbols);

  /// Write a segment load command.
  ///
  /// \param NumSections The number of sections in this segment.
  /// \param SectionDataSize The total size of the sections.
  void writeSegmentLoadCommand(StringRef Name, unsigned NumSections,
                               uint64_t VMAddr, uint64_t VMSize,
                               uint64_t SectionDataStartOffset,
                               uint64_t SectionDataSize, uint32_t MaxProt,
                               uint32_t InitProt);

  void writeSection(const MCAsmLayout &Layout, const MCSection &Sec,
                    uint64_t VMAddr, uint64_t FileOffset, unsigned Flags,
                    uint64_t RelocationsStart, unsigned NumRelocations);

  void writeSymtabLoadCommand(uint32_t SymbolOffset, uint32_t NumSymbols,
                              uint32_t StringTableOffset,
                              uint32_t StringTableSize);

  void writeDysymtabLoadCommand(
      uint32_t FirstLocalSymbol, uint32_t NumLocalSymbols,
      uint32_t FirstExternalSymbol, uint32_t NumExternalSymbols,
      uint32_t FirstUndefinedSymbol, uint32_t NumUndefinedSymbols,
      uint32_t IndirectSymbolOffset, uint32_t NumIndirectSymbols);

  void writeNlist(MachSymbolData &MSD, const MCAsmLayout &Layout);

  void writeLinkeditLoadCommand(uint32_t Type, uint32_t DataOffset,
                                uint32_t DataSize);

  void writeLinkerOptionsLoadCommand(const std::vector<std::string> &Options);

  // FIXME: We really need to improve the relocation validation. Basically, we
  // want to implement a separate computation which evaluates the relocation
  // entry as the linker would, and verifies that the resultant fixup value is
  // exactly what the encoder wanted. This will catch several classes of
  // problems:
  //
  //  - Relocation entry bugs, the two algorithms are unlikely to have the same
  //    exact bug.
  //
  //  - Relaxation issues, where we forget to relax something.
  //
  //  - Input errors, where something cannot be correctly encoded. 'as' allows
  //    these through in many cases.

  // Add a relocation to be output in the object file. At the time this is
  // called, the symbol indexes are not know, so if the relocation refers
  // to a symbol it should be passed as \p RelSymbol so that it can be updated
  // afterwards. If the relocation doesn't refer to a symbol, nullptr should be
  // used.
  void addRelocation(const MCSymbol *RelSymbol, const MCSection *Sec,
                     MachO::any_relocation_info &MRE) {
    RelAndSymbol P(RelSymbol, MRE);
    Relocations[Sec].push_back(P);
  }

  void recordScatteredRelocation(const MCAssembler &Asm,
                                 const MCAsmLayout &Layout,
                                 const MCFragment *Fragment,
                                 const MCFixup &Fixup, MCValue Target,
                                 unsigned Log2Size, uint64_t &FixedValue);

  void recordTLVPRelocation(const MCAssembler &Asm, const MCAsmLayout &Layout,
                            const MCFragment *Fragment, const MCFixup &Fixup,
                            MCValue Target, uint64_t &FixedValue);

  void recordRelocation(MCAssembler &Asm, const MCAsmLayout &Layout,
                        const MCFragment *Fragment, const MCFixup &Fixup,
                        MCValue Target, uint64_t &FixedValue) override;

  void bindIndirectSymbols(MCAssembler &Asm);

  /// Compute the symbol table data.
  void computeSymbolTable(MCAssembler &Asm,
                          std::vector<MachSymbolData> &LocalSymbolData,
                          std::vector<MachSymbolData> &ExternalSymbolData,
                          std::vector<MachSymbolData> &UndefinedSymbolData);

  void computeSectionAddresses(const MCAssembler &Asm,
                               const MCAsmLayout &Layout);

  void executePostLayoutBinding(MCAssembler &Asm,
                                const MCAsmLayout &Layout) override;

  bool isSymbolRefDifferenceFullyResolvedImpl(const MCAssembler &Asm,
                                              const MCSymbol &A,
                                              const MCSymbol &B,
                                              bool InSet) const override;

  bool isSymbolRefDifferenceFullyResolvedImpl(const MCAssembler &Asm,
                                              const MCSymbol &SymA,
                                              const MCFragment &FB, bool InSet,
                                              bool IsPCRel) const override;

  uint64_t writeObject(MCAssembler &Asm, const MCAsmLayout &Layout) override;
};

/// Construct a new Mach-O writer instance.
///
/// This routine takes ownership of the target writer subclass.
///
/// \param MOTW - The target specific Mach-O writer subclass.
/// \param OS - The stream to write to.
/// \returns The constructed object writer.
std::unique_ptr<MCObjectWriter>
createMachObjectWriter(std::unique_ptr<MCMachObjectTargetWriter> MOTW,
                       raw_pwrite_stream &OS, bool IsLittleEndian);

} // end namespace llvm

#endif // LLVM_MC_MCMACHOBJECTWRITER_H