The load commands follow the Mach header.
Everything else in the file is found through them. ncmds gives how many
there are and sizeofcmds their total size.
Common fields
| Offset | Size | Field | Meaning |
|---|---|---|---|
| 0 | 4 | cmd | The kind of command. |
| 4 | 4 | cmdsize | The size of this command in bytes, including anything after its fixed fields. A multiple of 4, or of 8 in 64-bit files. |
Because every command starts with its type and size, a loader can step over one it
does not understand. When the high bit is set (LC_REQ_DYLD,
0x80000000), the dynamic linker must understand the command, and refuses
the file if it does not.
Strings in a command are stored after its fixed fields. A field called an
lc_str holds the offset of the string from the start of the command.
The string ends in a zero byte, and any bytes after it to the end of the command
are zeros.
All commands
| Value | Constant | Layout | Meaning |
|---|---|---|---|
0x1 | LC_SEGMENT | segment_command | A 32-bit segment to map. |
0x2 | LC_SYMTAB | symtab_command | The symbol and string tables. |
0x3 | LC_SYMSEG | offset, size | GDB symbol data (obsolete). |
0x4 | LC_THREAD | thread_command | Registers of a thread; in core files. |
0x5 | LC_UNIXTHREAD | thread_command | Initial registers of the main thread, with a stack; older executables’ entry point. |
0x6 | LC_LOADFVMLIB | fvmlib_command | Load a fixed VM library (obsolete). |
0x7 | LC_IDFVMLIB | fvmlib_command | This fixed VM library’s identity (obsolete). |
0x8 | LC_IDENT | strings | Identification strings (obsolete). |
0x9 | LC_FVMFILE | name, header_addr | Internal use. |
0xA | LC_PREPAGE | — | Internal use. |
0xB | LC_DYSYMTAB | dysymtab_command | The structure of the symbol table for dynamic linking. |
0xC | LC_LOAD_DYLIB | dylib_command | A library this image needs. |
0xD | LC_ID_DYLIB | dylib_command | This dynamic library’s own name and versions. |
0xE | LC_LOAD_DYLINKER | dylinker_command | The dynamic linker to use, usually /usr/lib/dyld. |
0xF | LC_ID_DYLINKER | dylinker_command | This dynamic linker’s identity. |
0x10 | LC_PREBOUND_DYLIB | prebound_dylib_command | Modules prebound for a library (obsolete). |
0x11 | LC_ROUTINES | routines_command | A library’s initialisation routine. |
0x12 | LC_SUB_FRAMEWORK | name | This library is a sub-framework of an umbrella framework. |
0x13 | LC_SUB_UMBRELLA | name | A sub-umbrella framework. |
0x14 | LC_SUB_CLIENT | name | A client allowed to link against this sub-framework. |
0x15 | LC_SUB_LIBRARY | name | A sub-library. |
0x16 | LC_TWOLEVEL_HINTS | offset, nhints | Hints for the two-level namespace (see Symbols). |
0x17 | LC_PREBIND_CKSUM | cksum | A prebinding checksum (obsolete). |
0x80000018 | LC_LOAD_WEAK_DYLIB | dylib_command | A library that is allowed to be missing. |
0x19 | LC_SEGMENT_64 | segment_command_64 | A 64-bit segment to map. |
0x1A | LC_ROUTINES_64 | routines_command_64 | A library’s initialisation routine (64-bit). |
0x1B | LC_UUID | uuid (16 bytes) | A 128-bit number identifying this linked image; it links a binary to its debug symbols. |
0x8000001C | LC_RPATH | path | A directory added to the run path for @rpath libraries. |
0x1D | LC_CODE_SIGNATURE | linkedit_data_command | The code signature. |
0x1E | LC_SEGMENT_SPLIT_INFO | linkedit_data_command | Data for moving segments around. |
0x8000001F | LC_REEXPORT_DYLIB | dylib_command | Load a library and re-export its symbols. |
0x20 | LC_LAZY_LOAD_DYLIB | dylib_command | Delay loading a library until first use. |
0x21 | LC_ENCRYPTION_INFO | encryption_info_command | An encrypted range (32-bit). |
0x22 | LC_DYLD_INFO | dyld_info_command | Compressed dyld information. |
0x80000022 | LC_DYLD_INFO_ONLY | dyld_info_command | The same, and the file has no older form of it. |
0x80000023 | LC_LOAD_UPWARD_DYLIB | dylib_command | A library that also depends on this one. |
0x24 | LC_VERSION_MIN_MACOSX | version_min_command | Minimum macOS. |
0x25 | LC_VERSION_MIN_IPHONEOS | version_min_command | Minimum iOS. |
0x26 | LC_FUNCTION_STARTS | linkedit_data_command | Compressed table of function addresses. |
0x27 | LC_DYLD_ENVIRONMENT | dylinker_command | A string treated by dyld like an environment variable. |
0x80000028 | LC_MAIN | entry_point_command | The offset of main(); replaces LC_UNIXTHREAD. |
0x29 | LC_DATA_IN_CODE | linkedit_data_command | Data in code ranges. |
0x2A | LC_SOURCE_VERSION | source_version_command | The version of the sources it was built from. |
0x2B | LC_DYLIB_CODE_SIGN_DRS | linkedit_data_command | Designated requirements copied from linked libraries. |
0x2C | LC_ENCRYPTION_INFO_64 | encryption_info_command_64 | An encrypted range (64-bit). |
0x2D | LC_LINKER_OPTION | linker_option_command | Linker options, in object files. |
0x2E | LC_LINKER_OPTIMIZATION_HINT | linkedit_data_command | Optimisation hints, in object files. |
0x2F | LC_VERSION_MIN_TVOS | version_min_command | Minimum tvOS. |
0x30 | LC_VERSION_MIN_WATCHOS | version_min_command | Minimum watchOS. |
0x31 | LC_NOTE | note_command | Arbitrary data in the file, used in core files. |
0x32 | LC_BUILD_VERSION | build_version_command | Platform, minimum OS, SDK and tools. |
0x80000033 | LC_DYLD_EXPORTS_TRIE | linkedit_data_command | The export trie, without the rest of LC_DYLD_INFO. |
0x80000034 | LC_DYLD_CHAINED_FIXUPS | linkedit_data_command | Chained fixups. |
0x80000035 | LC_FILESET_ENTRY | fileset_entry_command | A Mach-O file inside a file set. |
0x36 | LC_ATOM_INFO | linkedit_data_command | Atom information. |
0x37 | LC_FUNCTION_VARIANTS | linkedit_data_command | Function variant tables. |
0x38 | LC_FUNCTION_VARIANT_FIXUPS | linkedit_data_command | Fixups for function variants. |
0x39 | LC_TARGET_TRIPLE | triple | The target triple it was compiled for, such as arm64e-apple-macosx15.0.0. |
0x3A | LC_LAZY_LOAD_DYLIB_INFO | linkedit_data_command | Data for lazy loaded libraries. |
symtab_command
| Offset | Size | Field | Meaning |
|---|---|---|---|
| 8 | 4 | symoff | File offset of the symbol table. |
| 12 | 4 | nsyms | Number of entries. |
| 16 | 4 | stroff | File offset of the string table. |
| 20 | 4 | strsize | Size of the string table. |
dylib_command
| Offset | Size | Field | Meaning |
|---|---|---|---|
| 8 | 4 | name.offset | Offset of the path from the start of the command. |
| 12 | 4 | timestamp | A build time stamp, usually a constant. |
| 16 | 4 | current_version | The library’s version, packed as xxxx.yy.zz in the top 16, middle and low 8 bits. |
| 20 | 4 | compatibility_version | The oldest version this is compatible with, in the same form. |
Since macOS 15 and iOS 18 a dylib_use_command can stand in for an
LC_LOAD_DYLIB or LC_LOAD_WEAK_DYLIB. It is recognised by name.offset
being 28 and the marker 0x1A741800 in the place of timestamp:
| Offset | Size | Field | Meaning |
|---|---|---|---|
| 8 | 4 | nameoff | 28. |
| 12 | 4 | marker | 0x1A741800. |
| 16 | 4 | current_version | The library’s version. |
| 20 | 4 | compat_version | Compatibility version. |
| 24 | 4 | flags | 1 weak link, 2 re-export, 4 upward, 8 delayed initialisation. |
dylinker_command
A single field at offset 8: name.offset, the offset of the path.
Commands holding one string
LC_SUB_FRAMEWORK, LC_SUB_UMBRELLA, LC_SUB_CLIENT, LC_SUB_LIBRARY, LC_RPATH and
LC_TARGET_TRIPLE have one lc_str field at offset 8.
fvmlib_command
name.offset at 8, minor_version at 12 and
header_addr at 16, each 4 bytes. These commands are obsolete.
prebound_dylib_command
name.offset at 8, nmodules at 12 and
linked_modules.offset at 16, the offset of a bit vector with one bit for
each module. Obsolete.
routines_command and routines_command_64
init_address and init_module come first, then six
reserved values. The fields are 4 bytes in the 32-bit form and 8 in the 64-bit form.
thread_command
After cmd and cmdsize come any number of register sets:
| Size | Field | Meaning |
|---|---|---|
| 4 | flavor | Which register set this is. |
| 4 | count | The size of the set, in 32-bit words. |
| count × 4 | state | The registers. |
| Processor | Flavour | Words | State |
|---|---|---|---|
| x86 | 1 (x86_THREAD_STATE32) | 16 | eax ebx ecx edx edi esi ebp esp ss eflags eip cs ds es fs gs |
| x86-64 | 4 (x86_THREAD_STATE64) | 42 | rax rbx rcx rdx rdi rsi rbp rsp r8–r15 rip rflags cs fs gs |
| ARM | 1 (ARM_THREAD_STATE) | 17 | r0–r12 sp lr pc cpsr |
| ARM64 | 6 (ARM_THREAD_STATE64) | 68 | x0–x28 fp lr sp pc, then cpsr (4 bytes) and padding |
The other flavours are in <mach/*/thread_status.h>. The explorer
shows these flavours’ registers by name and the entry point from the program
counter, and any other flavour as words.
linkedit_data_command
| Offset | Size | Field | Meaning |
|---|---|---|---|
| 8 | 4 | dataoff | File offset of the data in __LINKEDIT. |
| 12 | 4 | datasize | Size of the data. |
encryption_info_command
| Offset | Size | Field | Meaning |
|---|---|---|---|
| 8 | 4 | cryptoff | File offset of the encrypted range. |
| 12 | 4 | cryptsize | Size of the range. |
| 16 | 4 | cryptid | Which encryption system; 0 means not encrypted. |
| 20 | 4 | pad | 64-bit form only. |
version_min_command
version at 8 and sdk at 12, 4 bytes each, packed as
xxxx.yy.zz.
build_version_command
| Offset | Size | Field | Meaning |
|---|---|---|---|
| 8 | 4 | platform | 1 macOS, 2 iOS, 3 tvOS, 4 watchOS, 5 bridgeOS, 6 Mac Catalyst, 7 iOS Simulator, 8 tvOS Simulator, 9 watchOS Simulator, 10 DriverKit, 11 visionOS, 12 visionOS Simulator, 13 firmware, 14 sepOS, and 15 to 24 the ExclaveCore and ExclaveKit platforms. |
| 12 | 4 | minos | Minimum OS version, xxxx.yy.zz. |
| 16 | 4 | sdk | SDK version. |
| 20 | 4 | ntools | Number of tool entries. |
| 24 | 8 each | tools | tool (1 clang, 2 swift, 3 ld, 4 lld, 1024 metal, and a few more) and version, 4 bytes each. |
source_version_command
version at offset 8 is 8 bytes packed as A.B.C.D.E in 24, 10, 10, 10
and 10 bits.
entry_point_command
| Offset | Size | Field | Meaning |
|---|---|---|---|
| 8 | 8 | entryoff | The file offset of main(), from the start of __TEXT. |
| 16 | 8 | stacksize | The initial stack size, or 0 for the default. |
linker_option_command
count at offset 8, then that many strings packed one after the other,
padded with zeros to the end of the command.
note_command
| Offset | Size | Field | Meaning |
|---|---|---|---|
| 8 | 16 | data_owner | Who the note is for. |
| 24 | 8 | offset | File offset of the data. |
| 32 | 8 | size | Its size. |
fileset_entry_command
| Offset | Size | Field | Meaning |
|---|---|---|---|
| 8 | 8 | vmaddr | The address of the entry. |
| 16 | 8 | fileoff | The file offset of the entry’s Mach-O header. |
| 24 | 4 | entry_id.offset | Offset of the entry’s identifier. |
| 28 | 4 | reserved | Reserved. |