Assembly Language for Beginners

(nextflipdebug2) #1

3.14. VARIADIC FUNCTIONS


cdeclcalling conventions


Listing 3.57: Optimizing MSVC 6.0

_v$ = 8
_arith_mean PROC NEAR
mov eax, DWORD PTR _v$[esp-4] ; load 1st argument into sum
push esi
mov esi, 1 ; count=1
lea edx, DWORD PTR _v$[esp] ; address of the 1st argument
$L838:
mov ecx, DWORD PTR [edx+4] ; load next argument
add edx, 4 ; shift pointer to the next argument
cmp ecx, -1 ; is it -1?
je SHORT $L856 ; exit if so
add eax, ecx ; sum = sum + loaded argument
inc esi ; count++
jmp SHORT $L838
$L856:
; calculate quotient


cdq
idiv esi
pop esi
ret 0
_arith_mean ENDP


$SG851 DB '%d', 0aH, 00H


_main PROC NEAR
push -1
push 15
push 10
push 7
push 2
push 1
call _arith_mean
push eax
push OFFSET FLAT:$SG851 ; '%d'
call _printf
add esp, 32
ret 0
_main ENDP


The arguments, as we may see, are passed tomain()one-by-one.


The first argument is pushed into the local stack as first.


The terminating value (− 1 ) is pushed last.


Thearith_mean()function takes the value of the first argument and stores it in thesumvariable.


Then, it sets theEDXregister to the address of the second argument, takes the value from it, adds it to
sum, and does this in an infinite loop, until− 1 is found.


When it’s found, the sum is divided by the number of all values (excluding− 1 ) and thequotientis returned.


So, in other words, the function treats the stack fragment as an array of integer values of infinite length.


Now we can understand why thecdeclcalling convention forces us to push the first argument into the
stack as last.


Because otherwise, it would not be possible to find the first argument, or, for printf-like functions, it would
not be possible to find the address of the format-string.


Register-based calling conventions


The observant reader may ask, what about calling conventions where the first few arguments are passed
in registers? Let’s see:

Free download pdf