Path: blob/main/contrib/llvm-project/llvm/lib/ObjCopy/MachO/MachOObject.h
35294 views
//===- MachOObject.h - Mach-O object file model -----------------*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#ifndef LLVM_LIB_OBJCOPY_MACHO_MACHOOBJECT_H9#define LLVM_LIB_OBJCOPY_MACHO_MACHOOBJECT_H1011#include "llvm/ADT/StringRef.h"12#include "llvm/BinaryFormat/MachO.h"13#include "llvm/MC/StringTableBuilder.h"14#include "llvm/ObjectYAML/DWARFYAML.h"15#include "llvm/Support/StringSaver.h"16#include "llvm/Support/YAMLTraits.h"17#include <cstdint>18#include <string>19#include <vector>2021namespace llvm {22namespace objcopy {23namespace macho {2425struct MachHeader {26uint32_t Magic;27uint32_t CPUType;28uint32_t CPUSubType;29uint32_t FileType;30uint32_t NCmds;31uint32_t SizeOfCmds;32uint32_t Flags;33uint32_t Reserved = 0;34};3536struct RelocationInfo;37struct Section {38uint32_t Index;39std::string Segname;40std::string Sectname;41// CanonicalName is a string formatted as “<Segname>,<Sectname>".42std::string CanonicalName;43uint64_t Addr = 0;44uint64_t Size = 0;45// Offset in the input file.46std::optional<uint32_t> OriginalOffset;47uint32_t Offset = 0;48uint32_t Align = 0;49uint32_t RelOff = 0;50uint32_t NReloc = 0;51uint32_t Flags = 0;52uint32_t Reserved1 = 0;53uint32_t Reserved2 = 0;54uint32_t Reserved3 = 0;55StringRef Content;56std::vector<RelocationInfo> Relocations;5758Section(StringRef SegName, StringRef SectName);5960Section(StringRef SegName, StringRef SectName, StringRef Content);6162MachO::SectionType getType() const {63return static_cast<MachO::SectionType>(Flags & MachO::SECTION_TYPE);64}6566bool isVirtualSection() const {67return (getType() == MachO::S_ZEROFILL ||68getType() == MachO::S_GB_ZEROFILL ||69getType() == MachO::S_THREAD_LOCAL_ZEROFILL);70}7172bool hasValidOffset() const {73return !(isVirtualSection() || (OriginalOffset && *OriginalOffset == 0));74}75};7677struct LoadCommand {78// The type MachO::macho_load_command is defined in llvm/BinaryFormat/MachO.h79// and it is a union of all the structs corresponding to various load80// commands.81MachO::macho_load_command MachOLoadCommand;8283// The raw content of the payload of the load command (located right after the84// corresponding struct). In some cases it is either empty or can be85// copied-over without digging into its structure.86std::vector<uint8_t> Payload;8788// Some load commands can contain (inside the payload) an array of sections,89// though the contents of the sections are stored separately. The struct90// Section describes only sections' metadata and where to find the91// corresponding content inside the binary.92std::vector<std::unique_ptr<Section>> Sections;9394// Returns the segment name if the load command is a segment command.95std::optional<StringRef> getSegmentName() const;9697// Returns the segment vm address if the load command is a segment command.98std::optional<uint64_t> getSegmentVMAddr() const;99};100101// A symbol information. Fields which starts with "n_" are same as them in the102// nlist.103struct SymbolEntry {104std::string Name;105bool Referenced = false;106uint32_t Index;107uint8_t n_type;108uint8_t n_sect;109uint16_t n_desc;110uint64_t n_value;111112bool isExternalSymbol() const { return n_type & MachO::N_EXT; }113114bool isLocalSymbol() const { return !isExternalSymbol(); }115116bool isUndefinedSymbol() const {117return (n_type & MachO::N_TYPE) == MachO::N_UNDF;118}119120bool isSwiftSymbol() const {121return StringRef(Name).starts_with("_$s") ||122StringRef(Name).starts_with("_$S");123}124125std::optional<uint32_t> section() const {126return n_sect == MachO::NO_SECT ? std::nullopt127: std::optional<uint32_t>(n_sect);128}129};130131/// The location of the symbol table inside the binary is described by LC_SYMTAB132/// load command.133struct SymbolTable {134std::vector<std::unique_ptr<SymbolEntry>> Symbols;135136using iterator = pointee_iterator<137std::vector<std::unique_ptr<SymbolEntry>>::const_iterator>;138139iterator begin() const { return iterator(Symbols.begin()); }140iterator end() const { return iterator(Symbols.end()); }141142const SymbolEntry *getSymbolByIndex(uint32_t Index) const;143SymbolEntry *getSymbolByIndex(uint32_t Index);144void removeSymbols(145function_ref<bool(const std::unique_ptr<SymbolEntry> &)> ToRemove);146};147148struct IndirectSymbolEntry {149// The original value in an indirect symbol table. Higher bits encode extra150// information (INDIRECT_SYMBOL_LOCAL and INDIRECT_SYMBOL_ABS).151uint32_t OriginalIndex;152/// The Symbol referenced by this entry. It's std::nullopt if the index is153/// INDIRECT_SYMBOL_LOCAL or INDIRECT_SYMBOL_ABS.154std::optional<SymbolEntry *> Symbol;155156IndirectSymbolEntry(uint32_t OriginalIndex,157std::optional<SymbolEntry *> Symbol)158: OriginalIndex(OriginalIndex), Symbol(Symbol) {}159};160161struct IndirectSymbolTable {162std::vector<IndirectSymbolEntry> Symbols;163};164165/// The location of the string table inside the binary is described by LC_SYMTAB166/// load command.167struct StringTable {168std::vector<std::string> Strings;169};170171struct RelocationInfo {172// The referenced symbol entry. Set if !Scattered && Extern.173std::optional<const SymbolEntry *> Symbol;174// The referenced section. Set if !Scattered && !Extern.175std::optional<const Section *> Sec;176// True if Info is a scattered_relocation_info.177bool Scattered;178// True if the type is an ADDEND. r_symbolnum holds the addend instead of a179// symbol index.180bool IsAddend;181// True if the r_symbolnum points to a section number (i.e. r_extern=0).182bool Extern;183MachO::any_relocation_info Info;184185unsigned getPlainRelocationSymbolNum(bool IsLittleEndian) {186if (IsLittleEndian)187return Info.r_word1 & 0xffffff;188return Info.r_word1 >> 8;189}190191void setPlainRelocationSymbolNum(unsigned SymbolNum, bool IsLittleEndian) {192assert(SymbolNum < (1 << 24) && "SymbolNum out of range");193if (IsLittleEndian)194Info.r_word1 = (Info.r_word1 & ~0x00ffffff) | SymbolNum;195else196Info.r_word1 = (Info.r_word1 & ~0xffffff00) | (SymbolNum << 8);197}198};199200/// The location of the rebase info inside the binary is described by201/// LC_DYLD_INFO load command. Dyld rebases an image whenever dyld loads it at202/// an address different from its preferred address. The rebase information is203/// a stream of byte sized opcodes whose symbolic names start with204/// REBASE_OPCODE_. Conceptually the rebase information is a table of tuples:205/// <seg-index, seg-offset, type>206/// The opcodes are a compressed way to encode the table by only207/// encoding when a column changes. In addition simple patterns208/// like "every n'th offset for m times" can be encoded in a few209/// bytes.210struct RebaseInfo {211// At the moment we do not parse this info (and it is simply copied over),212// but the proper support will be added later.213ArrayRef<uint8_t> Opcodes;214};215216/// The location of the bind info inside the binary is described by217/// LC_DYLD_INFO load command. Dyld binds an image during the loading process,218/// if the image requires any pointers to be initialized to symbols in other219/// images. The bind information is a stream of byte sized opcodes whose220/// symbolic names start with BIND_OPCODE_. Conceptually the bind information is221/// a table of tuples: <seg-index, seg-offset, type, symbol-library-ordinal,222/// symbol-name, addend> The opcodes are a compressed way to encode the table by223/// only encoding when a column changes. In addition simple patterns like for224/// runs of pointers initialized to the same value can be encoded in a few225/// bytes.226struct BindInfo {227// At the moment we do not parse this info (and it is simply copied over),228// but the proper support will be added later.229ArrayRef<uint8_t> Opcodes;230};231232/// The location of the weak bind info inside the binary is described by233/// LC_DYLD_INFO load command. Some C++ programs require dyld to unique symbols234/// so that all images in the process use the same copy of some code/data. This235/// step is done after binding. The content of the weak_bind info is an opcode236/// stream like the bind_info. But it is sorted alphabetically by symbol name.237/// This enable dyld to walk all images with weak binding information in order238/// and look for collisions. If there are no collisions, dyld does no updating.239/// That means that some fixups are also encoded in the bind_info. For240/// instance, all calls to "operator new" are first bound to libstdc++.dylib241/// using the information in bind_info. Then if some image overrides operator242/// new that is detected when the weak_bind information is processed and the243/// call to operator new is then rebound.244struct WeakBindInfo {245// At the moment we do not parse this info (and it is simply copied over),246// but the proper support will be added later.247ArrayRef<uint8_t> Opcodes;248};249250/// The location of the lazy bind info inside the binary is described by251/// LC_DYLD_INFO load command. Some uses of external symbols do not need to be252/// bound immediately. Instead they can be lazily bound on first use. The253/// lazy_bind contains a stream of BIND opcodes to bind all lazy symbols. Normal254/// use is that dyld ignores the lazy_bind section when loading an image.255/// Instead the static linker arranged for the lazy pointer to initially point256/// to a helper function which pushes the offset into the lazy_bind area for the257/// symbol needing to be bound, then jumps to dyld which simply adds the offset258/// to lazy_bind_off to get the information on what to bind.259struct LazyBindInfo {260ArrayRef<uint8_t> Opcodes;261};262263/// The location of the export info inside the binary is described by264/// LC_DYLD_INFO load command. The symbols exported by a dylib are encoded in a265/// trie. This is a compact representation that factors out common prefixes. It266/// also reduces LINKEDIT pages in RAM because it encodes all information (name,267/// address, flags) in one small, contiguous range. The export area is a stream268/// of nodes. The first node sequentially is the start node for the trie. Nodes269/// for a symbol start with a uleb128 that is the length of the exported symbol270/// information for the string so far. If there is no exported symbol, the node271/// starts with a zero byte. If there is exported info, it follows the length.272/// First is a uleb128 containing flags. Normally, it is followed by273/// a uleb128 encoded offset which is location of the content named274/// by the symbol from the mach_header for the image. If the flags275/// is EXPORT_SYMBOL_FLAGS_REEXPORT, then following the flags is276/// a uleb128 encoded library ordinal, then a zero terminated277/// UTF8 string. If the string is zero length, then the symbol278/// is re-export from the specified dylib with the same name.279/// If the flags is EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER, then following280/// the flags is two uleb128s: the stub offset and the resolver offset.281/// The stub is used by non-lazy pointers. The resolver is used282/// by lazy pointers and must be called to get the actual address to use.283/// After the optional exported symbol information is a byte of284/// how many edges (0-255) that this node has leaving it,285/// followed by each edge.286/// Each edge is a zero terminated UTF8 of the addition chars287/// in the symbol, followed by a uleb128 offset for the node that288/// edge points to.289struct ExportInfo {290ArrayRef<uint8_t> Trie;291};292293struct LinkData {294ArrayRef<uint8_t> Data;295};296297struct Object {298MachHeader Header;299std::vector<LoadCommand> LoadCommands;300301SymbolTable SymTable;302StringTable StrTable;303304RebaseInfo Rebases;305BindInfo Binds;306WeakBindInfo WeakBinds;307LazyBindInfo LazyBinds;308ExportInfo Exports;309IndirectSymbolTable IndirectSymTable;310LinkData DataInCode;311LinkData LinkerOptimizationHint;312LinkData FunctionStarts;313LinkData ExportsTrie;314LinkData ChainedFixups;315LinkData DylibCodeSignDRs;316317std::optional<uint32_t> SwiftVersion;318319/// The index of LC_CODE_SIGNATURE load command if present.320std::optional<size_t> CodeSignatureCommandIndex;321/// The index of LC_DYLIB_CODE_SIGN_DRS load command if present.322std::optional<size_t> DylibCodeSignDRsIndex;323/// The index of LC_SYMTAB load command if present.324std::optional<size_t> SymTabCommandIndex;325/// The index of LC_DYLD_INFO or LC_DYLD_INFO_ONLY load command if present.326std::optional<size_t> DyLdInfoCommandIndex;327/// The index LC_DYSYMTAB load command if present.328std::optional<size_t> DySymTabCommandIndex;329/// The index LC_DATA_IN_CODE load command if present.330std::optional<size_t> DataInCodeCommandIndex;331/// The index of LC_LINKER_OPTIMIZATIN_HINT load command if present.332std::optional<size_t> LinkerOptimizationHintCommandIndex;333/// The index LC_FUNCTION_STARTS load command if present.334std::optional<size_t> FunctionStartsCommandIndex;335/// The index LC_DYLD_CHAINED_FIXUPS load command if present.336std::optional<size_t> ChainedFixupsCommandIndex;337/// The index LC_DYLD_EXPORTS_TRIE load command if present.338std::optional<size_t> ExportsTrieCommandIndex;339/// The index of the LC_SEGMENT or LC_SEGMENT_64 load command340/// corresponding to the __TEXT segment.341std::optional<size_t> TextSegmentCommandIndex;342343BumpPtrAllocator Alloc;344StringSaver NewSectionsContents;345346Object() : NewSectionsContents(Alloc) {}347348Error349removeSections(function_ref<bool(const std::unique_ptr<Section> &)> ToRemove);350351Error removeLoadCommands(function_ref<bool(const LoadCommand &)> ToRemove);352353void updateLoadCommandIndexes();354355/// Creates a new segment load command in the object and returns a reference356/// to the newly created load command. The caller should verify that SegName357/// is not too long (SegName.size() should be less than or equal to 16).358LoadCommand &addSegment(StringRef SegName, uint64_t SegVMSize);359360bool is64Bit() const {361return Header.Magic == MachO::MH_MAGIC_64 ||362Header.Magic == MachO::MH_CIGAM_64;363}364365uint64_t nextAvailableSegmentAddress() const;366};367368} // end namespace macho369} // end namespace objcopy370} // end namespace llvm371372#endif // LLVM_LIB_OBJCOPY_MACHO_MACHOOBJECT_H373374375