I am trying to learn x64 assembler. I wrote \"hello world\" and tried to call printf using the following code:
EXTERN printf: PROC
PUBLIC hello_world_asm
.data
It isn't required, this code just wastes an instruction by doing an lea
into RAX and then copying to RCX, when it could do
lea rcx, hello_msg
call printf ; printf(rcx, rdx, r8, r9, stack...)
printf
on 64-bit Windows ignores RAX as an input; RAX is the return-value register in the Windows x64 calling convention (and can also be clobbered by void
functions). The first 4 args go in RCX, RDX, R8, and R9 (if they're integer/pointer like here).
Also note that FP args in xmm0..3 have to be mirrored to the corresponding integer register for variadic functions like printf
(MS's docs), but for integer args it's not required to movq xmm0, rcx
.
In the x86-64 System V calling convention, variadic functions want al
= the number of FP args passed in registers. (So you'd xor eax,eax
to zero it). But the x64 Windows convention doesn't need that; it's optimized to make variadic functions easy to implement (instead of for higher performance / more register args for normal functions).
A few 32-bit calling conventions pass an arg in EAX, for example Irvine32, or gcc -m32 -mregparm=1
. But no standard x86-64 calling conventions do. You can do whatever you like with private asm functions you write, but you have to follow the standard calling conventions when calling library functions.
Also note that lea rax, offset hello_msg
was weird; LEA uses memory-operand syntax and machine encoding (and gives you the address instead of the data). offset hello_msg
is an immediate, not a memory operand. But MASM accepts it as a memory operand anyway in this context.
You could use mov ecx, offset hello_msg
in position-dependent code, otherwise you want a RIP-relative LEA. I'm not sure of the MASM syntax for that.
The Windows 64-bit (x64/AMD64) calling convention passes the first four integer arguments in RCX, RDX, R8 and R9.
The return value is stored in RAX and it is volatile so a C/C++ compiler is allowed to use it as generic storage in a function.