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