Mach-O
| Company type | File format |
|---|---|
| Industry | Computing / Software development |
| Products | Executables, object files, shared libraries, dynamically loaded modules, core dump files |
Mach-O (short for Mach object) represents a file format designed for executables, object files, shared libraries, dynamically loaded modules, and core dump files. It was created as a successor to the a.out format.
This format is utilized on platforms built around the Mach kernel, such as NeXTSTEP, macOS, and iOS, serving native executables, libraries, and object code.
Mach-O file structure
A Mach-O file is composed of a header, followed by a series of load commands, and one or more segments, each containing up to 255 sections. It employs the REL relocation scheme to handle symbol references. Symbol resolution uses a two-level namespace where symbols are encoded as 'object/symbol name' pairs and are searched sequentially by object first, then symbol.
The design—a sequence of variable-length load commands pointing to data blocks elsewhere in the file—was also implemented in the executable format for the Accent kernel. This Accent approach drew inspiration from a concept originating in Spice Lisp.
All multi-byte data values adhere to the byte order of the target system's architecture.
Mach-O header
| Offset | Size (bytes) | Description |
|---|---|---|
| 0 | 4 | Magic number |
| 4 | 4 | CPU type |
| 8 | 4 | CPU subtype |
| 12 | 4 | File type |
| 16 | 4 | Number of load commands |
| 20 | 4 | Total size of load commands |
| 24 | 4 | Flags |
| 28 | 4 | Reserved (only for 64-bit) |
Magic numbers vary depending on endianness and architecture: big-endian systems use (32-bit) and (64-bit), while little-endian systems use (32-bit) and (64-bit). The reserved field exists solely in 64-bit headers to accommodate future enhancements.
The CPU type field identifies the instruction set architecture, where the highest bit signals a 64-bit architecture. Notable CPU types include:
| Value | Architecture |
|---|---|
| 0x00000001 | VAX |
| 0x00000007 | x86 |
| 0x0000000C | ARM |
| 0x00000012 | PowerPC / MC98000 |
CPU subtypes specify particular processor variants, which is essential for ensuring compatibility and optimizing performance. For ARM processors:
| Value | Version Description |
|---|---|
| 0x00000000 | All ARM processors |
| 0x00000009 | Optimized for ARM-V7 or later versions |
| 0x0000000D | Optimized for ARM-V8 or newer |
For x86 processors:
| Value | Version Description |
|---|---|
| 0x00000003 | All x86 processors |
| 0x00000004 | Optimized for i486 or newer models |
| 0x0000000A | Optimized for Pentium-4 or later models |
The file type field indicates the Mach-O binary’s intended purpose:
| Value | Description |
|---|---|
| 0x00000001 | Relocatable object file |
| 0x00000002 | Demand-paged executable file |
| 0x00000006 | Dynamically linked shared library file |
Flags describe various properties and behaviors of the binary, including incremental linking, dynamic symbol binding, namespace usage, and security features. Multiple flags can be combined; some significant ones are:
| Flag | Meaning |
|---|---|
| 1<<0 | No undefined symbols allowed |
| 1<<3 | Undefined symbols resolved by dynamic linker at load time |
| 1<<7 | Utilizes two-level namespace bindings |
| 1<<21 | Main executable loaded at randomized memory address (ASLR) |
Together, these components define the Mach-O file’s organization, compatibility parameters, and execution behavior critical for software development and operating system integration.
Multi-architecture binaries
A multi-architecture binary merges several Mach-O files into one executable, allowing it to operate across diverse Apple processor architectures, including ARM64 and x86-64 CPUs.
The universal header, formatted in big-endian order, is structured as follows:
| Offset | Bytes | Description |
|---|---|---|
| 0 | 4 | Magic number |
| 4 | 4 | Count of contained binaries |
The magic number, represented as (big-endian), identifies the file as a multi-architecture binary. The count indicates how many Mach-O images are included.
Each binary is detailed by an entry with this layout:
| Offset | Bytes | Description |
|---|---|---|
| 0 | 4 | CPU type identifier |
| 4 | 4 | CPU subtype identifier |
| 8 | 4 | Offset within the file |
| 12 | 4 | Size of the binary |
| 16 | 4 | Section alignment (expressed as power of two) |
These entries specify the CPU type and subtype corresponding to each Mach-O image, along with the file offset and size of that image. The section alignment value (for example, a value of 14 corresponds to alignment on a 16,384-byte boundary) guarantees compatibility with tools that manipulate multi-architecture binaries while maintaining accurate placement of each image.
Load commands
Load commands follow immediately after the Mach-O header, which states both their quantity and total byte size to allow verification. Discrepancies in these values or premature reading can indicate file corruption.
Each load command contains:
| Offset | Bytes | Description |
|---|---|---|
| 0 | 4 | Type of command |
| 4 | 4 | Size of the command |
The command type determines the specific parameters it carries. Commands marked with the bit are essential for loading or executing the binary; this mechanism enables older loaders to bypass unsupported optional commands safely.
Segment load command
The load command type value designates either the 32-bit segment load command () or its 64-bit counterpart (). The difference between these commands arises from varying address sizes between architectures.
Virtual memory addresses are shifted by a base address to isolate application memory spaces. Each section within a segment has relocation offsets adjusted relative to this base address; relocations are unnecessary when loaded precisely at the base address.
| Offset (32-bit) | Bytes (32-bit) | Offset (64-bit) | Bytes (64-bit) | Description |
|---|---|---|---|---|
| 0 | 4 | 0 | 4 | <syntaxhighlight lang="text" class="" style="" inline="1">0x00000001</syntaxhighlight> (32-bit) / <syntaxhighlight lang="text" class="" style="" inline="1">0x00000019</syntaxhighlight> (64-bit) |
| 4 | 4 | 4 | 4 | Command size |
| 8 | 16 | 8 | 16 | Segment name |
| 24 | 4 | 24 | 8 | Virtual address |
| 28 | 4 | 32 | 8 | Address size |
| 32 | 4 | 40 | 8 | File offset |
| 36 | 4 | 48 | 8 | Size in bytes from file offset |
| 40 | 4 | 56 | 4 | Maximum VM protections |
| 44 | 4 | 60 | 4 | Initial VM protections |
| 48 | 4 | 64 | 4 | Number of sections |
| 52 | 4 | 68 | 4 | Flags |
Segment names are limited to a maximum of sixteen characters and padded with null bytes if shorter.
This segment load command defines the virtual address plus base, the data size to be written, file offset, and number of bytes to read from the file. If the specified address size exceeds available file data, remaining RAM bytes are zero-initialized.
The __PAGEZERO segment reserves virtual memory without corresponding file data or access permissions to catch NULL pointer dereferences. Its default size varies by architecture: typically 4KiB for 32-bit and up to 4GiB for 64-bit systems.
Initial CPU access rights derive from the initial virtual memory protections; these can be adjusted dynamically during execution within maximum protection constraints.
| Permission bit (binary) | Description |
|---|---|
| <syntaxhighlight lang="text" class="" style="" inline="1">0001</syntaxhighlight> (bitmask) | Read permission for CPU |
| <syntaxhighlight lang="text" class="" style="" inline="1">0010</syntaxhighlight> (bitmask) | Write permission for CPU |
| <syntaxhighlight lang="text" class="" style="" inline="1">0100</syntaxhighlight> (bitmask) | Execute permission for CPU |
Bits labeled "x" are reserved for future use.
Segment flags include:
| Flag32 in Binary | Meaning |
|---|---|
| <syntaxhighlight lang="text" class="" style="" inline="1">0001</syntaxhighlight> | High virtual memory space allocated; low space zero-filled (e.g., stacks) |
| <syntaxhighlight lang="text" class="" style="" inline="1">0010</syntaxhighlight> | Fixed virtual memory allocation for libraries to prevent overlaps |
| <syntaxhighlight lang="text" class="" style="" inline="1">0100</syntaxhighlight> | No relocations required in this segment; safe for replacement without relocation adjustments |
| <syntaxhighlight lang="text" class="" style="" inline="1">1000</syntaxhighlight> | Segment protected; first page unprotected if located at zero file offset |
| <syntaxhighlight lang="text" class="" style="" inline="1">10000</syntaxhighlight> | Read-only after any necessary relocations have been applied |
Bits marked "x" remain reserved.
Following flags is the count of sections contained; each section entry is formatted as:
| Offset (32-bit) | Bytes (32-bit) | Offset (64-bit) | Bytes (64-bit) | Description |
|---|---|---|---|---|
| 0 | 16 | 0 | 16 | Section name |
| 16 | 16 | 16 | 16 | Segment name (must correspond with segment command) |
| 32 | 4 | 32 | 8 | Section virtual address |
| 36 | =4 | 40 | =8 | Section size |
Reserved3 field (only in the 64-bit format) appears at offset seventy-six and occupies four bytes.
Sections define data locations within segments; their relocation entries adjust addresses if the base address differs from zero. Section sizes apply both in-memory and on-disk representations.
Section Flag/Type values encompass:
| Flag (binary) | Explanation |
|---|
- Sections containing executable machine instructions have their highest bit set. - Other flags indicate symbol coalescing behavior, stripping permissions, debug information presence, and relocation entry status. - The least significant eight bits specify section types such as non-lazy or lazy symbol pointers, stub functions, or zero-fill-on-demand sections.
Mach-O loaders keep track of symbol pointer and stub sections utilized by the indirect symbol table for method dispatch. Stub sizes are stored in reserved2 fields; symbol pointers use architecture-dependent address sizes. Sections are processed sequentially according to this table during loading.
Numbering of Segments and Sections
Within the compressed and uncompressed link edit data, segments and sections are distinguished by their respective segment and section numbers. A segment number of 3 corresponds to the fourth segment load command in the Mach-O file, as counting starts from zero. Section numbering begins at 1; notably, section zero in the symbol table represents undefined symbols, such as methods or data referenced externally from other binaries.
For instance, a segment containing 7 sections concludes at section number 8. The subsequent segment with 3 sections would then be assigned section numbers 9, 10, and 11 respectively. Consequently, section number 10 refers to the second section of the second segment.
Ensuring the correct sequence and file offset locations of segments and sections is vital for precise interpretation of the symbol table and linking details. File offsets allow for symbol readers to be constructed, link edit sections to be accessed, or method calls to be mapped without depending on RAM addresses or relocations—an essential aspect when developing disassemblers.
When implementing a Mach-O loader, it is important to output sections at their specified RAM addresses plus a base address to avoid conflicts between applications. While renaming segment and section identifiers does not affect linkability, maintaining the original order of segment commands is crucial.
Libraries Linked
Link libraries in Mach-O binaries operate similarly to those in other formats but do not include a load command defining the program’s entry point. There are three types of load commands utilized for loading linked libraries:
- Full file path to a dynamically linked shared library
- Dynamically linked shared libraries located relative to the application’s current directory
- Optional dynamically linked shared libraries that may be absent; symbols from these are weakly imported if not present
The structure of a link library load command comprises:
| Offset | Bytes | Description |
|---|---|---|
| 0 | 4 | Command type (values: 0x0000000C, 0x0000000D, or 0x00000018) |
| 4 | 4 | Size of command |
| 8 | 4 | String offset (fixed at 24) |
| 12 | 4 | Timestamp |
| 16 | 4 | Current version |
| 20 | 4 | Compatible version |
| 24 | Command size minus 24 | File path string |
The file path string begins at offset 24 and extends for the remaining bytes defined by command size minus 24. It terminates with a null character (), with any extra null bytes serving as padding.
Ordinal Numbers for Link Libraries
Link libraries are assigned ordinal numbers starting from 1 upwards; ordinal zero signifies that a symbol does not exist as an external reference in another Mach-O binary.
The link edit information uses these ordinal numbers to identify the corresponding library, assuming the order of link library commands remains consistent.
It is recommended to avoid using link library command type for performance considerations because if the specified library is missing, it triggers a search through all loaded link libraries.
__LINKEDIT Symbol Table
Both Mach-O executables and their linked libraries include a symbol table load command structured as follows:
| Offset | Bytes | Description |
|---|---|---|
| 0 | 4 | Command type (0x00000002) |
| 4 | 4 | Command size (fixed at 24) |
| 8 | 4 | File offset where symbols start (relative to Mach-O header) |
| 12 | 4 | Total number of symbols |
| 16 | 4 | File offset where string table begins (relative to Mach-O header) |
| 20 | 4 | Size of string table |
The symbol offset points to where symbol entries commence relative to the Mach-O header. The number of symbols indicates where the symbol table ends.
Each symbol's name is stored as an offset within the string table and concludes with a null byte. Symbol addresses use either 32-bit or 64-bit values depending on whether the file architecture is for a respective bitness.
Symbol entries are interpreted as follows:
| Offset (32-bit) | Bytes (32-bit) | Offset (64-bit) | Bytes (64-bit) | Description |
|---|---|---|---|---|
| 0 | 4 | 0 | 4 | Name offset within string table |
| 4 | 1 | 4 | 1 | Symbol type field |
| 5 | 1 | 5 | 1 | Section number (range: 0–255) |
| 6 | 2 | 6 | 2 | Additional data (library ordinal number) |
| 8 | 4 | 8 | 8 | Symbol address value |
The symbol type field contains multiple bit segments:
| Bit Pattern | Meaning |
|---|---|
| ???xxxxx | Local debugging symbols |
| xxxx???x | Symbol address classification |
| xxx?xxx? | Symbol visibility indicators |
Local debugging symbols facilitate software development but are unnecessary during runtime.
Symbol address classifications include:
| Bit Pattern | Meaning |
|---|---|
| xxxx000x | Undefined symbols |
| xxxx001x | Absolute symbols |
| xxxx101x | Indirect symbols |
| xxxx110x | Prebound undefined symbols |
| xxxx111x | Defined within specific section number |
Visibility flags denote:
| Bit Pattern | Meaning |
|---|---|
| xxx1xxx0 | Private symbol scope |
| xxx0xxx1 | External symbol scope |
External symbols possess defined addresses within linked libraries and can resolve undefined references in Mach-O executables. Private symbols are disregarded when resolving undefined references unless they reside in the same file.
Section numbers indicate where a symbol is located; zero implies undefined with no associated section or address.
The data info field specifies both the link library ordinal number and linker-related options:
| Bit Pattern | Description |
|---|---|
| ????????xxxxxxxx | Library ordinal number (values from 0 to 255) |
| xxxxxxxx????xxxx | Flags related to dynamic loader behavior |
| xxxxxxxxxxxx???? | Address type options for dynamic linking |
An ordinal value of zero denotes either an external or current-file symbol. Undefined symbols use this field to indicate their associated library ordinal and linker options.
Dynamic loader flags include:
xxxxxxxx0001xxxx | Required reference by dynamic loader| Bit Pattern | Description | ||
|---|---|---|---|
|
xxxxxxxx0010xxxx | Utilized at runtime by dynamic linker |
xxxxxxxx0100xxxx | Sets symbol address to zero if undefined during runtime |
xxxxxxxx1000xxxx | Ignores duplicate definitions detected by static or dynamic linker |
Multiple flags may be applied simultaneously.
Address type options define how method calls behave:
xxxxxxxxxxxx0000 | Non-lazy pointer call| Bit Pattern | Description | |||
|---|---|---|---|---|
|
xxxxxxxxxxxx0001 | Lazy pointer call |
xxxxxxxxxxxx0010 | Method call defined within this library or program |
xxxxxxxxxxxx0011 | Private method call defined within this library or program |
xxxxxxxxxxxx0100 | Private non-lazy pointer call |
xxxxxxxxxxxx0101 | Private lazy pointer call |
Only one address type flag applies per symbol. Lazy pointers initially point to dyld_stub_binder, which resolves the actual address upon first invocation and replaces the stub thereafter, enhancing performance efficiency.
Organization of the Symbol Table
Entries within the symbol table are categorized by type in a specific sequence: starting with local debug symbols, followed by private symbols, then external symbols, and concluding with undefined symbols that link to external Mach-O binaries.
Whenever a symbol table is present, the corresponding load command for symbol table information is included. This command details the counts and starting indices for local, private, external, and undefined symbols. Such organization enables the dynamic linker to efficiently locate undefined and external symbols without scanning the entire symbol list.
Maintaining the original order of symbols is crucial because symbols receive sequential numbering beginning at zero. The load command depends on these numbers to accurately associate undefined symbols with their respective stubs and pointers. Any change in this sequence could result in erroneous method invocations during runtime.
__LINKEDIT Symbol Table Details
This load command facilitates rapid identification of undefined and external symbols during linking by specifying their locations as referenced by the command .
| Offset | Size (Bytes) | Description |
|---|---|---|
| 0 | 4 | <syntaxhighlight lang="text" class="" style="" inline="1">0x0000000B</syntaxhighlight> (Command identifier) |
| 4 | 4 | Size of command (fixed at 80 bytes) |
| 8 | 4 | Starting index for local symbols |
| 12 | 4 | Count of local symbols |
| 16 | 4 | Starting index for external symbols |
| 20 | 4 | Count of external symbols |
| 24 | 4 | Starting index for undefined symbols |
| 28 | 4 | Count of undefined symbols |
| 32 | 4 | Offset to content table |
| 36 | 4 | Number of entries in content table |
| 40 | 4 | Offset to module table |
| 44 | 4 | Number of entries in module table |
| 48 | 4 | Offset to referenced symbol table |
| 52 | 4 | Number of entries in referenced symbol table |
| 56 | 4 | Offset to indirect symbol table |
| 60 | 4 | Number of entries in indirect symbol table |
| 64 | 4 | Offset to external relocation entries |
| 68 | 4 | Count of external relocation entries |
| 72 | 4 | Offset to local relocation entries |
| 76 | 4 | Count of local relocation entries |
To locate individual entries, symbol indices are multiplied by either 12 bytes (for 32-bit architectures) or 16 bytes (for 64-bit architectures), then added to the base offset of the symbol table. Local symbols begin at index zero and mainly support debugging processes.
Similar indexing and counting apply to external and undefined symbols to streamline their retrieval. When private symbols exist, a gap may appear between local and external symbol ranges.
Offsets with a value of zero indicate sections that are not utilized.
Indirect Symbol Table
During segment load commands, the Mach-O loader records sections containing symbol pointers and stubs. These sections are accessed in sequence by the indirect symbol table to resolve method invocations. The offset for the indirect symbol table points to an array of 32-bit values representing symbol indices, which correspond sequentially to addresses stored within pointer and stub sections.
The symbol stub section includes machine-level JUMP instructions that route calls to functions or methods located in other Mach-O binaries. The size of these instructions varies depending on processor architecture and is specified in the reserved2 field within the segment load command.
Pointer sections store address values sized at either 32 bits or 64 bits based on the binary's architecture. These pointers are directly utilized by machine code for method/function calls rather than containing executable instructions themselves.
Symbol index values with a particular bit set identify absolute methods—pointers referencing exact addresses—whereas those with another bit set denote local methods lacking explicit method names.
In designing disassemblers, associating symbol names with offsets in stub and pointer tables allows clear visualization of function or method calls without needing to cross-reference undefined symbols from other Mach-O files.
__LINKEDIT Compressed table
When a compressed link edit table command is present, the need for undefined or external symbols along with the indirect symbol table is eliminated. This enhancement improves loading efficiency by consolidating all binding data.
Nonetheless, the indirect symbol table might still be included to maintain compatibility with older operating system versions.
| Offset | Bytes | Description |
|---|---|---|
| 0 | 4 | <syntaxhighlight lang="text" class="" style="" inline="1">0x00000022</syntaxhighlight> (Command type) |
| 4 | 4 | Size of command (48 bytes) |
| 8 | 4 | Offset for rebase information |
| 12 | 4 | Size of rebase data |
| 16 | 4 | Offset for bind information |
| 20 | 4 | Size of bind data |
| 24 | 4 | Offset for weak bind data |
| 28 | 4 | Size of weak bind data |
| 32 | 4 | Offset for lazy bind data |
| 36 | 4 | Size of lazy bind data |
| 40 | 4 | Offset for export information |
| 44 | 4 | Size of export data |
File offsets that are unused are set to zero.
Binding information
The bind, weak bind, and lazy bind sections share a single opcode format to resolve symbols.
Weak binding permits fallback to symbols from previously loaded Mach-O files if the specified library ordinal does not provide them. Lazy binding initially routes calls through a dyld_stub_binder that resolves the symbol dynamically at runtime, then patches the call site for direct future access. Plain binding mandates the symbol’s presence in the specified library ordinal.
Library ordinals are encoded as byte values: for ordinals between 0 and 15, or as – followed by a LEB128-encoded number for larger ordinals (for example, ordinal 132 is encoded as ).
Symbol names are introduced with byte values , where flag bits indicate whether an import is weak (flag 8) or non-weak (flag 1). For instance, specifies a weakly imported symbol named "Example."
Location-setting opcodes select segments and add LEB128 offsets to establish the current binding address.
Binding opcodes associate the current location with symbols and advance addresses by the pointer size (4 bytes on 32-bit platforms, 8 bytes on 64-bit).
An example sequence sets the library ordinal, specifies segment location plus offset, and binds symbols "Example" and "Example2," writing their addresses consecutively.
This compact format removes redundant fields from symbol tables and makes the indirect symbol table unnecessary.
Application main entry point
A load command of type specifies where the application begins execution.
| Offset | Bytes | Description |
|---|---|---|
| 0 | 4 | <syntaxhighlight lang="text" class="" style="" inline="1">0x00000028</syntaxhighlight> (Command type) |
| 4 | 4 | Command size (24 bytes) |
| 8 | 8 | Starting address location |
| 16 | 8 | Stack size in memory |
If no relocation occurs, the main entry point equals the address location plus a zero base address. This marks the CPU’s initial instruction execution point.
This supersedes an older load command , which varied depending on CPU architecture and stored initial register states.
Application UUID number
A load command with type designates the application's universally unique identifier (UUID).
| Offset | Bytes | Description |
|---|---|---|
| 0 | 4 | <syntaxhighlight lang="text" class="" style="" inline="1">0x0000001B</syntaxhighlight> (Command type) |
| 4 | 4 | Command size (24 bytes) |
| 8 | 16 | A unique, compile-time assigned, 128-bit UUID |
The UUID functions as a distinct identifier assigned during compilation to differentiate the application file in app distribution platforms or online environments.
Minimum OS Version Requirement
A load command identified by the type indicates the minimum operating system version necessary.
| Offset | Bytes | Description |
|---|---|---|
| 0 | 4 | <syntaxhighlight lang="text" class="" style="" inline="1">0x00000032</syntaxhighlight> (Command identifier) |
| 4 | 4 | Size of the command |
| 8 | 4 | Platform identifier |
| 12 | 4 | Minimum required OS version |
| 16 | 4 | SDK version used |
| 20 | 4 | Count of tools utilized |
The following platform identifiers are defined:
| Value | Platform |
|---|---|
| 0x00000001 | macOS |
| 0x00000002 | iOS |
| 0x00000003 | tvOS |
| 0x00000004 | watchOS |
| 0x00000005 | bridgeOS |
| 0x00000006 | Mac Catalyst |
| Additional values represent simulators and DriverKit platforms. |
Version numbers are encoded as a combination of major, minor, and patch levels. For instance, corresponds to version 13.2.0. The SDK version utilizes the same encoding scheme.
The tools employed during binary compilation are itemized as follows:
| Offset | Bytes | Description |
|---|---|---|
| 0 | 4 | Tool identifier |
| 4 | 4 | Version number of the tool |
Tool identifiers include:
| Value | Tool Name |
|---|---|
| 0x00000001 | CLANG |
| 0x00000002 | SWIFT |
| 0x00000003 | LD (Linker) |
Version numbers for tools adhere to the same format as OS versions.
Starting with Mac OS X 10.6, Mach-O binaries default to execution only on systems running version 10.6 or newer due to introduction of load commands incompatible with earlier releases. Furthermore, Link Edit tables within the __LINKEDIT segment were compressed to optimize space but cannot be processed by versions preceding Mac OS X 10.6. To preserve compatibility with older versions, developers may apply the linker option "-mmacosx-version-min=".
Alternative Implementations
Mach-O applications can operate on various operating systems provided that a Mach-O binary compatible with the device's CPU architecture is available. Most desktop systems utilize x86 processors, enabling x86 Mach-O binaries to execute when mapped into memory. For ARM-based iPhone CPUs, running Mach-O binaries requires either ARM-based hardware (not limited to Apple silicon) or dynamic translation of ARM instructions into x86 code. A significant obstacle is the presence of undefined symbols referencing functions from other Mach-O binaries that may not exist on different operating systems. Some symbols might be resolved by linking to equivalent functions or through adapter routines that emulate macOS behavior. Variations in Mach-O files across iPhone (iOS), macOS, watchOS, and tvOS platforms influence compatibility of function calls.
Certain releases of NetBSD incorporated Mach-O support to enable binary compatibility, allowing execution of select Mac OS X 10.3 applications.
On Linux systems, Shinichiro Hamaji developed a Mach-O loader capable of handling binaries built for version 10.6 and later. Building upon this foundation, the Darling Project provides a comprehensive environment for running macOS software on Linux.
For Ruby developers, the ruby-macho gem offers a pure Ruby implementation for parsing and modifying Mach-O binaries.
See also
- Fat binary
- Universal binary
- Dynamic linker
- Mac transition to Intel processors
- Mac transition to Apple silicon
- Xcode
- PE
- ELF
- Comparison of executable file formats
Bibliography
External links
- OS X ABI Mach-O File Format Documentation (Apple Inc., archived September 4, 2014)
- Mach Object File Details (Documentation for NEXTSTEP)
- Overview of Mach-O Dynamic Libraries
- Techniques for Mach-O Linking and Loading
- MachOView Utility
- JDasm (A cross-platform disassembler supporting macOS, iOS, Windows PE, ELF, and various file format analyses)