Can't link object file using ld - Mac OS X

不打扰是莪最后的温柔 提交于 2019-12-03 08:55:38

Getting the program to link is the easy part:

  • Change _start to start
  • $ nasm -f macho exit.asm
  • $ ld -arch i386 -o exiter exit.o

The problem is that exit.asm is calling the i386 Linux exit() system call (EAX = 1) and the program would NOT exit with a zero status as intended on OS X.

System Calls

A system call is a request to the kernel. exit(), unlike sqrt(), must make a request to a software component with higher privileges in its implementation since it terminates a running program. Apps can't create or terminate processes by themselves. System calls provide a way for apps to ask the kernel to perform actions on their behalf.

Making a syscall goes something like this:

  • Apps describe the operation they want to perform by placing data in CPU registers (or memory pointed to by registers), e.g.
    • The value 1 in EAX is the system call number of exit.
    • The value 0 in EBX (EBX was cleared by xor) is the first argument to the syscall, the exit status.
  • Apps issue an instruction that causes control to transfer to the kernel, e.g.
    • int 80 on i386
    • sycall on x86-64
    • svc in Thumb mode on ARMv7
  • The kernel inspects the request and decides to perform or deny it.
  • The kernel transfers control back to the app with the return value in an agreed upon location, e.g. EAX on i386.

Linux and OS X both provide a void exit(int) function for C programs but don't agree on the details on how to describe this request to the kernel. The code in exit.asm is at the same level as the implementation of the _exit() function in libc.

Even between different architectures running Linux the syscall numbers and calling convention differ. e.g. On x86-64 Linux, exit(0) is more commonly issued like this:

xor rdi, rdi
mov al, 60
syscall

You can see this by disassembling _exit in /lib64/libc.so.6.

Can't We Just Call exit() from libc Instead?

You can. But you'd have to link the program with libc. It's the difference between linking exit.asm above with:

$ cc -m32 -nostdlib exit.o -o exiter

and

exit-libc.asm

extern exit
global main
main:
push 0
call exit

which has to be linked with:

$ cc -m32 exit-libc.o -o exit-libc

Try this and take a look at the file size.

Mac OS X doesn't use ELF, so you'll want to generate a Mach-O object to link with on that system. On my machine nasm appears to only support 32-bit output, so you'll need to match that architecture when linking, too.

I also had to change _start to start to get it to link.

Here's a working example with your code:

$ cat exit.asm 
[SECTION .text]

global start

start:
xor eax, eax
xor ebx, ebx
mov al, 1
int 0x80
$ nasm -f macho exit.asm 
$ ld -arch i386 -macosx_version_min 10.7  -o exiter exit.o 
$ ./exiter 
$ echo $?
236

Note that the program probably doesn't do what you want on Mac OS X, since it doesn't do system calls the same way as Linux.

Most of the time when you receive this error:

ld: warning: PIE disabled. Absolute addressing (perhaps -mdynamic-no-pic) not 
allowed in code signed PIE, but used in _start from hello.o. To fix this 
warning, don't compile with -mdynamic-no-pic or link with -Wl,-no_pie

It is because it is looking for your "main()" function(label) to me the label "start:". It is always best to specify the your main label with "ld -e".

For nasm:

-o hello.tmp - outfile
-f macho - specify format
Linux - elf or elf64
Mac OSX - macho

For ld:

-arch i386 - specify architecture (32 bit assembly)
-macosx_version_min 10.6 (Mac OSX - complains about default specification)
-no_pie (Mac OSX - removes ld warning)
-e main - specify main symbol name (Mac OSX - default is start)
-o hello.o - outfile

For Shell:

./hello.o - execution

One-liner:

nasm -o hello.tmp -f macho hello.s && ld -arch i386 -macosx_version_min 10.6 -no_pie -e _main -o hello.o hello.tmp && ./hello.o

Let me know if this helps!

I wrote how to do it on my blog here:

http://blog.burrowsapps.com/2013/07/how-to-compile-helloworld-in-intel-x86.html

For a more verbose explanation, I explained on my Github here:

https://github.com/jaredsburrows/Assembly

The standard mac gcc won't link elf objects. For people who need to stick with the elf format and develop on a mac, 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
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!