You won’t be able to get your hands on an Apple Silicon Mac for a few months yet, but you no doubt want to check which of your apps are already Universal, and include code to enable them to run native on both Intel and Apple Silicon Macs. Until you are running macOS 11 Big Sur, inspecting them in the Finder’s Get Info dialog tells you nothing about this. This article explains how you can check on Catalina and earlier.
Simplest is using my free utility ArchiChect, which shows in the first row of checkboxes which processor architectures an app supports. This information is also duplicated in the codesign check reported in detail in the scrolling text view below, where it says
Format=app bundle with Mach-O universal (x86_64 arm64)
Terminal also provides two useful commands for checking the platforms supported by executable code: file
and lipo
. You can’t use these on the app folder itself, but need to pass the file containing executable code instead. For example,
file LockRattler.app/Contents/MacOS/LockRattler
should return something like
LockRattler: Mach-O universal binary with 2 architectures: [x86_64:Mach-O 64-bit executable x86_64] [arm64:Mach-O 64-bit executable arm64]
LockRattler (for architecture x86_64): Mach-O 64-bit executable x86_64
LockRattler (for architecture arm64): Mach-O 64-bit executable arm64
Using lipo
:
lipo -archs LockRattler.app/Contents/MacOS/LockRattler
should return the briefer
x86_64 arm64
If you want to go lower still and inspect the executable code itself, you’ll see the differences immediately.
Executable x86_64 files start with the ‘magic’ bytes CF FA ED FE 07, which when their byte order is rearranged spells FEEDFACF, the ‘magic’ for a Mach-O executable for x86_64. Shortly after that, you’ll see the text PAGEZERO, following which is the single-architecture executable.
Universal files with x86_64 and arm64 support start with the ‘magic’ bytes CA FE BA BE, in that order, which is also the ‘magic’ for a Java class file. Following that is empty padding until you encounter the x86_64 executable, which is introduced using the same ‘magic’ bytes of CF FA ED FE 07, then the text PAGEZERO, and the rest of the executable.
About half way through a Universal file supporting x86_64 and arm64 architectures, you’ll notice the embedded certificates and material which normally come at the end of the executable. Following that is another run of empty padding before you encounter the arm64 executable. That’s introduced using the ‘magic’ bytes of CF FA ED FE 0C which indicates the different architecture, following which is the text PAGEZERO and another complete executable including the embedded certificate information, and finally more empty padding.
There are a few executables which are ‘Universal’ in the sense that they support multiple platforms none of which is arm64. One example is /usr/lib/libobjc.dylib, which lipo
reveals supports three architectures – x86_64 x86_64h and i386 – but on an Intel Mac none of those is arm64! If in doubt about an executable, check its supported architectures using lipo
rather than relying on ‘magic’ yourself.
Apple provides additional information here.
Thanks to @rosyna for pointing out that executable code which appears to be ‘Universal’ may simply support multiple Intel architectures, and not Apple Silicon. I have amended my initial version to try to make this clearer.