Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to write assembly language hello world program for 64 bit Mac OS X using printf?

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.

like image 762
Alfred Zhong Avatar asked Jan 01 '12 04:01

Alfred Zhong


1 Answers

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
like image 66
Stephen Canon Avatar answered Sep 28 '22 15:09

Stephen Canon