6.1. ARGUMENTS PASSING METHODS (CALLING CONVENTIONS)
#include <stdio.h>
// located in some other file
void modify_a (int *a);
void f (int a)
{
modify_a (&a);
printf ("%d\n", a);
};
It’s hard to understand how it works until we can see the code:
Listing 6.10: Optimizing MSVC 2010
$SG2796 DB '%d', 0aH, 00H
_a$ = 8
_f PROC
lea eax, DWORD PTR _a$[esp-4] ; just get the address of value in local stack
push eax ; and pass it to modify_a()
call _modify_a
mov ecx, DWORD PTR _a$[esp] ; reload it from the local stack
push ecx ; and pass it to printf()
push OFFSET $SG2796 ; '%d'
call _printf
add esp, 12
ret 0
_f ENDP
The address of the place in the stack whereahas been passed is just passed to another function. It
modifies the value addressed by the pointer and thenprintf()prints the modified value.
The observant reader might ask, what about calling conventions where the function’s arguments are
passed in registers?
That’s a situation where theShadow Spaceis used.
The input value is copied from the register to theShadow Spacein the local stack, and then this address
is passed to the other function:
Listing 6.11: Optimizing MSVC 2012 x64
$SG2994 DB '%d', 0aH, 00H
a$ = 48
f PROC
mov DWORD PTR [rsp+8], ecx ; save input value in Shadow Space
sub rsp, 40
lea rcx, QWORD PTR a$[rsp] ; get address of value and pass it to modify_a()
call modify_a
mov edx, DWORD PTR a$[rsp] ; reload value from Shadow Space and pass it to printf⤦
Ç()
lea rcx, OFFSET FLAT:$SG2994 ; '%d'
call printf
add rsp, 40
ret 0
f ENDP
GCC also stores the input value in the local stack:
Listing 6.12: Optimizing GCC 4.9.1 x64
.LC0:
.string "%d\n"
f:
sub rsp, 24
mov DWORD PTR [rsp+12], edi ; store input value to the local stack
lea rdi, [rsp+12] ; take an address of the value and pass it to modify_a⤦
Ç()
call modify_a