17

I am trying to learn writing assembly language for 64 bit Mac OS. I have no problem with 32 bit Mac OS and both 32 bit and 64 bit Linux.

However, Mac OS 64 bit is different and I couldn't figure out. Therefore I am here to ask for help.

I have not problem using system call to print. However, I would like to learn how to call C functions using 64 bit assembly language of Mac OS.

Please look at the following code

.data
_hello:
    .asciz "Hello, world\n"


.text
.globl _main
_main:
    movq $0, %rax
    movq _hello(%rip), %rdi
    call _printf

I use $ gcc -arch x86_64 hello.s

to assemble and link.

It generates binary code. However, I got a segmentation fault when running it.

I tried adding "subq $8, %rsp" before calling _printf, still the same result as before.

What did I do wrong?

By the way, is that any way to debug this code on Mac? I tried adding -ggdb or -gstab or -gDWARF, and $gdb ./a.out, and can't see the code and set break points.

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
Alfred Zhong
  • 6,773
  • 11
  • 47
  • 59

1 Answers1

12

You didn't say exactly what the problem you're seeing is, but I'm guessing that you're crashing at the point of the call to printf. This is because OS X (both 32- and 64-bit) requires that the stack pointer have 16-byte alignment at the point of any external function call.

The stack pointer was 16-byte aligned when _main was called; that call pushed an eight-byte return address onto the stack, so the stack is not 16-byte aligned at the point of the call to _printf. Subtract eight from %rsp before making the call in order to properly align it.


So I went ahead and debugged this for you (no magic involved, just use gdb, break main, display/5i $pc, stepi, etc). The other problem you're having is here:

movq _hello(%rip), %rdi

This loads the first eight bytes of your string into %rdi, which isn't what you want at all (in particular, the first eight bytes of your string are exceedingly unlikely to constitute a valid pointer to a format string, which results in a crash in printf). Instead, you want to load the address of the string. A debugged version of your program is:

.cstring
_hello: .asciz "Hello, world\n"

.text
.globl _main
_main:
    sub  $8, %rsp           // align rsp to 16B boundary
    mov  $0, %rax
    lea  _hello(%rip), %rdi // load address of format string
    call _printf            // call printf
    add  $8, %rsp           // restore rsp
    ret
Stephen Canon
  • 103,815
  • 19
  • 183
  • 269
  • Thanks, Stephen. I am aware of the 16 byte stack alignment issue. I added subq $8, %rsp and still get segmentation fault... I am suspecting movq _hello(%rip), %rdi, I am not sure this is right. On Linux I can just use movq _hello, %rdi, but mac will complain that absolute address is not supported. – Alfred Zhong Jan 01 '12 at 17:41
  • Thank again, Stephen! It works! What a magic! I actually tried using leaq. However, I didn't realize even not pushing any parameter on the stack, the stack still has to be aligned by 16 bytes. What a confusing situation! – Alfred Zhong Jan 03 '12 at 07:08
  • What is %rdi in here? – Koray Tugay Dec 25 '14 at 09:17
  • @KorayTugay: It's not obvious what you're asking; `%rdi` is a register name, specifically the name of the register that contains the first integer/pointer argument (in this case a pointer) of a function call under the OS X x86_64 calling conventions. – Stephen Canon Dec 25 '14 at 15:46