I'm trying to write a hello world program but it doesn't work - why?
.data
str:
.ascii "Hello World\12\0"
.text
.globl main
.extern printf
main:
pushq %rbp
movq %rsp,%rbp
movq str,%rdi
callq printf
movq %rbp,%rsp
popq %rbp
ret
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 theRAXregister to indicate the number of floating-point arguments being passed in vector registers. You do not initialize theRAXregister, so it effectively contains garbage data. Theprintffunction 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
RAXbefore making the call. There are several ways to do that. The obvious ismovq $0, %rax, however, a more optimal way to zero-out a register is to use theXORinstruction—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 doxorl %eax, %eax. This is one byte shorter, and will execute slightly faster.Technically, your
mainfunction should also be returning 0. The calling convention specifies that a function returns an integer result using theRAXregister, so you just need to zero-outRAXagain before you return. Right now,printfis returning its result inRAX, and since you don't setRAX, you are effectively returning the result ofprintffrommain. That's legal, but probably not what you want.So, your
mainfunction should look like this:But you can make the code even shorter by eliminating the
movq %rsp, %rbpinstruction. You aren't doingRBP-relative addressing, so you don't need that here. And, as Peter Cordes pointed out in a comment, you could optimizemovq str, %rditomovl str, %edi. Your final code would then simply be: