brintos

brintos / llvm-project-archived public Read only

0
0
Text · 14.1 KiB · 86c6b12 Raw
375 lines · c
1//===- MachOObject.h - Mach-O object file model -----------------*- 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-exception6//7//===----------------------------------------------------------------------===//8 9#ifndef LLVM_LIB_OBJCOPY_MACHO_MACHOOBJECT_H10#define LLVM_LIB_OBJCOPY_MACHO_MACHOOBJECT_H11 12#include "llvm/ADT/StringRef.h"13#include "llvm/BinaryFormat/MachO.h"14#include "llvm/MC/StringTableBuilder.h"15#include "llvm/ObjectYAML/DWARFYAML.h"16#include "llvm/Support/StringSaver.h"17#include "llvm/Support/YAMLTraits.h"18#include <cstdint>19#include <string>20#include <vector>21 22namespace llvm {23namespace objcopy {24namespace macho {25 26struct MachHeader {27  uint32_t Magic;28  uint32_t CPUType;29  uint32_t CPUSubType;30  uint32_t FileType;31  uint32_t NCmds;32  uint32_t SizeOfCmds;33  uint32_t Flags;34  uint32_t Reserved = 0;35};36 37struct RelocationInfo;38struct Section {39  uint32_t Index;40  std::string Segname;41  std::string Sectname;42  // CanonicalName is a string formatted as “<Segname>,<Sectname>".43  std::string CanonicalName;44  uint64_t Addr = 0;45  uint64_t Size = 0;46  // Offset in the input file.47  std::optional<uint32_t> OriginalOffset;48  uint32_t Offset = 0;49  uint32_t Align = 0;50  uint32_t RelOff = 0;51  uint32_t NReloc = 0;52  uint32_t Flags = 0;53  uint32_t Reserved1 = 0;54  uint32_t Reserved2 = 0;55  uint32_t Reserved3 = 0;56  StringRef Content;57  std::vector<RelocationInfo> Relocations;58 59  Section(StringRef SegName, StringRef SectName);60 61  Section(StringRef SegName, StringRef SectName, StringRef Content);62 63  MachO::SectionType getType() const {64    return static_cast<MachO::SectionType>(Flags & MachO::SECTION_TYPE);65  }66 67  bool isBssSection() const {68    return (getType() == MachO::S_ZEROFILL ||69            getType() == MachO::S_GB_ZEROFILL ||70            getType() == MachO::S_THREAD_LOCAL_ZEROFILL);71  }72 73  bool hasValidOffset() const {74    return !(isBssSection() || OriginalOffset == 0);75  }76};77 78struct LoadCommand {79  // The type MachO::macho_load_command is defined in llvm/BinaryFormat/MachO.h80  // and it is a union of all the structs corresponding to various load81  // commands.82  MachO::macho_load_command MachOLoadCommand;83 84  // The raw content of the payload of the load command (located right after the85  // corresponding struct). In some cases it is either empty or can be86  // copied-over without digging into its structure.87  std::vector<uint8_t> Payload;88 89  // Some load commands can contain (inside the payload) an array of sections,90  // though the contents of the sections are stored separately. The struct91  // Section describes only sections' metadata and where to find the92  // corresponding content inside the binary.93  std::vector<std::unique_ptr<Section>> Sections;94 95  // Returns the segment name if the load command is a segment command.96  std::optional<StringRef> getSegmentName() const;97 98  // Returns the segment vm address if the load command is a segment command.99  std::optional<uint64_t> getSegmentVMAddr() const;100};101 102// A symbol information. Fields which starts with "n_" are same as them in the103// nlist.104struct SymbolEntry {105  std::string Name;106  bool Referenced = false;107  uint32_t Index;108  uint8_t n_type;109  uint8_t n_sect;110  uint16_t n_desc;111  uint64_t n_value;112 113  bool isExternalSymbol() const { return n_type & MachO::N_EXT; }114 115  bool isLocalSymbol() const { return !isExternalSymbol(); }116 117  bool isUndefinedSymbol() const {118    return (n_type & MachO::N_TYPE) == MachO::N_UNDF;119  }120 121  bool isSwiftSymbol() const {122    return StringRef(Name).starts_with("_$s") ||123           StringRef(Name).starts_with("_$S");124  }125 126  std::optional<uint32_t> section() const {127    return n_sect == MachO::NO_SECT ? std::nullopt128                                    : std::optional<uint32_t>(n_sect);129  }130};131 132/// The location of the symbol table inside the binary is described by LC_SYMTAB133/// load command.134struct SymbolTable {135  std::vector<std::unique_ptr<SymbolEntry>> Symbols;136 137  using iterator = pointee_iterator<138      std::vector<std::unique_ptr<SymbolEntry>>::const_iterator>;139 140  iterator begin() const { return iterator(Symbols.begin()); }141  iterator end() const { return iterator(Symbols.end()); }142 143  const SymbolEntry *getSymbolByIndex(uint32_t Index) const;144  SymbolEntry *getSymbolByIndex(uint32_t Index);145  void updateSymbols(function_ref<void(SymbolEntry &)> Callable);146  void removeSymbols(147      function_ref<bool(const std::unique_ptr<SymbolEntry> &)> ToRemove);148};149 150struct IndirectSymbolEntry {151  // The original value in an indirect symbol table. Higher bits encode extra152  // information (INDIRECT_SYMBOL_LOCAL and INDIRECT_SYMBOL_ABS).153  uint32_t OriginalIndex;154  /// The Symbol referenced by this entry. It's std::nullopt if the index is155  /// INDIRECT_SYMBOL_LOCAL or INDIRECT_SYMBOL_ABS.156  std::optional<SymbolEntry *> Symbol;157 158  IndirectSymbolEntry(uint32_t OriginalIndex,159                      std::optional<SymbolEntry *> Symbol)160      : OriginalIndex(OriginalIndex), Symbol(Symbol) {}161};162 163struct IndirectSymbolTable {164  std::vector<IndirectSymbolEntry> Symbols;165};166 167/// The location of the string table inside the binary is described by LC_SYMTAB168/// load command.169struct StringTable {170  std::vector<std::string> Strings;171};172 173struct RelocationInfo {174  // The referenced symbol entry. Set if !Scattered && Extern.175  std::optional<const SymbolEntry *> Symbol;176  // The referenced section. Set if !Scattered && !Extern.177  std::optional<const Section *> Sec;178  // True if Info is a scattered_relocation_info.179  bool Scattered;180  // True if the type is an ADDEND. r_symbolnum holds the addend instead of a181  // symbol index.182  bool IsAddend;183  // True if the r_symbolnum points to a section number (i.e. r_extern=0).184  bool Extern;185  MachO::any_relocation_info Info;186 187  unsigned getPlainRelocationSymbolNum(bool IsLittleEndian) {188    if (IsLittleEndian)189      return Info.r_word1 & 0xffffff;190    return Info.r_word1 >> 8;191  }192 193  void setPlainRelocationSymbolNum(unsigned SymbolNum, bool IsLittleEndian) {194    assert(SymbolNum < (1 << 24) && "SymbolNum out of range");195    if (IsLittleEndian)196      Info.r_word1 = (Info.r_word1 & ~0x00ffffff) | SymbolNum;197    else198      Info.r_word1 = (Info.r_word1 & ~0xffffff00) | (SymbolNum << 8);199  }200};201 202/// The location of the rebase info inside the binary is described by203/// LC_DYLD_INFO load command. Dyld rebases an image whenever dyld loads it at204/// an address different from its preferred address.  The rebase information is205/// a stream of byte sized opcodes whose symbolic names start with206/// REBASE_OPCODE_. Conceptually the rebase information is a table of tuples:207///   <seg-index, seg-offset, type>208/// The opcodes are a compressed way to encode the table by only209/// encoding when a column changes.  In addition simple patterns210/// like "every n'th offset for m times" can be encoded in a few211/// bytes.212struct RebaseInfo {213  // At the moment we do not parse this info (and it is simply copied over),214  // but the proper support will be added later.215  ArrayRef<uint8_t> Opcodes;216};217 218/// The location of the bind info inside the binary is described by219/// LC_DYLD_INFO load command. Dyld binds an image during the loading process,220/// if the image requires any pointers to be initialized to symbols in other221/// images. The bind information is a stream of byte sized opcodes whose222/// symbolic names start with BIND_OPCODE_. Conceptually the bind information is223/// a table of tuples: <seg-index, seg-offset, type, symbol-library-ordinal,224/// symbol-name, addend> The opcodes are a compressed way to encode the table by225/// only encoding when a column changes.  In addition simple patterns like for226/// runs of pointers initialized to the same value can be encoded in a few227/// bytes.228struct BindInfo {229  // At the moment we do not parse this info (and it is simply copied over),230  // but the proper support will be added later.231  ArrayRef<uint8_t> Opcodes;232};233 234/// The location of the weak bind info inside the binary is described by235/// LC_DYLD_INFO load command. Some C++ programs require dyld to unique symbols236/// so that all images in the process use the same copy of some code/data. This237/// step is done after binding. The content of the weak_bind info is an opcode238/// stream like the bind_info.  But it is sorted alphabetically by symbol name.239/// This enable dyld to walk all images with weak binding information in order240/// and look for collisions.  If there are no collisions, dyld does no updating.241/// That means that some fixups are also encoded in the bind_info.  For242/// instance, all calls to "operator new" are first bound to libstdc++.dylib243/// using the information in bind_info.  Then if some image overrides operator244/// new that is detected when the weak_bind information is processed and the245/// call to operator new is then rebound.246struct WeakBindInfo {247  // At the moment we do not parse this info (and it is simply copied over),248  // but the proper support will be added later.249  ArrayRef<uint8_t> Opcodes;250};251 252/// The location of the lazy bind info inside the binary is described by253/// LC_DYLD_INFO load command. Some uses of external symbols do not need to be254/// bound immediately. Instead they can be lazily bound on first use.  The255/// lazy_bind contains a stream of BIND opcodes to bind all lazy symbols. Normal256/// use is that dyld ignores the lazy_bind section when loading an image.257/// Instead the static linker arranged for the lazy pointer to initially point258/// to a helper function which pushes the offset into the lazy_bind area for the259/// symbol needing to be bound, then jumps to dyld which simply adds the offset260/// to lazy_bind_off to get the information on what to bind.261struct LazyBindInfo {262  ArrayRef<uint8_t> Opcodes;263};264 265/// The location of the export info inside the binary is described by266/// LC_DYLD_INFO load command. The symbols exported by a dylib are encoded in a267/// trie.  This is a compact representation that factors out common prefixes. It268/// also reduces LINKEDIT pages in RAM because it encodes all information (name,269/// address, flags) in one small, contiguous range. The export area is a stream270/// of nodes.  The first node sequentially is the start node for the trie. Nodes271/// for a symbol start with a uleb128 that is the length of the exported symbol272/// information for the string so far. If there is no exported symbol, the node273/// starts with a zero byte. If there is exported info, it follows the length.274/// First is a uleb128 containing flags. Normally, it is followed by275/// a uleb128 encoded offset which is location of the content named276/// by the symbol from the mach_header for the image.  If the flags277/// is EXPORT_SYMBOL_FLAGS_REEXPORT, then following the flags is278/// a uleb128 encoded library ordinal, then a zero terminated279/// UTF8 string.  If the string is zero length, then the symbol280/// is re-export from the specified dylib with the same name.281/// If the flags is EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER, then following282/// the flags is two uleb128s: the stub offset and the resolver offset.283/// The stub is used by non-lazy pointers.  The resolver is used284/// by lazy pointers and must be called to get the actual address to use.285/// After the optional exported symbol information is a byte of286/// how many edges (0-255) that this node has leaving it,287/// followed by each edge.288/// Each edge is a zero terminated UTF8 of the addition chars289/// in the symbol, followed by a uleb128 offset for the node that290/// edge points to.291struct ExportInfo {292  ArrayRef<uint8_t> Trie;293};294 295struct LinkData {296  ArrayRef<uint8_t> Data;297};298 299struct Object {300  MachHeader Header;301  std::vector<LoadCommand> LoadCommands;302 303  SymbolTable SymTable;304  StringTable StrTable;305 306  RebaseInfo Rebases;307  BindInfo Binds;308  WeakBindInfo WeakBinds;309  LazyBindInfo LazyBinds;310  ExportInfo Exports;311  IndirectSymbolTable IndirectSymTable;312  LinkData DataInCode;313  LinkData LinkerOptimizationHint;314  LinkData FunctionStarts;315  LinkData ExportsTrie;316  LinkData ChainedFixups;317  LinkData DylibCodeSignDRs;318 319  std::optional<uint32_t> SwiftVersion;320 321  /// The index of LC_CODE_SIGNATURE load command if present.322  std::optional<size_t> CodeSignatureCommandIndex;323  /// The index of LC_DYLIB_CODE_SIGN_DRS load command if present.324  std::optional<size_t> DylibCodeSignDRsIndex;325  /// The index of LC_SYMTAB load command if present.326  std::optional<size_t> SymTabCommandIndex;327  /// The index of LC_DYLD_INFO or LC_DYLD_INFO_ONLY load command if present.328  std::optional<size_t> DyLdInfoCommandIndex;329  /// The index LC_DYSYMTAB load command if present.330  std::optional<size_t> DySymTabCommandIndex;331  /// The index LC_DATA_IN_CODE load command if present.332  std::optional<size_t> DataInCodeCommandIndex;333  /// The index of LC_LINKER_OPTIMIZATIN_HINT load command if present.334  std::optional<size_t> LinkerOptimizationHintCommandIndex;335  /// The index LC_FUNCTION_STARTS load command if present.336  std::optional<size_t> FunctionStartsCommandIndex;337  /// The index LC_DYLD_CHAINED_FIXUPS load command if present.338  std::optional<size_t> ChainedFixupsCommandIndex;339  /// The index LC_DYLD_EXPORTS_TRIE load command if present.340  std::optional<size_t> ExportsTrieCommandIndex;341  /// The index of the LC_SEGMENT or LC_SEGMENT_64 load command342  /// corresponding to the __TEXT segment.343  std::optional<size_t> TextSegmentCommandIndex;344 345  BumpPtrAllocator Alloc;346  StringSaver NewSectionsContents;347 348  Object() : NewSectionsContents(Alloc) {}349 350  Error351  removeSections(function_ref<bool(const std::unique_ptr<Section> &)> ToRemove);352 353  Error removeLoadCommands(function_ref<bool(const LoadCommand &)> ToRemove);354 355  void updateLoadCommandIndexes();356 357  /// Creates a new segment load command in the object and returns a reference358  /// to the newly created load command. The caller should verify that SegName359  /// is not too long (SegName.size() should be less than or equal to 16).360  LoadCommand &addSegment(StringRef SegName, uint64_t SegVMSize);361 362  bool is64Bit() const {363    return Header.Magic == MachO::MH_MAGIC_64 ||364           Header.Magic == MachO::MH_CIGAM_64;365  }366 367  uint64_t nextAvailableSegmentAddress() const;368};369 370} // end namespace macho371} // end namespace objcopy372} // end namespace llvm373 374#endif // LLVM_LIB_OBJCOPY_MACHO_MACHOOBJECT_H375