Compiling NASM Assembly with Xcode in a C/C++ Project
Last time I talked about how to integrate NASM in a CMake/Clang build, but if you are developing on a Mac you may want to use Xcode to debug your assembly code.
Xcode needs a bit of massaging in order to support NASM within a C/C++ project.
Getting the latest NASM
First I suggest you install the latest version of NASM using Homebrew like so:
This will probably install nasm to /usr/local/bin
, unless you changed your Homebrew config. Double-check the location of your nasm executable and open Xcode.
Sample C++ Project
I suggest you create a blank “Command Line Tool” project in order to test the integration. You can use this as an test main.cpp
:
The GetRDTSC()
function returns the Time-Stamp Counter and is implemented in Assembly. In Rival Fortress rdtsc
is used for timing execution of performance critical code.
Now create a new assembly file. By default Xcode uses the .s
extension for assembly, but I prefer .asm
so I’ll use that in this example. This is the code for the x86-64 assembly file using NASM syntax. The call to cpuid
is required in order to avoid incorrect mesurements coused by Out of Order Execution, as detailed in the Benchmark Code Execution Paper by Intel.
Building NASM with Xcode
If you try to build the project you will receive syntax errors from Clang complaining about the invalid tokens from your .asm
file.
To fix this open the Build Rules for your target and create a new rule like so:
Here is the build script for easier copying:
And don’t forget to add a new Output File with the following path $(DERIVED_FILE_DIR)/${INPUT_FILE_BASE}.o
.
Now you should be able to build and debug your project.
Debugging and Stepping through ASM code
You can step into your assembly function with Xcode by using CTRL-F7
or CTRL+click
-ing the Step in button in the Xcode GUI.
The LLDB command line is also very useful in order to inspect registers since, unlike Visual Studio, Xcode lacks a Registers window.
Make sure you have it open by going to View->Debug Area->Activate Console, then type LLDB commands in the (lldb)
prompt. Use the register read
command to print out the contents of the general purpose registers in hex, or print $rax
to view the decimal value of a particular register. You can find the LLDB Command Map on the official website.