| //===- MachOObject.h - Mach-O object file model -----------------*- 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_LIB_OBJCOPY_MACHO_MACHOOBJECT_H |
| #define LLVM_LIB_OBJCOPY_MACHO_MACHOOBJECT_H |
| |
| #include "llvm/ADT/StringRef.h" |
| #include "llvm/BinaryFormat/MachO.h" |
| #include "llvm/MC/StringTableBuilder.h" |
| #include "llvm/ObjectYAML/DWARFYAML.h" |
| #include "llvm/Support/StringSaver.h" |
| #include "llvm/Support/YAMLTraits.h" |
| #include <cstdint> |
| #include <string> |
| #include <vector> |
| |
| namespace llvm { |
| namespace objcopy { |
| namespace macho { |
| |
| struct MachHeader { |
| uint32_t Magic; |
| uint32_t CPUType; |
| uint32_t CPUSubType; |
| uint32_t FileType; |
| uint32_t NCmds; |
| uint32_t SizeOfCmds; |
| uint32_t Flags; |
| uint32_t Reserved = 0; |
| }; |
| |
| struct RelocationInfo; |
| struct Section { |
| uint32_t Index; |
| std::string Segname; |
| std::string Sectname; |
| // CanonicalName is a string formatted as “<Segname>,<Sectname>". |
| std::string CanonicalName; |
| uint64_t Addr = 0; |
| uint64_t Size = 0; |
| // Offset in the input file. |
| std::optional<uint32_t> OriginalOffset; |
| uint32_t Offset = 0; |
| uint32_t Align = 0; |
| uint32_t RelOff = 0; |
| uint32_t NReloc = 0; |
| uint32_t Flags = 0; |
| uint32_t Reserved1 = 0; |
| uint32_t Reserved2 = 0; |
| uint32_t Reserved3 = 0; |
| StringRef Content; |
| std::vector<RelocationInfo> Relocations; |
| |
| Section(StringRef SegName, StringRef SectName); |
| |
| Section(StringRef SegName, StringRef SectName, StringRef Content); |
| |
| MachO::SectionType getType() const { |
| return static_cast<MachO::SectionType>(Flags & MachO::SECTION_TYPE); |
| } |
| |
| bool isVirtualSection() const { |
| return (getType() == MachO::S_ZEROFILL || |
| getType() == MachO::S_GB_ZEROFILL || |
| getType() == MachO::S_THREAD_LOCAL_ZEROFILL); |
| } |
| |
| bool hasValidOffset() const { |
| return !(isVirtualSection() || (OriginalOffset && *OriginalOffset == 0)); |
| } |
| }; |
| |
| struct LoadCommand { |
| // The type MachO::macho_load_command is defined in llvm/BinaryFormat/MachO.h |
| // and it is a union of all the structs corresponding to various load |
| // commands. |
| MachO::macho_load_command MachOLoadCommand; |
| |
| // The raw content of the payload of the load command (located right after the |
| // corresponding struct). In some cases it is either empty or can be |
| // copied-over without digging into its structure. |
| std::vector<uint8_t> Payload; |
| |
| // Some load commands can contain (inside the payload) an array of sections, |
| // though the contents of the sections are stored separately. The struct |
| // Section describes only sections' metadata and where to find the |
| // corresponding content inside the binary. |
| std::vector<std::unique_ptr<Section>> Sections; |
| |
| // Returns the segment name if the load command is a segment command. |
| std::optional<StringRef> getSegmentName() const; |
| |
| // Returns the segment vm address if the load command is a segment command. |
| std::optional<uint64_t> getSegmentVMAddr() const; |
| }; |
| |
| // A symbol information. Fields which starts with "n_" are same as them in the |
| // nlist. |
| struct SymbolEntry { |
| std::string Name; |
| bool Referenced = false; |
| uint32_t Index; |
| uint8_t n_type; |
| uint8_t n_sect; |
| uint16_t n_desc; |
| uint64_t n_value; |
| |
| bool isExternalSymbol() const { return n_type & MachO::N_EXT; } |
| |
| bool isLocalSymbol() const { return !isExternalSymbol(); } |
| |
| bool isUndefinedSymbol() const { |
| return (n_type & MachO::N_TYPE) == MachO::N_UNDF; |
| } |
| |
| bool isSwiftSymbol() const { |
| return StringRef(Name).startswith("_$s") || |
| StringRef(Name).startswith("_$S"); |
| } |
| |
| std::optional<uint32_t> section() const { |
| return n_sect == MachO::NO_SECT ? std::nullopt |
| : std::optional<uint32_t>(n_sect); |
| } |
| }; |
| |
| /// The location of the symbol table inside the binary is described by LC_SYMTAB |
| /// load command. |
| struct SymbolTable { |
| std::vector<std::unique_ptr<SymbolEntry>> Symbols; |
| |
| using iterator = pointee_iterator< |
| std::vector<std::unique_ptr<SymbolEntry>>::const_iterator>; |
| |
| iterator begin() const { return iterator(Symbols.begin()); } |
| iterator end() const { return iterator(Symbols.end()); } |
| |
| const SymbolEntry *getSymbolByIndex(uint32_t Index) const; |
| SymbolEntry *getSymbolByIndex(uint32_t Index); |
| void removeSymbols( |
| function_ref<bool(const std::unique_ptr<SymbolEntry> &)> ToRemove); |
| }; |
| |
| struct IndirectSymbolEntry { |
| // The original value in an indirect symbol table. Higher bits encode extra |
| // information (INDIRECT_SYMBOL_LOCAL and INDIRECT_SYMBOL_ABS). |
| uint32_t OriginalIndex; |
| /// The Symbol referenced by this entry. It's std::nullopt if the index is |
| /// INDIRECT_SYMBOL_LOCAL or INDIRECT_SYMBOL_ABS. |
| std::optional<SymbolEntry *> Symbol; |
| |
| IndirectSymbolEntry(uint32_t OriginalIndex, |
| std::optional<SymbolEntry *> Symbol) |
| : OriginalIndex(OriginalIndex), Symbol(Symbol) {} |
| }; |
| |
| struct IndirectSymbolTable { |
| std::vector<IndirectSymbolEntry> Symbols; |
| }; |
| |
| /// The location of the string table inside the binary is described by LC_SYMTAB |
| /// load command. |
| struct StringTable { |
| std::vector<std::string> Strings; |
| }; |
| |
| struct RelocationInfo { |
| // The referenced symbol entry. Set if !Scattered && Extern. |
| std::optional<const SymbolEntry *> Symbol; |
| // The referenced section. Set if !Scattered && !Extern. |
| std::optional<const Section *> Sec; |
| // True if Info is a scattered_relocation_info. |
| bool Scattered; |
| // True if the type is an ADDEND. r_symbolnum holds the addend instead of a |
| // symbol index. |
| bool IsAddend; |
| // True if the r_symbolnum points to a section number (i.e. r_extern=0). |
| bool Extern; |
| MachO::any_relocation_info Info; |
| |
| unsigned getPlainRelocationSymbolNum(bool IsLittleEndian) { |
| if (IsLittleEndian) |
| return Info.r_word1 & 0xffffff; |
| return Info.r_word1 >> 8; |
| } |
| |
| void setPlainRelocationSymbolNum(unsigned SymbolNum, bool IsLittleEndian) { |
| assert(SymbolNum < (1 << 24) && "SymbolNum out of range"); |
| if (IsLittleEndian) |
| Info.r_word1 = (Info.r_word1 & ~0x00ffffff) | SymbolNum; |
| else |
| Info.r_word1 = (Info.r_word1 & ~0xffffff00) | (SymbolNum << 8); |
| } |
| }; |
| |
| /// The location of the rebase info inside the binary is described by |
| /// LC_DYLD_INFO load command. Dyld rebases an image whenever dyld loads it at |
| /// an address different from its preferred address. The rebase information is |
| /// a stream of byte sized opcodes whose symbolic names start with |
| /// REBASE_OPCODE_. Conceptually the rebase information is a table of tuples: |
| /// <seg-index, seg-offset, type> |
| /// The opcodes are a compressed way to encode the table by only |
| /// encoding when a column changes. In addition simple patterns |
| /// like "every n'th offset for m times" can be encoded in a few |
| /// bytes. |
| struct RebaseInfo { |
| // At the moment we do not parse this info (and it is simply copied over), |
| // but the proper support will be added later. |
| ArrayRef<uint8_t> Opcodes; |
| }; |
| |
| /// The location of the bind info inside the binary is described by |
| /// LC_DYLD_INFO load command. Dyld binds an image during the loading process, |
| /// if the image requires any pointers to be initialized to symbols in other |
| /// images. The bind information is a stream of byte sized opcodes whose |
| /// symbolic names start with BIND_OPCODE_. Conceptually the bind information is |
| /// a table of tuples: <seg-index, seg-offset, type, symbol-library-ordinal, |
| /// symbol-name, addend> The opcodes are a compressed way to encode the table by |
| /// only encoding when a column changes. In addition simple patterns like for |
| /// runs of pointers initialized to the same value can be encoded in a few |
| /// bytes. |
| struct BindInfo { |
| // At the moment we do not parse this info (and it is simply copied over), |
| // but the proper support will be added later. |
| ArrayRef<uint8_t> Opcodes; |
| }; |
| |
| /// The location of the weak bind info inside the binary is described by |
| /// LC_DYLD_INFO load command. Some C++ programs require dyld to unique symbols |
| /// so that all images in the process use the same copy of some code/data. This |
| /// step is done after binding. The content of the weak_bind info is an opcode |
| /// stream like the bind_info. But it is sorted alphabetically by symbol name. |
| /// This enable dyld to walk all images with weak binding information in order |
| /// and look for collisions. If there are no collisions, dyld does no updating. |
| /// That means that some fixups are also encoded in the bind_info. For |
| /// instance, all calls to "operator new" are first bound to libstdc++.dylib |
| /// using the information in bind_info. Then if some image overrides operator |
| /// new that is detected when the weak_bind information is processed and the |
| /// call to operator new is then rebound. |
| struct WeakBindInfo { |
| // At the moment we do not parse this info (and it is simply copied over), |
| // but the proper support will be added later. |
| ArrayRef<uint8_t> Opcodes; |
| }; |
| |
| /// The location of the lazy bind info inside the binary is described by |
| /// LC_DYLD_INFO load command. Some uses of external symbols do not need to be |
| /// bound immediately. Instead they can be lazily bound on first use. The |
| /// lazy_bind contains a stream of BIND opcodes to bind all lazy symbols. Normal |
| /// use is that dyld ignores the lazy_bind section when loading an image. |
| /// Instead the static linker arranged for the lazy pointer to initially point |
| /// to a helper function which pushes the offset into the lazy_bind area for the |
| /// symbol needing to be bound, then jumps to dyld which simply adds the offset |
| /// to lazy_bind_off to get the information on what to bind. |
| struct LazyBindInfo { |
| ArrayRef<uint8_t> Opcodes; |
| }; |
| |
| /// The location of the export info inside the binary is described by |
| /// LC_DYLD_INFO load command. The symbols exported by a dylib are encoded in a |
| /// trie. This is a compact representation that factors out common prefixes. It |
| /// also reduces LINKEDIT pages in RAM because it encodes all information (name, |
| /// address, flags) in one small, contiguous range. The export area is a stream |
| /// of nodes. The first node sequentially is the start node for the trie. Nodes |
| /// for a symbol start with a uleb128 that is the length of the exported symbol |
| /// information for the string so far. If there is no exported symbol, the node |
| /// starts with a zero byte. If there is exported info, it follows the length. |
| /// First is a uleb128 containing flags. Normally, it is followed by |
| /// a uleb128 encoded offset which is location of the content named |
| /// by the symbol from the mach_header for the image. If the flags |
| /// is EXPORT_SYMBOL_FLAGS_REEXPORT, then following the flags is |
| /// a uleb128 encoded library ordinal, then a zero terminated |
| /// UTF8 string. If the string is zero length, then the symbol |
| /// is re-export from the specified dylib with the same name. |
| /// If the flags is EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER, then following |
| /// the flags is two uleb128s: the stub offset and the resolver offset. |
| /// The stub is used by non-lazy pointers. The resolver is used |
| /// by lazy pointers and must be called to get the actual address to use. |
| /// After the optional exported symbol information is a byte of |
| /// how many edges (0-255) that this node has leaving it, |
| /// followed by each edge. |
| /// Each edge is a zero terminated UTF8 of the addition chars |
| /// in the symbol, followed by a uleb128 offset for the node that |
| /// edge points to. |
| struct ExportInfo { |
| ArrayRef<uint8_t> Trie; |
| }; |
| |
| struct LinkData { |
| ArrayRef<uint8_t> Data; |
| }; |
| |
| struct Object { |
| MachHeader Header; |
| std::vector<LoadCommand> LoadCommands; |
| |
| SymbolTable SymTable; |
| StringTable StrTable; |
| |
| RebaseInfo Rebases; |
| BindInfo Binds; |
| WeakBindInfo WeakBinds; |
| LazyBindInfo LazyBinds; |
| ExportInfo Exports; |
| IndirectSymbolTable IndirectSymTable; |
| LinkData DataInCode; |
| LinkData LinkerOptimizationHint; |
| LinkData FunctionStarts; |
| LinkData ExportsTrie; |
| LinkData ChainedFixups; |
| LinkData DylibCodeSignDRs; |
| |
| std::optional<uint32_t> SwiftVersion; |
| |
| /// The index of LC_CODE_SIGNATURE load command if present. |
| std::optional<size_t> CodeSignatureCommandIndex; |
| /// The index of LC_DYLIB_CODE_SIGN_DRS load command if present. |
| std::optional<size_t> DylibCodeSignDRsIndex; |
| /// The index of LC_SYMTAB load command if present. |
| std::optional<size_t> SymTabCommandIndex; |
| /// The index of LC_DYLD_INFO or LC_DYLD_INFO_ONLY load command if present. |
| std::optional<size_t> DyLdInfoCommandIndex; |
| /// The index LC_DYSYMTAB load command if present. |
| std::optional<size_t> DySymTabCommandIndex; |
| /// The index LC_DATA_IN_CODE load command if present. |
| std::optional<size_t> DataInCodeCommandIndex; |
| /// The index of LC_LINKER_OPTIMIZATIN_HINT load command if present. |
| std::optional<size_t> LinkerOptimizationHintCommandIndex; |
| /// The index LC_FUNCTION_STARTS load command if present. |
| std::optional<size_t> FunctionStartsCommandIndex; |
| /// The index LC_DYLD_CHAINED_FIXUPS load command if present. |
| std::optional<size_t> ChainedFixupsCommandIndex; |
| /// The index LC_DYLD_EXPORTS_TRIE load command if present. |
| std::optional<size_t> ExportsTrieCommandIndex; |
| /// The index of the LC_SEGMENT or LC_SEGMENT_64 load command |
| /// corresponding to the __TEXT segment. |
| std::optional<size_t> TextSegmentCommandIndex; |
| |
| BumpPtrAllocator Alloc; |
| StringSaver NewSectionsContents; |
| |
| Object() : NewSectionsContents(Alloc) {} |
| |
| Error |
| removeSections(function_ref<bool(const std::unique_ptr<Section> &)> ToRemove); |
| |
| Error removeLoadCommands(function_ref<bool(const LoadCommand &)> ToRemove); |
| |
| void updateLoadCommandIndexes(); |
| |
| /// Creates a new segment load command in the object and returns a reference |
| /// to the newly created load command. The caller should verify that SegName |
| /// is not too long (SegName.size() should be less than or equal to 16). |
| LoadCommand &addSegment(StringRef SegName, uint64_t SegVMSize); |
| |
| bool is64Bit() const { |
| return Header.Magic == MachO::MH_MAGIC_64 || |
| Header.Magic == MachO::MH_CIGAM_64; |
| } |
| |
| uint64_t nextAvailableSegmentAddress() const; |
| }; |
| |
| } // end namespace macho |
| } // end namespace objcopy |
| } // end namespace llvm |
| |
| #endif // LLVM_LIB_OBJCOPY_MACHO_MACHOOBJECT_H |