Metric Panda Games

One pixel at a time.

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:

brew install nasm

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:

#include <stdio.h>

extern "C" long long GetRDTSC();

int main(int, const char**)
{
  long long RDTSC1 = GetRDTSC();
  long long RDTSC2 = GetRDTSC();
  printf("Time-Stamp Counters: %lld - %lld\n", RDTSC1, RDTSC2);
  return 0;
}

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.

global _GetRDTSC

section .text

_GetRDTSC:
  cpuid
  rdtsc
  shl   rdx, 32
  or    rax, rdx
  ret

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:

/usr/local/bin/nasm -f macho64 ${INPUT_FILE_PATH} -o ${SCRIPT_OUTPUT_FILE_0}

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.