Linkers, Loaders & Object Formats

Mach-O and PE/COFF

/ mock-OH; pee-ee, coff rhymes with cough /

ELF is the binary container on Linux, but it is not the only one. If you write code on a Mac, the compiler produces Mach-O files; if you build on Windows, you get PE/COFF files. They are different on the outside — different magic numbers, different field names, different tools — but they answer the same questions ELF answers: where is the code, where is the data, what symbols are defined or needed, how do addresses get fixed up.

Mach-O (the format used by macOS and iOS) begins with a magic number such as 0xfeedface (32-bit) or 0xfeedfacf (64-bit), followed by a sequence of load commands. Each load command tells the loader something concrete: map this segment, here is the symbol table, here is the dynamic linker to use (dyld). Where ELF has sections grouped into segments, Mach-O has segments (like __TEXT and __DATA) that each contain sections (like __text and __data) — note the double-underscore naming. PE/COFF (Portable Executable, built on the older COFF) is the Windows world: a file begins with the old DOS 'MZ' header, which points to a 'PE' signature, after which COFF section headers describe .text, .data, .rdata, and an import table naming the DLLs and functions the program needs, resolved by the Windows loader.

Why know about all three? Because the ideas transfer. Once you understand sections, segments, a symbol table, relocations, and a dynamic linker in ELF terms, you can read any of the formats — the vocabulary changes but the machinery does not. A common mistake is assuming a tool or a .o file is portable across operating systems: it is not, because the container differs at the byte level. The C source is portable; the linked binary is tied to one format.

Magic numbers at the start of each format: ELF : 7f 45 4c 46 (\x7fELF) Mach-O : cf fa ed fe (0xfeedfacf, 64-bit, byte-swapped) PE/COFF : 4d 5a ... 50 45 ('MZ' ... 'PE')

Three operating systems, three containers, three magic numbers — but each holds code, data, symbols, and relocations.

A .o or .so built on Linux will not load on macOS or Windows and vice versa; only the source code is portable, not the linked object. The concepts, however, map cleanly across all three.

Also called
Mach objectPortable ExecutableCommon Object File FormatWindows 與 macOS 的執行檔格式