Hello world in 64bit, Mac OS X

System call numbers in 64 bit are different when compared to the 32 bit versions. They are obtained by adding the 32 bit system call number to 0x2000000 (see SYSCALL_CONSTRUCT_UNIX in syscall_hw.h).

Other 64 bit particularities are instruction pointer (%rip) relative data references.

If you try to assemble:

.data
msg:
.ascii "Hello, world!\n"
len:
.long . - msg

.text # text section
.globl _start # declare _start as global symbol for the linker to find

_start:
movq len, %rdx # length of string



you get:


cristi:64bit diciu$ as -arch x86_64 rdf.s -o rdf.o
rdf.s:14:32-bit absolute addressing is not supported for x86-64
rdf.s:14:cannot do signed 4 byte relocation


This is explained in the x86-64 Code Model:

All local and small data is accessed directly using addressing that’s relative to the instruction pointer (RIP-relative addressing). All large or possibly nonlocal data is accessed indirectly through a global offset table (GOT) entry. The GOT entry is accessed directly using RIP-relative addressing.



Our hello world assembler program becomes:


============= hello64bit.s ===================
#as -arch x86_64 hello64bit.s -o hello64bit.o
#ld -e _start -arch x86_64 hello64bit.o -o hello64bit

.data # data section
msg:
.ascii "Hello, world!\n" # ascii string to be printed
len:
.long . - msg # string length

.text # text section
.globl _start # declare _start as global symbol for the linker to find

_start:
movq $0x2000004, %rax # write call (see SYSCALL_CONSTRUCT_UNIX)
movq $1, %rdi # file descriptior (stdout)
movq msg@GOTPCREL(%rip), %rsi # string to print
movq len(%rip), %rdx # length of string
syscall # call write

movq $0x2000001, %rax # exit call
movq $0, %rdi # return code
syscall # call exit