When using Rosetta on macOS running on an ARM processor, the arch command can be used to force a wrapped command to execute as a specific architecture. In other words, arch -arch x86_64 mycommand will try to launch mycommand as an x86/Intel program. If mycommand is ARM-only, it will fail; if mycommand is a universal binary, it will be run as x86.
But how does the arch -arch ... command actually work? Specifically, I have these questions:
- By what mechanism does
arch -arch $arch $programselect a$archfrom a universal binary$programand run it? - By what mechanism does
arch -arch $arch $programtry to run a non-universal binary$programas the selected architecture$arch, causing a failure if the binary doesn't support it? - Is it possible for another program to do what
archdoes here, without shelling out toarch? Even if it's possible-but-not-recommended/a private macOS API, I'm still interested in how it happens.
I'm asking this out of curiosity, not because I need to get around what arch does.
I've tried:
- Looking into the guts of
lipowhile making universal binaries.liposeems to be concatenating binaries for different architectures together in a Mach-O "fat binary" container with some magic bits at the top to indicate what contents are where. This helps a little bit with the first question above, but doesn't help with the second or third. - Looking into fat binary parsing tools like mach_object. It seems theoretically possible for me to extract the appropriate sub-binary from a fat binary, dump it to a temp file, and execute it, but that seems like it would have all sorts of problems (CWD would be wrong, writing a file just to launch a program seems wasteful).