The same bytes ship to machines running different OS releases, get debugged months later, and may be rejected before they run at all. Two small load commands answer the three questions that follow: where is this allowed to run (platform + minimum OS), what was it built against (SDK, plus the tool versions that produced it), and which exact build is this (UUID). dyld consults the first to refuse old systems cleanly; crash reporters and dsymutil use the UUID to join a crashed binary to its debug file — without a matching UUID there are no symbols, only addresses.
If you have ever seen "built with SDK … requires macOS …" in an error dialog, or a crash log keyed by a 36-character hex string, these two commands are the source.
Think of LC_BUILD_VERSION as a passport stamp and LC_UUID as a fingerprint:
LC_UUID is simpler still: cmd, cmdsize, and 16 raw bytes. It is not derived from content (rebuild with identical sources and it changes) — it is minted per link, per architecture slice.
The model's missing piece: minos and sdk answer different questions. A binary can carry sdk 13.3 and minos 10.15 — built today against the 13.3 SDK, still runnable on four-year-old systems — and only minos gates execution.
build_version_command = {cmd 0x32, cmdsize, platform, minos, sdk, ntools} followed by ntools × build_tool_version {tool, version} — so cmdsize = 32 + 8 × ntools for the usual ntools = 1. Versions pack three parts into one u32, loader.h's comment: "X.Y.Z is encoded in nibbles xxxx.yy.zz" — major shift 16, minor shift 8, patch in the low byte (13.3 → 0x000D0300). Tool values from the same header: TOOL_CLANG 1, TOOL_SWIFT 2, TOOL_LD 3. Platforms: PLATFORM_MACOS 1, IOS 2, TVOS 3, WATCHOS 4, BRIDGEOS 5, MACCATALYST 6, then simulators 7–9, DRIVERKIT 10.
The older form, LC_VERSION_MIN_MACOSX (0x24), is a 16-byte version_min_command {version, sdk} with no platform field — one command per OS family (LC_VERSION_MIN_IPHONEOS etc.). LC_BUILD_VERSION (0x32) replaced it when one binary could target platforms the old commands could not name. LC_UUID is 0x1b, cmdsize 24, always exactly one per slice.
The dylib sample — classic era, macOS-only, built by the linker itself:
cmd LC_UUID
cmdsize 24
uuid DA4AFC52-D48E-39AB-B574-FE3B9CC5232F
cmd LC_BUILD_VERSION
cmdsize 32
platform 1
sdk 13.3
minos 10.15
ntools 1
tool 3
version 857.1Decode: platform 1 = macOS; sdk 13.3 = 0x000D0300; minos 10.15 = 0x000A0F00; tool 3 = TOOL_LD — this stamp says ld 857.1 built the file against the macOS 13.3 SDK with a 10.15 floor. Now the executable sample — modern era, both slices from the same link:
uuid 4C4C44C9-5555-3144-A19F-1D5685FC622F (x86_64)
uuid 4C4C44B1-5555-3144-A130-3397BCE0A53C (arm64)
platform 1 sdk 13.0 minos 13.0 ntools 1
tool 4 version 22.1.2sdk and minos both 13.0 — a single-platform, single-floor build. tool 4 is where honesty matters: this course's loader.h revision names only tools 1–3, so the value 4 (version 22.1.2) is recorded here as observed, without a name we can cite from the header. And the two UUIDs differ despite identical sources — per-slice identity, exactly as the model says.
$ /usr/lib/llvm-21/bin/llvm-otool -arch x86_64 -l prog64.macho | grep -A8 LC_BUILD_VERSION
$ python3 -c "v=0x000D0300; print((v>>16)&0xffff, (v>>8)&0xff, v&0xff)"
13 3 0
$ /usr/lib/llvm-21/bin/llvm-otool -arch x86_64 -l prog64.macho | grep -A2 LC_UUIDWhat to look for: the python unpack is the inverse of loader.h's xxxx.yy.zz rule — three numbers, one u32; otool prints sdk/minos already decoded. Then compare UUIDs across arch flags on a FAT binary: two slices, two stamps, and a crash log only makes sense once you know which one it cites.
Without looking back: a load command's minos field reads 0x000D0300. What version is that?
A binary reports platform 1, sdk 13.3, minos 10.15. A user runs it on macOS 11. What decides whether dyld loads it?
The pattern: platform must match, minos must be satisfied, sdk is provenance — and the UUID rides along untouched until a debugger needs it.
Knowing which build this is invites the next question: is it also which bytes the developer signed? The UUID identifies a build to tools; macOS wants a cryptographic statement identifying it to a developer — and the load command that carries it is next.
Next: Code Signing — LC_CODE_SIGNATURE, the big-endian superblob, page hashes in the CodeDirectory, and the team identity embedded at byte 101 of ours.