Search code examples
cassemblyx86stack

Assembly code, printf and allocating space on the stack


I am in the process of writing 64-bit assembly code for the Pentium. I am using Microsoft Visual C/C++ and MASM. In assembly code, I wrote the following code fragment to call printf:

push    rcx
push    rdx
push    rdi
push    rsi

lea rcx,string1
call    printf

pop rsi
pop rdi
pop rdx
pop rcx

where string1 is defined as: string1 db "start of func", 10, 0.

I expected the first four instructions to save four registers on the stack. That is, the values of the saved registers would be restored by the four pop instructions. However, the register values were not being properly restored. I found this video:

Link on calling printf

This video says that before calling printf you need to allocate 32 bytes on the stack for these values. Hence, I wrote this code:

push    rcx
push    rdx
push    rdi
push    rsi

sub rsp,20
lea rcx,string1
call    printf
add rsp,20h

pop rsi
pop rdi
pop rdx
pop rcx

This code works and makes some sense to me. When I look at the code generated by the C compiler it does not allocate any additional space on the stack and it works. Therefore, I do not understand why I need to allocate additional space on the stack. Please tell me what I am missing.


Solution

  • From the fact that you are passing a value in rcx, it appears you are using the windows calling conventions, rather than the "standard" calling conventions used by everyone except microsoft.

    For the Windows x64 calling convetions, when calling a varargs function (which printf is) you must allocate 32 bytes of "shadow" space on the stack immediately above1 the return address. There doesn't need to be anything in this space, but you can't (reliably) store anything there, as the called function may clobber it -- that is in fact what is happening to your saved register values in your first fragment.


    1"above" since the stack grows downward means allocated before the call