Can't link assembly file in Mac OS X using ld

Jack Greenhill picture Jack Greenhill · Aug 5, 2011 · Viewed 16.6k times · Source


I'm trying to run a basic assembly file using 64 Bit Mac OS X Lion, using nasm and ld which are installed by default with Xcode.

I've written an assembly file, which prints a character, and I got it to build using nasm.

nasm -f elf -o program.o main.asm

However, when I go to link it with ld, it fails with quite a few errors/warnings:

ld -o program program.o

ld: warning: -arch not specified
ld: warning: -macosx_version_min not specificed, assuming 10.7
ld: warning: ignoring file program.o, file was built for unsupported file format which is not the architecture being linked (x86_64)
ld: warning: symbol dyld_stub_binder not found, normally in libSystem.dylib
ld: entry point (start) undefined.  Usually in crt1.o for inferred architecture x86_64

So, I tried to rectify a few of these issues, and got nowhere.

Here's one of things I've tried:

ld -arch i386 -e _start -o program program.o

Which I thought would work, but I was wrong.

How do you make the object file a compatible architecture that nasm and ld will agree with?

Also, how would you define the entry point in the program (right now I'm using global _start in .section text, which is above _start, which doesn't seem to do much good.)

I'm a bit confused as to how you would successfully link an object file to a binary file using ld, and I think I'm just missing some code (or argument to nasm or ld) that will make them agree.

Any help appreciated.

Answer

mk12 picture mk12 · Dec 30, 2011

You need to use global start and start:, no underscore. Also, you should not be using elf as the arch. Here is a bash script I use to assemble my x86-64 NASM programs on Mac OS X:

#!/bin/bash

if [[ -n "$1" && -f "$1" ]]; then
    filename="$1"
    base="${filename%%.*}"
    ext="${filename##*.}"

    nasm -f macho64 -Ox "$filename" \
    && ld -macosx_version_min 10.7 "${base}.o" -o "$base"
fi

If you have a file called foo.s, this script will first run

nasm -f macho64 -Ox foo.s

Which will create foo.o. The -Ox flag makes NASM do some extra optimization with jumps (i.e. making them short, near or far) so that you don't have to do it yourself. I'm using x86-64, so my code is 64-bit, but it looks like you're trying to assemble 32-bit. In that case, you would use -f macho32. See nasm -hf for a list of valid output formats.

Now, the object file will be linked:

ld -macosx_version_min 10.7 foo.o -o foo

I've set the -macosx_version_min option to quiet NASM down and prevent a warning. You don't have to set it to Lion (10.7). This will create an executable called foo. With any luck, typing ./foo and hitting return should run your program.

In regard to the ld: warning: symbol dyld_stub_binder not found, normally in libSystem.dylib warning, I get that every time too and I'm not sure why, but everything seems fine when I run the executable.