You are violating the calling convention. Since this is 64-bit code running on Linux, the applicable calling convention would be System V AMD64. (More detailed info in the x86 tag wiki.)
Note that for variadic functions like printf
, this calling convention requires that the caller set the RAX
register to indicate the number of floating-point arguments being passed in vector registers. You do not initialize the RAX
register, so it effectively contains garbage data. The printf
function then tries to read an undefined number of floating-point values from vector registers, and thus causes a segmentation fault.
All you need to do to fix the code is to zero-out RAX
before making the call. There are several ways to do that. The obvious is movq $0, %rax
, however, a more optimal way to zero-out a register is to use the XOR
instruction—e.g.: xorq %rax, %rax
. But you can do even better than that. Since on x86-64, all instructions implicitly clear the upper 32 bits of the destination register, you can simply do xorl %eax, %eax
. This is one byte shorter, and will execute slightly faster.
Technically, your main
function should also be returning 0. The calling convention specifies that a function returns an integer result using the RAX
register, so you just need to zero-out RAX
again before you return. Right now, printf
is returning its result in RAX
, and since you don't set RAX
, you are effectively returning the result of printf
from main
. That's legal, but probably not what you want.
So, your main
function should look like this:
pushq %rbp
movq %rsp, %rbp
movq str, %rdi
xorl %eax, %eax
callq printf
xorl %eax, %eax
movq %rbp, %rsp
popq %rbp
ret
But you can make the code even shorter by eliminating the movq %rsp, %rbp
instruction. You aren't doing RBP
-relative addressing, so you don't need that here. And, as Peter Cordes pointed out in a comment, you could optimize movq str, %rdi
to movl str, %edi
. Your final code would then simply be:
pushq %rbp # reserve 8 bytes of space on the stack
movl str, %edi # get address of string constant
xorl %eax, %eax # clear RAX register in preparation for calling printf
callq printf
xorl %eax, %eax # clear RAX register so we return 0
popq %rbp # clean up the stack
ret
`, select the code and press the `{}` button in the editor.
– Chai T. Rex Dec 31 '16 at 01:28