Compiling XNU for x86_64 is quite easy, particularly when armed with a good guide. Aside from an extremely helpful gist and a Twitter thread from Proteas, there didn’t seem to be much on compiling XNU for arm64.

Why would you want to compile XNU for arm64? Well, you definitely can’t run it on your i-device. But there could be many other reasons. For me, a clean compile means I can generate a clean compile-commands.json file for use with Woboq.


The long and short of this process is, follow the steps from this blog, with the following ammendments:

  1. Use my repository for xnu - it contains modifications to the xnu source necessary for building
    • Note: if you would rather build from Apple’s source, check the diff from my repo for changes I made
  2. a copy of the TargetConditionals.h header must be made from the iPhoneOS SDK’s /usr/include directory to the iPhoneOS SDK’s /System/Library/Frameworks/Kernel.framework/Versions/A/Headers directory in order to build libfirehose
  3. When building: the SDK is “iphoneos”, the ARCH is “arm64”, and XNU’s build also needs BUILD_WERROR=0

The Details

This process worked for me compiling XNU 4570.41.2 with a clean install of macOS High Sierra (10.13.5) and XCode 9.4, however, your mileage may vary.

CTF Tools

The CTF tools (ctfconvert, ctfdump and ctfmerge) are executed as part of XNU’s build and are expected to be in your hosts’s SDK path. Build is per the blog.

tar zxvf dtrace-262.tar.gz
cd dtrace-262
mkdir obj sym dst
xcodebuild install \
    -target ctfconvert -target ctfdump -target ctfmerge \
sudo ditto \
    $PWD/dst/Applications/ \
cd ..


AvailabilityVersions provides a perl script used as part of the XNU build. Build and installation is per the blog, except the install target is the iphoneos SDK.

tar zxvf AvailabilityVersions-32.30.1.tar.gz
cd AvailabilityVersions-32.30.1
mkdir dst
make install SRCROOT=$PWD DSTROOT=$PWD/dst
sudo ditto \
    $PWD/dst/usr/local/libexec \
    $(xcrun -sdk iphoneos -show-sdk-path)/usr/local/libexec
cd ..

libplatform Headers

Just three header files are required from this project.

tar zxvf libplatform-161.20.1.tar.gz
cd libplatform-161.20.1
sudo mkdir -p \
    $(xcrun -sdk iphoneos -show-sdk-path)/usr/local/include/os/internal
sudo ditto $PWD/private/os/internal \
    $(xcrun -sdk iphoneos -show-sdk-path)/usr/local/include/os/internal
cd ..

XNU Headers

The headers are ready to be built now. This is where the first modifications are required. Proteas’ suggestion of copying the compile and link flags for the ARM64 architecture at this point just works. I’d recommend using my repo and check the diff to see what I did.

After the headers are installed, a copy of the TargetConditionals.h header must be made from the SDK’s /usr/include directory to the SDK’s /System/Library/Frameworks/Kernel.framework/Versions/A/Headers directory in order to build libfirehose.

git clone -b xnu-4570.41.2
cd xnu
sudo ditto $PWD/BUILD/dst $(xcrun -sdk iphoneos -show-sdk-path)
sudo cp $(xcrun -sdk iphoneos -show-sdk-path)/usr/include/TargetConditionals.h \
    $(xcrun -sdk iphoneos -show-sdk-path)/System/Library/Frameworks/Kernel.framework/Versions/A/Headers/TargetConditionals.h
cd ..

libfirehose_kernel From libdispatch

The kernel libfirehose header and objects are required to build XNU. With the XNU headers and TargetConditionals.h header in the right place, this step is the same as before, however ENABLE_BITCODE must be set to “no” in the build.

tar zxvf libdispatch-913.30.4.tar.gz
cd libdispatch-913.30.4
mkdir obj sym dst
xcodebuild install -sdk iphoneos -target libfirehose_kernel \
sudo ditto $PWD/dst/usr/local \
    $(xcrun -sdk iphoneos -show-sdk-path)/usr/local
cd ..


Now it’s time to build XNU. With several code modifications (one fix and some code stubbing) and help to the make scripts, this is as simple as running one make command.

cd xnu

From there, you’ll have your very own XNU kernel targetting ARM64 located at BUILD/obj/RELEASE_ARM64/mach (and an unstripped version at BUILD/obj/RELEASE_ARM64/mach.unstripped)