Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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


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.

like image 838
Jack Greenhill Avatar asked Aug 05 '11 13:08

Jack Greenhill


3 Answers

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.

like image 140
mk12 Avatar answered Nov 08 '22 18:11

mk12


OK, looking at your samples I assume you either used a generic nasm or linux assembly tutorial.
The first thing you need to take care of is the binary format created by nasm.
Your post states:

ld: warning: ignoring file program.o, file was built for unsupported file format which is not the architecture being linked (x86_64)

Thats the result of the '-f elf' parameter which tells nasm you want a 32bit ELF object (which would be the case for e.g. linux). But since you're on OSX what you want is a Mach-O object.

Try the following:

nasm -f macho64 -o program.o main.asm
gcc -o program program.o

Or if you wan't to create a 32bit binary:

nasm -f macho32 -o program.o main.asm
gcc -m32 -o program program.o

Regarding the _start symbol - if you wan't to create a simple program that will be able to use the provided libc system functions then you shouldn't use _start at al. It's the default entry point ld will look for and normaly it's provided in your libc / libsystem.

I suggest you try to replace the _start in your code by something like '_main' and link it like the example above states.

A generic libc-based assembly template for nasm could look like this:

;---------------------------------------------------
.section text
;---------------------------------------------------
use32             ; use64 if you create 64bit code
global _main      ; export the symbol so ld can find it

_main:
    push ebp
    mov  ebp, esp ; create a basic stack frame

    [your code here]

    pop ebp       ; restore original stack
    mov eax, 0    ; store the return code for main in eax
    ret           ; exit the program

In addition to this I should mention that any call's you do on OSX need to use an aligned stack frame or your code will just crash.
There are some good tutorials on that out there too - try searching for OSX assembly guide.

like image 5
Shirkrin Avatar answered Nov 08 '22 18:11

Shirkrin


It's probably easier just to let gcc do the heavy lifting for you, rather than trying to drive ld directly, e.g.

$ gcc -m32 program.o -o program
like image 2
Paul R Avatar answered Nov 08 '22 19:11

Paul R