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

4

13


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.

Donato answered 5/8, 2011 at 13:58 Comment(1)
Have you tried linking using gcc instead of ld? It's often a lot easier and you can use the C runtime and standard library (e.g. have main as the entry point). Another thing to try is to use a mach object file format instead of elf.Sparteine
H
6

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.

Hetrick answered 30/12, 2011 at 18:33 Comment(0)
I
5

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.

Indogermanic answered 15/9, 2011 at 7:29 Comment(0)
K
2

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
Karylkarylin answered 5/8, 2011 at 14:13 Comment(0)
X
1

The mac gcc compiler won't link elf objects. You need a cross compiler...

http://crossgcc.rts-software.org/doku.php?id=compiling_for_linux

Then you can proceed with something similar to this...

/usr/local/gcc-4.8.1-for-linux32/bin/i586-pc-linux-ld -m elf_i386 -T link.ld -o kernel kasm.o kc.o
Xanthippe answered 3/12, 2015 at 16:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.