Using ld on macOS to turn a raw arm64 binary into an executable Mach-O binary
14:33 27 Apr 2026

I am working making an assembler that compiles bf code into an executable that can be run on macOS. Essentially, I run the compiler, which outputs a raw arm64 binary to output.bin (i.e., a binary that contains the arm64 machine code without any formatting). I figured out that the output.bin cannot be run directly, rather it needs to be first linked into a Mach-O binary in order for it to be executable. From what I've researched, the linking phase seems like it could be accomplished with the following steps:

  1. Compile an empty C file to create a stub Mach-O object
touch stub.c
cc -c stub.c -o stub.o
  1. Link the output.bin into the stub Mach-O object, creating a _start symbol
ld -r -o output.o stub.o -sectcreate __TEXT _start output.bin
  1. Link the newly-created output.o against the system libraries and designate _start as the executable entry point
ld -o output output.o -lSystem -syslibroot `xcrun -sdk macosx --show-sdk-path` -e _start -arch arm64

Where I get stuck is when I try to link the output.o to make the final executable, I get the following error:

Undefined symbols for architecture arm64:
  "_start", referenced from:
      
ld: symbol(s) not found for architecture arm64
make: *** [output] Error 1

When I run the nm output.o command, it doesn't show the _start symbol in the symbol table, rather I only see the following:

0000000000000000 t ltmp0

However, when I hex dump the output.o, there is a cluster of bytes that comes up with this:

000000b0: 0000 0000 0000 0000 5f73 7461 7274 0000  ........_start..
000000c0: 0000 0000 0000 0000 5f5f 5445 5854 0000  ........__TEXT..

Furthermore, the program code starts at offset 0x00000170 in the output.o. What step am I missing here?

macos linker mach-o