Assembly Language for Beginners

(Jeff_L) #1

1.10. ACCESSING PASSED ARGUMENTS


As we can see, the compact functionf()takes all its arguments from the registers.


TheLEAinstruction here is used for addition, apparently the compiler considered it faster thanADD.


LEAis also used in themain()function to prepare the first and thirdf()arguments. The compiler must
have decided that this would work faster than the usual way of loading values into a register usingMOV
instruction.


Let’s take a look at the non-optimizing MSVC output:


Listing 1.90: MSVC 2012 x64

f proc near


; shadow space:
arg_0 = dword ptr 8
arg_8 = dword ptr 10h
arg_10 = dword ptr 18h


; ECX - 1st argument
; EDX - 2nd argument
; R8D - 3rd argument
mov [rsp+arg_10], r8d
mov [rsp+arg_8], edx
mov [rsp+arg_0], ecx
mov eax, [rsp+arg_0]
imul eax, [rsp+arg_8]
add eax, [rsp+arg_10]
retn
f endp


main proc near
sub rsp, 28h
mov r8d, 3 ; 3rd argument
mov edx, 2 ; 2nd argument
mov ecx, 1 ; 1st argument
call f
mov edx, eax
lea rcx, $SG2931 ; "%d\n"
call printf


; return 0
xor eax, eax
add rsp, 28h
retn
main endp


It looks somewhat puzzling because all 3 arguments from the registers are saved to the stack for some
reason. This is called “shadow space”^81 : every Win64 may (but is not required to) save all 4 register
values there. This is done for two reasons: 1) it is too lavish to allocate a whole register (or even 4
registers) for an input argument, so it will be accessed via stack; 2) the debugger is always aware where
to find the function arguments at a break^82.


So, some large functions can save their input arguments in the “shadows space” if they want to use them
during execution, but some small functions (like ours) may not do this.


It is acallerresponsibility to allocate “shadow space” in the stack.


GCC


Optimizing GCC generates more or less understandable code:


Listing 1.91: Optimizing GCC 4.4.6 x64

f:
; EDI - 1st argument
; ESI - 2nd argument
; EDX - 3rd argument


(^81) MSDN
(^82) MSDN

Free download pdf