Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:44:14

0001 //===- llvm/MC/MCMachObjectWriter.h - Mach Object Writer --------*- C++ -*-===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 
0009 #ifndef LLVM_MC_MCMACHOBJECTWRITER_H
0010 #define LLVM_MC_MCMACHOBJECTWRITER_H
0011 
0012 #include "llvm/ADT/DenseMap.h"
0013 #include "llvm/ADT/StringRef.h"
0014 #include "llvm/BinaryFormat/MachO.h"
0015 #include "llvm/MC/MCDirectives.h"
0016 #include "llvm/MC/MCExpr.h"
0017 #include "llvm/MC/MCLinkerOptimizationHint.h"
0018 #include "llvm/MC/MCObjectWriter.h"
0019 #include "llvm/MC/MCSection.h"
0020 #include "llvm/MC/StringTableBuilder.h"
0021 #include "llvm/Support/EndianStream.h"
0022 #include "llvm/Support/VersionTuple.h"
0023 #include <cstdint>
0024 #include <memory>
0025 #include <string>
0026 #include <vector>
0027 
0028 namespace llvm {
0029 
0030 class MachObjectWriter;
0031 
0032 class MCMachObjectTargetWriter : public MCObjectTargetWriter {
0033   const unsigned Is64Bit : 1;
0034   const uint32_t CPUType;
0035 protected:
0036   uint32_t CPUSubtype;
0037 public:
0038   unsigned LocalDifference_RIT = 0;
0039 
0040 protected:
0041   MCMachObjectTargetWriter(bool Is64Bit_, uint32_t CPUType_,
0042                            uint32_t CPUSubtype_);
0043 
0044   void setLocalDifferenceRelocationType(unsigned Type) {
0045     LocalDifference_RIT = Type;
0046   }
0047 
0048 public:
0049   virtual ~MCMachObjectTargetWriter();
0050 
0051   Triple::ObjectFormatType getFormat() const override { return Triple::MachO; }
0052   static bool classof(const MCObjectTargetWriter *W) {
0053     return W->getFormat() == Triple::MachO;
0054   }
0055 
0056   /// \name Lifetime Management
0057   /// @{
0058 
0059   virtual void reset() {}
0060 
0061   /// @}
0062 
0063   /// \name Accessors
0064   /// @{
0065 
0066   bool is64Bit() const { return Is64Bit; }
0067   uint32_t getCPUType() const { return CPUType; }
0068   uint32_t getCPUSubtype() const { return CPUSubtype; }
0069   unsigned getLocalDifferenceRelocationType() const {
0070     return LocalDifference_RIT;
0071   }
0072 
0073   /// @}
0074 
0075   /// \name API
0076   /// @{
0077 
0078   virtual void recordRelocation(MachObjectWriter *Writer, MCAssembler &Asm,
0079                                 const MCFragment *Fragment,
0080                                 const MCFixup &Fixup, MCValue Target,
0081                                 uint64_t &FixedValue) = 0;
0082 
0083   /// @}
0084 };
0085 
0086 class MachObjectWriter final : public MCObjectWriter {
0087 public:
0088   struct DataRegionData {
0089     MachO::DataRegionType Kind;
0090     MCSymbol *Start;
0091     MCSymbol *End;
0092   };
0093 
0094   // A Major version of 0 indicates that no version information was supplied
0095   // and so the corresponding load command should not be emitted.
0096   using VersionInfoType = struct {
0097     bool EmitBuildVersion;
0098     union {
0099       MCVersionMinType Type;        ///< Used when EmitBuildVersion==false.
0100       MachO::PlatformType Platform; ///< Used when EmitBuildVersion==true.
0101     } TypeOrPlatform;
0102     unsigned Major;
0103     unsigned Minor;
0104     unsigned Update;
0105     /// An optional version of the SDK that was used to build the source.
0106     VersionTuple SDKVersion;
0107   };
0108 
0109 private:
0110   /// Helper struct for containing some precomputed information on symbols.
0111   struct MachSymbolData {
0112     const MCSymbol *Symbol;
0113     uint64_t StringIndex;
0114     uint8_t SectionIndex;
0115 
0116     // Support lexicographic sorting.
0117     bool operator<(const MachSymbolData &RHS) const;
0118   };
0119 
0120   struct IndirectSymbolData {
0121     MCSymbol *Symbol;
0122     MCSection *Section;
0123   };
0124 
0125   /// The target specific Mach-O writer instance.
0126   std::unique_ptr<MCMachObjectTargetWriter> TargetObjectWriter;
0127 
0128   /// \name Relocation Data
0129   /// @{
0130 
0131   struct RelAndSymbol {
0132     const MCSymbol *Sym;
0133     MachO::any_relocation_info MRE;
0134     RelAndSymbol(const MCSymbol *Sym, const MachO::any_relocation_info &MRE)
0135         : Sym(Sym), MRE(MRE) {}
0136   };
0137 
0138   DenseMap<const MCSection *, std::vector<RelAndSymbol>> Relocations;
0139   std::vector<IndirectSymbolData> IndirectSymbols;
0140   DenseMap<const MCSection *, unsigned> IndirectSymBase;
0141 
0142   std::vector<DataRegionData> DataRegions;
0143 
0144   SectionAddrMap SectionAddress;
0145 
0146   // List of sections in layout order. Virtual sections are after non-virtual
0147   // sections.
0148   SmallVector<MCSection *, 0> SectionOrder;
0149 
0150   /// @}
0151   /// \name Symbol Table Data
0152   /// @{
0153 
0154   StringTableBuilder StringTable;
0155   std::vector<MachSymbolData> LocalSymbolData;
0156   std::vector<MachSymbolData> ExternalSymbolData;
0157   std::vector<MachSymbolData> UndefinedSymbolData;
0158 
0159   /// @}
0160 
0161   // Used to communicate Linker Optimization Hint information.
0162   MCLOHContainer LOHContainer;
0163 
0164   VersionInfoType VersionInfo{};
0165   VersionInfoType TargetVariantVersionInfo{};
0166 
0167   // The list of linker options for LC_LINKER_OPTION.
0168   std::vector<std::vector<std::string>> LinkerOptions;
0169 
0170   MachSymbolData *findSymbolData(const MCSymbol &Sym);
0171 
0172   void writeWithPadding(StringRef Str, uint64_t Size);
0173 
0174 public:
0175   MachObjectWriter(std::unique_ptr<MCMachObjectTargetWriter> MOTW,
0176                    raw_pwrite_stream &OS, bool IsLittleEndian)
0177       : TargetObjectWriter(std::move(MOTW)),
0178         StringTable(TargetObjectWriter->is64Bit() ? StringTableBuilder::MachO64
0179                                                   : StringTableBuilder::MachO),
0180         W(OS,
0181           IsLittleEndian ? llvm::endianness::little : llvm::endianness::big) {}
0182 
0183   support::endian::Writer W;
0184 
0185   const MCSymbol &findAliasedSymbol(const MCSymbol &Sym) const;
0186 
0187   /// \name Lifetime management Methods
0188   /// @{
0189 
0190   void reset() override;
0191 
0192   /// @}
0193 
0194   /// \name Utility Methods
0195   /// @{
0196 
0197   bool isFixupKindPCRel(const MCAssembler &Asm, unsigned Kind);
0198 
0199   std::vector<IndirectSymbolData> &getIndirectSymbols() {
0200     return IndirectSymbols;
0201   }
0202   std::vector<DataRegionData> &getDataRegions() { return DataRegions; }
0203   const llvm::SmallVectorImpl<MCSection *> &getSectionOrder() const {
0204     return SectionOrder;
0205   }
0206   SectionAddrMap &getSectionAddressMap() { return SectionAddress; }
0207   MCLOHContainer &getLOHContainer() { return LOHContainer; }
0208 
0209   uint64_t getSectionAddress(const MCSection *Sec) const {
0210     return SectionAddress.lookup(Sec);
0211   }
0212   uint64_t getSymbolAddress(const MCSymbol &S, const MCAssembler &Asm) const;
0213 
0214   uint64_t getFragmentAddress(const MCAssembler &Asm,
0215                               const MCFragment *Fragment) const;
0216 
0217   uint64_t getPaddingSize(const MCAssembler &Asm, const MCSection *SD) const;
0218 
0219   const MCSymbol *getAtom(const MCSymbol &S) const;
0220 
0221   bool doesSymbolRequireExternRelocation(const MCSymbol &S);
0222 
0223   /// Mach-O deployment target version information.
0224   void setVersionMin(MCVersionMinType Type, unsigned Major, unsigned Minor,
0225                      unsigned Update,
0226                      VersionTuple SDKVersion = VersionTuple()) {
0227     VersionInfo.EmitBuildVersion = false;
0228     VersionInfo.TypeOrPlatform.Type = Type;
0229     VersionInfo.Major = Major;
0230     VersionInfo.Minor = Minor;
0231     VersionInfo.Update = Update;
0232     VersionInfo.SDKVersion = SDKVersion;
0233   }
0234   void setBuildVersion(MachO::PlatformType Platform, unsigned Major,
0235                        unsigned Minor, unsigned Update,
0236                        VersionTuple SDKVersion = VersionTuple()) {
0237     VersionInfo.EmitBuildVersion = true;
0238     VersionInfo.TypeOrPlatform.Platform = Platform;
0239     VersionInfo.Major = Major;
0240     VersionInfo.Minor = Minor;
0241     VersionInfo.Update = Update;
0242     VersionInfo.SDKVersion = SDKVersion;
0243   }
0244   void setTargetVariantBuildVersion(MachO::PlatformType Platform,
0245                                     unsigned Major, unsigned Minor,
0246                                     unsigned Update, VersionTuple SDKVersion) {
0247     TargetVariantVersionInfo.EmitBuildVersion = true;
0248     TargetVariantVersionInfo.TypeOrPlatform.Platform = Platform;
0249     TargetVariantVersionInfo.Major = Major;
0250     TargetVariantVersionInfo.Minor = Minor;
0251     TargetVariantVersionInfo.Update = Update;
0252     TargetVariantVersionInfo.SDKVersion = SDKVersion;
0253   }
0254 
0255   std::vector<std::vector<std::string>> &getLinkerOptions() {
0256     return LinkerOptions;
0257   }
0258 
0259   /// @}
0260 
0261   /// \name Target Writer Proxy Accessors
0262   /// @{
0263 
0264   bool is64Bit() const { return TargetObjectWriter->is64Bit(); }
0265   bool isX86_64() const {
0266     uint32_t CPUType = TargetObjectWriter->getCPUType();
0267     return CPUType == MachO::CPU_TYPE_X86_64;
0268   }
0269 
0270   /// @}
0271 
0272   void writeHeader(MachO::HeaderFileType Type, unsigned NumLoadCommands,
0273                    unsigned LoadCommandsSize, bool SubsectionsViaSymbols);
0274 
0275   /// Write a segment load command.
0276   ///
0277   /// \param NumSections The number of sections in this segment.
0278   /// \param SectionDataSize The total size of the sections.
0279   void writeSegmentLoadCommand(StringRef Name, unsigned NumSections,
0280                                uint64_t VMAddr, uint64_t VMSize,
0281                                uint64_t SectionDataStartOffset,
0282                                uint64_t SectionDataSize, uint32_t MaxProt,
0283                                uint32_t InitProt);
0284 
0285   void writeSection(const MCAssembler &Asm, const MCSection &Sec,
0286                     uint64_t VMAddr, uint64_t FileOffset, unsigned Flags,
0287                     uint64_t RelocationsStart, unsigned NumRelocations);
0288 
0289   void writeSymtabLoadCommand(uint32_t SymbolOffset, uint32_t NumSymbols,
0290                               uint32_t StringTableOffset,
0291                               uint32_t StringTableSize);
0292 
0293   void writeDysymtabLoadCommand(
0294       uint32_t FirstLocalSymbol, uint32_t NumLocalSymbols,
0295       uint32_t FirstExternalSymbol, uint32_t NumExternalSymbols,
0296       uint32_t FirstUndefinedSymbol, uint32_t NumUndefinedSymbols,
0297       uint32_t IndirectSymbolOffset, uint32_t NumIndirectSymbols);
0298 
0299   void writeNlist(MachSymbolData &MSD, const MCAssembler &Asm);
0300 
0301   void writeLinkeditLoadCommand(uint32_t Type, uint32_t DataOffset,
0302                                 uint32_t DataSize);
0303 
0304   void writeLinkerOptionsLoadCommand(const std::vector<std::string> &Options);
0305 
0306   // FIXME: We really need to improve the relocation validation. Basically, we
0307   // want to implement a separate computation which evaluates the relocation
0308   // entry as the linker would, and verifies that the resultant fixup value is
0309   // exactly what the encoder wanted. This will catch several classes of
0310   // problems:
0311   //
0312   //  - Relocation entry bugs, the two algorithms are unlikely to have the same
0313   //    exact bug.
0314   //
0315   //  - Relaxation issues, where we forget to relax something.
0316   //
0317   //  - Input errors, where something cannot be correctly encoded. 'as' allows
0318   //    these through in many cases.
0319 
0320   // Add a relocation to be output in the object file. At the time this is
0321   // called, the symbol indexes are not know, so if the relocation refers
0322   // to a symbol it should be passed as \p RelSymbol so that it can be updated
0323   // afterwards. If the relocation doesn't refer to a symbol, nullptr should be
0324   // used.
0325   void addRelocation(const MCSymbol *RelSymbol, const MCSection *Sec,
0326                      MachO::any_relocation_info &MRE) {
0327     RelAndSymbol P(RelSymbol, MRE);
0328     Relocations[Sec].push_back(P);
0329   }
0330 
0331   void recordRelocation(MCAssembler &Asm, const MCFragment *Fragment,
0332                         const MCFixup &Fixup, MCValue Target,
0333                         uint64_t &FixedValue) override;
0334 
0335   void bindIndirectSymbols(MCAssembler &Asm);
0336 
0337   /// Compute the symbol table data.
0338   void computeSymbolTable(MCAssembler &Asm,
0339                           std::vector<MachSymbolData> &LocalSymbolData,
0340                           std::vector<MachSymbolData> &ExternalSymbolData,
0341                           std::vector<MachSymbolData> &UndefinedSymbolData);
0342 
0343   void computeSectionAddresses(const MCAssembler &Asm);
0344 
0345   void executePostLayoutBinding(MCAssembler &Asm) override;
0346 
0347   bool isSymbolRefDifferenceFullyResolvedImpl(const MCAssembler &Asm,
0348                                               const MCSymbol &SymA,
0349                                               const MCFragment &FB, bool InSet,
0350                                               bool IsPCRel) const override;
0351 
0352   void populateAddrSigSection(MCAssembler &Asm);
0353 
0354   uint64_t writeObject(MCAssembler &Asm) override;
0355 };
0356 } // end namespace llvm
0357 
0358 #endif // LLVM_MC_MCMACHOBJECTWRITER_H