// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. #ifndef RUNTIME_PLATFORM_MACH_O_H_ #define RUNTIME_PLATFORM_MACH_O_H_ #include namespace dart { namespace mach_o { #pragma pack(push, 1) typedef int cpu_type_t; typedef int cpu_subtype_t; // Mask for architecture variant bits. static constexpr cpu_type_t CPU_ARCH_MASK = 0xff000000; // CPU with a 64-bit ABI. static constexpr cpu_type_t CPU_ARCH_ABI64 = 0x01000000; // Fallback for architectures without more specific constants (e.g., // architectures like RISCV that MacOS doesn't run on natively). static constexpr cpu_type_t CPU_TYPE_ANY = -1; static constexpr cpu_subtype_t CPU_SUBTYPE_ANY = -1; // x86-family CPUs. static constexpr cpu_type_t CPU_TYPE_X86 = 7; static constexpr cpu_type_t CPU_TYPE_I386 = CPU_TYPE_X86; static constexpr cpu_type_t CPU_TYPE_X86_64 = CPU_TYPE_X86 | CPU_ARCH_ABI64; // x86-family CPU subtypes. constexpr cpu_subtype_t CPU_SUBTYPE_INTEL(uint8_t f, cpu_subtype_t m) { return f + (m << 4); } static constexpr cpu_subtype_t CPU_SUBTYPE_I386_ALL = CPU_SUBTYPE_INTEL(3, 0); static constexpr cpu_subtype_t CPU_SUBTYPE_X86_ALL = CPU_SUBTYPE_I386_ALL; static constexpr cpu_subtype_t CPU_SUBTYPE_X86_64_ALL = CPU_SUBTYPE_I386_ALL; // ARM-family CPUs. static constexpr cpu_type_t CPU_TYPE_ARM = 12; static constexpr cpu_type_t CPU_TYPE_ARM64 = CPU_TYPE_ARM | CPU_ARCH_ABI64; // ARM-family CPU subtypes. static constexpr cpu_type_t CPU_SUBTYPE_ARM_ALL = 0; static constexpr cpu_type_t CPU_SUBTYPE_ARM64_ALL = CPU_SUBTYPE_ARM_ALL; typedef int vm_prot_t; static constexpr vm_prot_t VM_PROT_NONE = 0x00; static constexpr vm_prot_t VM_PROT_READ = 0x01; static constexpr vm_prot_t VM_PROT_WRITE = 0x02; static constexpr vm_prot_t VM_PROT_EXECUTE = 0x04; static constexpr vm_prot_t VM_PROT_DEFAULT = (VM_PROT_READ | VM_PROT_WRITE); static constexpr vm_prot_t VM_PROT_ALL = (VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE); struct mach_header { uint32_t magic; cpu_type_t cputype; cpu_subtype_t cpusubtype; uint32_t filetype; uint32_t ncmds; uint32_t sizeofcmds; uint32_t flags; }; static constexpr uint32_t MH_MAGIC = 0xfeedface; static constexpr uint32_t MH_CIGAM = 0xcefaedfe; struct mach_header_64 { uint32_t magic; cpu_type_t cputype; cpu_subtype_t cpusubtype; uint32_t filetype; uint32_t ncmds; uint32_t sizeofcmds; uint32_t flags; uint32_t reserved; }; static constexpr uint32_t MH_MAGIC_64 = 0xfeedfacf; static constexpr uint32_t MH_CIGAM_64 = 0xcffaedfe; // Filetypes for the Mach-O header. // A relocatable object file that has all sections in a single unnamed segment. static constexpr uint32_t MH_OBJECT = 0x1; // A dynamically bound shared library. static constexpr uint32_t MH_DYLIB = 0x6; // An object file that only contains debugging information. static constexpr uint32_t MH_DSYM = 0xa; // Flag values for the Mach-O header. // The object file has no undefined references. static constexpr uint32_t MH_NOUNDEFS = 0x1; // The object file is an appropriate input for the dynamic linker // and cannot be statically link edited again. static constexpr uint32_t MH_DYLDLINK = 0x4; // The object file does not re-export any of its input dynamic // libraries. static constexpr uint32_t MH_NO_REEXPORTED_DYLIBS = 0x100000; // The object file uses two-level namespace bindings. static constexpr uint32_t MH_TWOLEVEL = 0x80; struct load_command { // The tag that specifies the load command for the following // bytes. One of the LC_* constants below. uint32_t cmd; // The total size of the load command, including cmd and cmdsize. uint32_t cmdsize; }; // The description of the LC_* constants are followed by the name of // the specific C structure describing their contents in parentheses. // Flag stored in high bit for LC_* constants that denotes sections // the dynamic linker must understand to properly load the library. static constexpr uint32_t LC_REQ_DYLD = 0x80000000; // A portion of the file that is mapped into memory when the // object file is loaded. (segment_command) static constexpr uint32_t LC_SEGMENT = 0x1; // The static symbol table. (symtab_command) static constexpr uint32_t LC_SYMTAB = 0x2; // The dynamic symbol table. (dysymtab_command) static constexpr uint32_t LC_DYSYMTAB = 0xb; // A dynamic library that must be loaded to use this object file. // (dylib_command) static constexpr uint32_t LC_LOAD_DYLIB = 0xc; // The identifier for this dynamic library (for MH_DYLIB files). // (dylib_command) static constexpr uint32_t LC_ID_DYLIB = 0xd; // A 64-bit segment. (segment_command_64) static constexpr uint32_t LC_SEGMENT_64 = 0x19; // The UUID, used as a build identifier. (uuid_command) static constexpr uint32_t LC_UUID = 0x1b; static constexpr uint32_t LC_RPATH = (0x1c | LC_REQ_DYLD); // The code signature which protects the preceding portion of the object file. // Must be the last contents in the object file. (linkedit_data_command) static constexpr uint32_t LC_CODE_SIGNATURE = 0x1d; // Information about encrypted segments for 32-bit targets. Must also be present // for programs with no encrypted segments that are uploaded to the App Store // so it can be updated appropriately. static constexpr uint32_t LC_ENCRYPTION_INFO = 0x21; // Information about encrypted segments for 64-bit targets. Must also be present // for programs with no encrypted segments that are uploaded to the App Store // so it can be updated appropriately. static constexpr uint32_t LC_ENCRYPTION_INFO_64 = 0x2c; // An arbitrary piece of data not specified by the Mach-O format. (note_command) static constexpr uint32_t LC_NOTE = 0x31; // The target platform and minimum and target OS versions for this object file. // (build_version_command) static constexpr uint32_t LC_BUILD_VERSION = 0x32; struct segment_command { uint32_t cmd; // LC_SEGMENT uint32_t cmdsize; // The name of the segment. Must be unique within a given object file. char segname[16]; // The starting virtual address and the size of the segment in memory. uint32_t vmaddr; uint32_t vmsize; // The starting file offset and size of the segment in the object file. // The file size and memory size of the segment may be different, for // example, if the segment contains zerofill sections. uint32_t fileoff; uint32_t filesize; // The maximum memory protection possible for this segment. vm_prot_t maxprot; // The initial memory protection for this segment once loaded. vm_prot_t initprot; // The number of sections in the variable-length payload of this load command. uint32_t nsects; // uint32_t flags; // section[] }; // Contains the same fields as segment_command, but the starting memory // address and size and the file offset and size are 64-bit fields. struct segment_command_64 { uint32_t cmd; // LC_SEGMENT_64 uint32_t cmdsize; char segname[16]; uint64_t vmaddr; uint64_t vmsize; uint64_t fileoff; uint64_t filesize; vm_prot_t maxprot; vm_prot_t initprot; uint32_t nsects; uint32_t flags; // section_64[] }; struct section { char sectname[16]; char segname[16]; uint32_t addr; uint32_t size; uint32_t offset; uint32_t align; uint32_t reloff; uint32_t nreloc; uint32_t flags; uint32_t reserved1; uint32_t reserved2; }; struct section_64 { char sectname[16]; char segname[16]; uint64_t addr; uint64_t size; uint32_t offset; uint32_t align; uint32_t reloff; uint32_t nreloc; uint32_t flags; uint32_t reserved1; uint32_t reserved2; uint32_t reserved3; }; static constexpr uint32_t SECTION_TYPE = 0x000000ff; static constexpr uint32_t SECTION_ATTRIBUTES = 0xffffff00; // Creates section flags from the type and attributes. constexpr uint32_t SectionFlags(intptr_t type, intptr_t attributes) { // Note that the S_* attribute values below do not need shifting. return (attributes & SECTION_ATTRIBUTES) | (type & SECTION_TYPE); } // Section types. static constexpr uint32_t S_REGULAR = 0x0; static constexpr uint32_t S_ZEROFILL = 0x1; static constexpr uint32_t S_GB_ZEROFILL = 0xc; // Section attributes. Note that these values do not need shifting when // combining with a type and so the type bits are always 0. static constexpr uint32_t S_NO_ATTRIBUTES = 0; // The section only contains instructions. static constexpr uint32_t S_ATTR_PURE_INSTRUCTIONS = 0x80000000; // The section only contains information needed for debugging. // No symbols should refer to this section and it must have type S_REGULAR. static constexpr uint32_t S_ATTR_DEBUG = 0x02000000; // The section contains some instructions. Should be set if // S_ATTR_PURE_INSTRUCTIONS is also set. static constexpr uint32_t S_ATTR_SOME_INSTRUCTIONS = 0x00000400; // Special segment and section names used by Mach-O files. Only the // ones used in our Mach-O writer are listed. // Segment and section names for the text segment, which also contains // constant data and unwinding information. static constexpr char SEG_TEXT[] = "__TEXT"; static constexpr char SECT_TEXT[] = "__text"; static constexpr char SECT_CONST[] = "__const"; static constexpr char SECT_UNWIND_INFO[] = "__unwind_info"; static constexpr char SECT_EH_FRAME[] = "__eh_frame"; // Segment and section names for the data segment, which contains // non-constant data (like the BSS section). static constexpr char SEG_DATA[] = "__DATA"; static constexpr char SECT_BSS[] = "__bss"; // Segment and section names for the DWARF segment. static constexpr char SEG_DWARF[] = "__DWARF"; static constexpr char SECT_DEBUG_LINE[] = "__debug_line"; static constexpr char SECT_DEBUG_INFO[] = "__debug_info"; static constexpr char SECT_DEBUG_ABBREV[] = "__debug_abbrev"; // Segment name for the linkedit segment. Does not contain sections but rather // the non-header contents for other non-segment link commands like the symbol // table and code signature. static constexpr char SEG_LINKEDIT[] = "__LINKEDIT"; // Segment/section names used for relocatable object files. static constexpr char SEG_UNNAMED[] = ""; static constexpr char SEG_LD[] = "__LD"; static constexpr char SECT_COMPACT_UNWIND[] = "__compact_unwind"; struct symtab_command { uint32_t cmd; // LC_SYMTAB uint32_t cmdsize; uint32_t symoff; // The offset of the symbol table data in the object file. uint32_t nsyms; // The number of symbols in the symbol table data. uint32_t stroff; // The offset of the string table for the symbol table. uint32_t strsize; // The size of the string table in bytes. }; // The structure used for symbols in the symbol table. struct nlist { uint32_t n_idx; // The index of the symbol name in the string table. uint8_t n_type; // The type of the syble (see below). uint8_t n_sect; // For section symbols, the section that owns this symbol. uint16_t n_desc; // Interpreted based on the type of the symbol. // This is normally defined as a uword, but it must match the target // architecture's bitsize, not the host. #if defined(TARGET_ARCH_IS_32_BIT) uint32_t n_value; #else uint64_t n_value; #endif }; // The "section" for symbols not belonging to a specific section. static constexpr uint8_t NO_SECT = 0; // Masks for n_type. // If any bits in (n_type & N_STAB) are set, then the symbol is // a symbolic debugging symbol and so n_type is a specific constant. static constexpr uint8_t N_STAB = 0xe0; // Otherwise, n_type is a bitfield described by the following masks: // The private external symbol bit. static constexpr uint8_t N_PEXT = 0x10; // A mask for the actual type of the symbol. static constexpr uint8_t N_TYPE = 0xe; // The external symbol bit. static constexpr uint8_t N_EXT = 0x1; // Values for the N_TYPE bits when no bits in N_STAB are set. // An undefined symbol. (n_sect == NO_SECT) static constexpr uint8_t N_UNDEF = 0x0; // A symbol to an absolute offset in the Mach-O file. (n_sect == NO_SECT) static constexpr uint8_t N_ABS = 0x2; // A symbol defined in a specific section (load command index in n_sect). static constexpr uint8_t N_SECT = 0xe; // Values for the N_TYPE bits that set bits in N_STAB. // A global symbol. (n_sect == NO_SECT, value = 0). static constexpr uint8_t N_GSYM = 0x20; // A function defined in a specific section. static constexpr uint8_t N_FUN = 0x24; // A static (object) symbol defined in a specific section. static constexpr uint8_t N_STSYM = 0x26; // The start of a function symbol in a specific section. static constexpr uint8_t N_BNSYM = 0x2e; // The end of a function symbol in a specific section. static constexpr uint8_t N_ENSYM = 0x4e; // The name of the object file. (n_sect == 0, n_desc = 1, value = mtime) static constexpr uint8_t N_OSO = 0x66; // Values for n_desc. // Indicates an alternate symbol definition for a symbol value that // is already defined elsewhere. static constexpr uint16_t N_ALT_ENTRY = 0x0200; struct dysymtab_command { uint32_t cmd; // LC_DYSYMTAB uint32_t cmdsize; // The initial fields pairs are offsets into the symbol table information // in the linkedit segment. The first field is the symbol table index of // the first corresponding symbol (not file offset) and the second field // is the number of symbols starting at that index. // The local symbols in the symbol table. uint32_t ilocalsym; uint32_t nlocalsym; // The defined external symbols in the symbol table. uint32_t iextdefsym; uint32_t nextdefsym; // The undefined external symbols in the symbol table. uint32_t iundefsym; uint32_t nundefsym; // The remaining fields pairs are offsets into the linkedit segment. // The first field is the file offset and the second field is the number // of objects to read starting at that index. // // The Mach-O writer in the VM does not use these fields, so there's // no need for further documentation (they are populated with 0 values). uint32_t tocoff; uint32_t ntoc; uint32_t modtaboff; uint32_t nmodtab; uint32_t extrefsymoff; uint32_t nextrefsyms; uint32_t indirectsymoff; uint32_t nindirectsyms; uint32_t extreloff; uint32_t nextrel; uint32_t locreloff; uint32_t nlocrel; }; struct note_command { uint32_t cmd; // LC_NOTE uint32_t cmdsize; // An identifier used to determine the owner of this note (e.g., to // determine how to interpret the contents of the note.) char data_owner[16]; // The file offset of the note contents. uint64_t offset; // The size of the note contents in bytes. uint64_t size; }; struct uuid_command { uint32_t cmd; // LC_UUID uint32_t cmdsize; uint8_t uuid[16]; // The 128-bit UUID of this object file. }; struct build_version_command { uint32_t cmd; // LC_BUILD_VERSION uint32_t cmdsize; uint32_t platform; // See PLATFORM_* constants. // minos and sdk are X.Y.Z versions encoded as a bitfield: // From most to least significant: // X : 16 // Y : 8 // Z : 8 uint32_t minos; // Minimum OS version. uint32_t sdk; // Target OS version. // The number of build_tool_version structs in the variable-length // payload of this load command. For our purposes, always 0 and // so there is no definition of the build_tool_version struct here. uint32_t ntools; }; // Values for platform. static constexpr uint32_t PLATFORM_UNKNOWN = 0x0; static constexpr uint32_t PLATFORM_ANY = 0xffffffff; static constexpr uint32_t PLATFORM_MACOS = 0x1; static constexpr uint32_t PLATFORM_IOS = 0x2; union lc_str { // The offset of the string in the load command contents. uint32_t offset; // We don't include the in-memory pointer alternative here. }; struct dylib_info { lc_str name; // The timestamp the library was built and copied into user. uint32_t timestamp; // Version format is same as in build_version_command. uint32_t current_version; uint32_t compatibility_version; }; struct dylib_command { uint32_t cmd; // LC_LOAD_DYLIB and LC_ID_DYLIB among others uint32_t cmdsize; dylib_info dylib; }; struct linkedit_data_command { uint32_t cmd; // LC_CODE_SIGNATURE among others uint32_t cmdsize; // The file offset of the corresponding contents. (Note that this is // _not_ the offset into the linkedit segment.) uint32_t dataoff; // The size of the contents in bytes. uint32_t datasize; }; struct rpath_command { uint32_t cmd; // LC_RPATH uint32_t cmdsize; lc_str path; }; // Magic numbers for code signature blobs. static constexpr uint32_t CSMAGIC_CODEDIRECTORY = 0xfade0c02; static constexpr uint32_t CSMAGIC_EMBEDDED_SIGNATURE = 0xfade0cc0; // Types for code signature blobs. static constexpr uint32_t CSSLOT_CODEDIRECTORY = 0; // Code signature code directory flags. static constexpr uint32_t CS_ADHOC = 0x00000002; static constexpr uint32_t CS_LINKER_SIGNED = 0x00020000; // Code signature hash types. static constexpr uint8_t CS_HASHTYPE_SHA256 = 0x2; // Code signature version numbers. // The earliest version that can appear in a code signature. static constexpr uint32_t CS_SUPPORTSNONE = 0x20001; static constexpr uint32_t CS_SUPPORTSSCATTER = 0x20100; static constexpr uint32_t CS_SUPPORTSTEAMID = 0x20200; static constexpr uint32_t CS_SUPPORTSCODELIMIT64 = 0x20300; static constexpr uint32_t CS_SUPPORTSEXECSEG = 0x20400; struct cs_blob_index { uint32_t type; // e.g., CSSLOT_CODEDIRECTORY // the offset of the nested blob within the superblob uint32_t offset; }; struct cs_superblob { uint32_t magic; // CSMAGIC_EMBEDDED_SIGNATURE // The length of the superblob, which includes any nested blobs. uint32_t length; // The number of nested blobs in this blob. uint32_t count; // The blob indices for the nested blobs. cs_blob_index index[]; // The variable length payload also contains the contents of the nested blobs // after the blob indices. The blob indices are not aligned, and the data for // each nested blob is 8-byte aligned. }; struct cs_code_directory { uint32_t magic; // CSMAGIC_CODEDIRECTORY // The length of the code directory, including the identifier and hashes. uint32_t length; uint32_t version; // For us, CS_SUPPORTSEXECSEG above. uint32_t flags; // For us, CS_ADHOC | CS_LINKED_SIGNED. uint32_t hash_offset; // The file offset of the hashes. uint32_t ident_offset; // The file offset of the identifier. uint32_t num_special_slots; // Unused by us, so 0. // The number of hashes (one for each page up to the code limit, // including one for the final incomplete page if any). uint32_t num_code_slots; // The end of the file covered by this code directory (for us, the file // offset of the superblob). uint32_t code_limit; // The size of each hash in the special and code slots. uint8_t hash_size; // The type of each hash in the special and code slots. uint8_t hash_type; uint8_t platform; // Unused by us, so 0. uint8_t page_size; // log2(page size) uint32_t spare2; // always 0. uint32_t scatter_offset; // Unused by us, so 0. uint32_t teamid_offset; // Unused by us, so 0. uint32_t spare3; // always 0. uint64_t code_limit_64; // Code limit if larger than 32 bits. uint64_t exec_seg_base; // file offset of the executable segment uint64_t exec_seg_limit; // file size of the executable segment uint64_t exec_seg_flags; // For our purposes, always 0. // Technically there can be more with later code signature versions, // but the Mach-O writer doesn't output those in the ad-hoc linker // signed signature. // The variable length payload contains the identifier followed by // the hashes in the special and code slots. The identifier data is // 8-byte aligned (like blobs) and the hash data is 16-byte aligned. }; // Compact unwinding information constants for encodings. // Architecture-independent constants for encodings. // A shorthand for the zero-value encoding that denotes that the associated // memory space does not contain function instructions. static constexpr uint32_t UNWIND_INFO_ENCODING_NONE = 0; static constexpr uint32_t UNWIND_INFO_ENCODING_IS_NOT_FUNCTION_START = 0x80000000; static constexpr uint32_t UNWIND_INFO_ENCODING_HAS_LSDA = 0x40000000; static constexpr uint32_t UNWIND_INFO_ENCODING_PERSONALITY_MASK = 0x30000000; // Currently compact unwinding information is only generated for ARM64, so only // the constants used by the MachO writer are included below. // ARM64-specific constants for encodings. static constexpr uint32_t UNWIND_INFO_ENCODING_ARM64_MODE_MASK = 0x0F000000; // A standard ARM64 prologue where FP/LR are immediately pushed on the // stack and then SP is copied to FP. If there are any non-volatile // registers saved, they are saved in pairs right below the FP/LR pair // in register number order. // // In the MachO writer, this is the only non-zero encoding used and // no non-volatile register pairs are recorded as being saved, so // the appropriate constants for each pair and for other encodings are elided. static constexpr uint32_t UNWIND_INFO_ENCODING_ARM64_MODE_FRAME = 0x04000000; // Note that fields ending in section_offset are offsets into the unwind info // section as a whole, whereas fields ending in page_offset are offsets into // the specific second level page (e.g., the page header starts at offset 0). struct unwind_info_lsda_index { uint32_t function_offset; uint32_t lsda_offset; }; struct unwind_info_first_level_page_index { uint32_t function_offset; uint32_t second_level_page_section_offset; uint32_t lsda_index_section_offset; }; // Second level pages have two formats: a compressed and a "regular" format. // As the Mach-O writer only creates a single second level page with four // entries currently, it uses the regular format as it is simpler. static constexpr uint32_t UNWIND_INFO_REGULAR_SECOND_LEVEL_PAGE = 2; struct unwind_info_regular_second_level_page_entry { uint32_t function_offset; uint32_t encoding; }; struct unwind_info_regular_second_level_page_header { uint32_t kind; // UNWIND_INFO_REGULAR_SECOND_LEVEL_PAGE uint16_t entry_page_offset; uint16_t entry_count; }; static const size_t UNWIND_INFO_SECOND_LEVEL_PAGE_MAX_SIZE = 4 * KB; static constexpr uint32_t UNWIND_INFO_REGULAR_SECOND_LEVEL_PAGE_MAX_ENTRIES = (UNWIND_INFO_SECOND_LEVEL_PAGE_MAX_SIZE - sizeof(unwind_info_regular_second_level_page_header)) / sizeof(unwind_info_regular_second_level_page_entry); constexpr size_t UnwindInfoRegularSecondLevelPageSize(intptr_t entries) { return sizeof(unwind_info_regular_second_level_page_header) + sizeof(unwind_info_regular_second_level_page_entry) * entries; } static constexpr uint32_t UNWIND_INFO_VERSION = 1; struct unwind_info_header { uint32_t version; uint32_t common_encodings_section_offset; uint32_t common_encodings_count; uint32_t personalities_section_offset; uint32_t personalities_count; uint32_t first_level_page_indices_section_offset; uint32_t first_level_page_indices_count; // Note that the last first level page indices is a sentinel that contains // the end of the covered space as its function offset and the end // of the lsda array as its lsda_index_section_offset. // // sentinel_index = first_level_page_indices_count - 1 // // lsda_size = // first_level_pages[sentinel_index].lsda_index_section_offset - // first_level_pages[0].lsda_index_section_offset // // lsda_count = lsda_size / sizeof(unwind_info_lsda_index) // second_level_page_count = sentinel_index; // Variadic payload of unwind info section after unwind_info_header: // uint32_t common_encodings[common_encodings_count] // uint32_t personalities[personalities_count] // unwind_info_first_level_page_index // first_level_pages[first_level_page_indices_count] // unwind_info_lsda_index lsda[lsda_count] // ... regular and compressed second level pages ... }; // Relocation information in relocatable objects. The reloff field in // the section and section_64 structs gives the starting file offset for // the section's relocation information, and nreloc gives the number of // structs found starting from that offset. struct relocation_info { // The "address" of the relocation entry is the offset into the // corresponding section. int32_t address; // The metadata contains the following bit fields, from low to high: // 0-23: The index of the section or symbol on which this relation entry // is based. Note that, as with other parts of the Mach-O format, // section indices are 1-based, while symbol indices are 0-based. // 24: Whether or not this relocation is PC-relative. // 25-26: log2(n), where n is the size of the relocation entry in bytes. // 27: Whether or not this relocation is "external". An external // relocation is based on a symbol in the symbol table. If false, // then the relocation is based on a section instead. // 28-31: The type of the relocation entry, see the RELOC_TYPE_* // constants below. uint32_t metadata; }; // The number of low bits used to store the symbol or section index in // the relocation entry. static constexpr uint32_t RELOC_METADATA_INDEX_BITS = 24; // The size of the relocation in the section contents. static constexpr uint32_t RELOC_SIZE_BYTE = 0 << 25; static constexpr uint32_t RELOC_SIZE_2BYTES = 1 << 25; static constexpr uint32_t RELOC_SIZE_4BYTES = 2 << 25; static constexpr uint32_t RELOC_SIZE_8BYTES = 3 << 25; // This bit is set if the index in the payload is the index of a symbol // in the symbol table. It is unset if the index in the payload is the // (1-based) index of a section. static constexpr uint32_t RELOC_EXTERN = 1 << 27; // For our purposes, the MachOWriter only emits two types of relocation entries: // UNSIGNED and SUBTRACTOR. The numeric encoding of these types are // platform dependent, but the semantics are the same for both X64 and ARM64: // // Consider a relocation comprised of the following parts: // (Target + TOffset) - (Source + SOffset) // at the offset ROffset in section Section with virtual address // RAddress = Section.addr + ROffset // in the relocatable object. // // An UNSIGNED relocation entry specifies Target. It refers either to a section // or a symbol via the stored index. // // A SUBTRACTOR relocation entry specifies Source. It always refers to a symbol, // never a section. Additionally, SUBTRACTOR relocation entries are always found // immediately before the corresponding UNSIGNED relocation entries. // // The offsets are combined into a single addend, which is stored in the section // contents at the offset of the relocation. If the relocation entries are // symbol based, then // addend = TOffset - SOffset // and for section-based relocation entries (which have no Source/SOffset), // addend = RAddress + TOffset // That is, the virtual address of the relocation is included in the addend for // section-based relocation entries. // X64-specific constants for relocation types. // A relocation specifying a section or symbol that is the target // of the relocation. static constexpr uint32_t RELOC_TYPE_X64_UNSIGNED = 0 << 28; // A relocation specifying a symbol that is the source of the relocation. // Note that in the list of the relocations, the source comes immediately // _before_ the target (UNSIGNED) entry that it is subtracted from. static constexpr uint32_t RELOC_TYPE_X64_SUBTRACTOR = 5 << 28; // ARM64-specific constants for relocation types. // A relocation specifying a section or symbol that is the target // of the relocation. static constexpr uint32_t RELOC_TYPE_ARM64_UNSIGNED = 0 << 28; // A relocation specifying a symbol that is the source of the relocation. // Note that in the list of the relocations, the source comes immediately // _before_ the target (UNSIGNED) entry that it is subtracted from. static constexpr uint32_t RELOC_TYPE_ARM64_SUBTRACTOR = 1 << 28; struct encryption_info_command { uint32_t cmd; // LC_ENCRYPTION_INFO uint32_t cmdsize; uint32_t cryptoff; // file offset of the encrypted segment(s) uint32_t cryptsize; // file size of the encrypted segment(s) uint32_t cryptid; // encryption cypher used (0 == not encrypted) }; struct encryption_info_command_64 { uint32_t cmd; // LC_ENCRYPTION_INFO_64 uint32_t cmdsize; uint32_t cryptoff; // file offset of the encrypted segment(s) uint32_t cryptsize; // file size of the encrypted segment(s) uint32_t cryptid; // encryption cypher used (0 == not encrypted) uint32_t pad; // padding to a multiple of 64 bits }; #pragma pack(pop) } // namespace mach_o } // namespace dart #endif // RUNTIME_PLATFORM_MACH_O_H_