I do not understand either Microsoft x64 calling convention or FASM's implementation of it

Viewed 221

I've written a short PE32+ program in FASM that writes "Hello World!" to stdout and quits.

format PE64 console
include 'win64wx.inc'
.code
  start:
    invoke WriteFile,<invoke GetStdHandle,STD_OUTPUT_HANDLE>,hello,hello.length,dummy,0
    invoke ExitProcess,0
  .end start
.data
  dummy rd 1  
  hello db "Hello world!",13,10,0
  hello.length = $ - hello

I've looked at the generated machine code, but I cannot understand why RSP is manipulated the way it is. This is the disassembly:

sub rsp,byte +0x08         ;Allocate 8 bytes on the stack. 
sub rsp,byte +0x30         ;Allocate shadow space for WriteFile (48 bytes)
sub rsp,byte +0x20         ;Allocate shadow space for GetStdHandle
mov rcx,0xfffffffffffffff5 ;Set the constant for stdout
call [rel 0x1060]          ;Call GetStdHandle. The handle for stdout is now in RAX
add rsp,byte +0x20         ;Deallocate shadow space for GetStdHandle
mov rcx,rax                ;Set stdout handle: hFile
mov rdx,0x403004           ;Set the pointer to string "Hello World!\r\n": lpBuffer
mov r8,0xf                 ;Set the length of the string: nNumberOfBytesToWrite
mov r9,0x403000            ;Set the pointer for lpNumberOfBytesWritten
mov qword [rsp+0x20],0x0   ;Push a 64 bit NULL pointer onto the stack: lpOverlapped
call [rel 0x1068]          ;Call WriteFile
add rsp,byte +0x30         ;Deallocate shadow space for WriteFile
sub rsp,byte +0x20         ;Allocate shadow space for ExitProcess
mov rcx,0x0                ;Set the return value
call [rel 0x1058]          ;Call ExitProcess
add rsp,byte +0x20         ;Deallocate shadow space for ExitProcess

I understand it doesn't really matter that the space for WriteFile is allocated well in advance, but why is it sub rsp,byte +0x30 and not sub rsp,byte +0x28? And why is the first sub rsp,byte +0x08 there? Is it FASM's idiosyncrasy or am I fundamentally misunderstanding Microsoft x64 stack management rules?

0 Answers
Related