This routine will calculate the number of bytes in arguments passed to a VARARG function and call the function correcting the stack afterwards. My question is why the

**sub eax,52**? I know that this can be done other ways but I was a bit interested and decided to figure it out.```
callvararg PROTO C :DWORD,:VARARG
```

[color=red];###############

;example :

;[b]invoke callvararg, pFunction, Arg1, Arg2, Arg3, Arg4, .....[/b]

;###############[/color]

callvararg proc C pFunction:DWORD,args:VARARG

LOCAL cbParams :DWORD

mov eax,[ebp]

sub eax,ebp

sub eax,52

jns @F

add eax,44

@@:

mov [cbParams],eax

sub eax,4

@@:

push [ebp+eax+8]

sub eax,4

jnz @B

CALL [pFunction]

mov eax,[cbParams]

sub eax,4 ; did not use the first dword

add esp,eax

ret

callvararg endp

Since the stack grows upward that you are being pointed back to the current stack pointer. The 56 is probably number of byte positions or divided by 4, the number of entries place in the stack by Windows before control is passed to your program.

But why always 56 if it is called from within a proc and 52 if called from outside a proc. It must have something to do with the way a stack frame is built. For example is there an extra DWORD that is pushed onto the stack if a procedure is called from within a proc ? If yes is it possible to know this at run-time ?

Hmmm, changed it a bit because the numbers are different if called from within a stack frame. The changes will adjust for a call from within another procedure but also allow for a call from outside of a procedure. This is really weird.

mov eax, ; = move the old value of ebp into eax

sub eax, ebp ; = difference between the old ebp and the current value in ebp

sub eax, 52 ; = this number differs, depending on whether you have local variables, preserved edi, esi etc. Also the parameters pushed onto the stack affects it. There the value you are subtracting from eax does depends on where you call it from etc.

sub eax, ebp ; = difference between the old ebp and the current value in ebp

sub eax, 52 ; = this number differs, depending on whether you have local variables, preserved edi, esi etc. Also the parameters pushed onto the stack affects it. There the value you are subtracting from eax does depends on where you call it from etc.

Actually Roticv, it remains the exact same if I have locals or not and the same if I preserve registers. The number is pretty much constant. I think it mainly depends on how many local variables and how many parameters are in the proc where it is called from. Anyway I think I'll give up for a while ;)

52 is = return address+ old base pointer + 44

44 or 12 dwords are the maximun arguments passed.

the first two lines is for calculate the distance between frames.

Here you can have two options:

a)one that pass the limit 52 (as is 12 dwords + ret addr + o bp) and

b) one that the distance is less or equal to 52.

with add eax, 44 you are calculating the number of arguments inside this, they can only be 0<arguments<12.

if the jump is taked, then I think the maximun numerb of args is 12, and are taked from ebp+eax+8

a explanation for

? let D be distance between stack frames a positive integer. (first to lines) 0<D< MAX

? check againt the limit 52 or the maximus of 12 args +

a) D > 52.

eg D=144

144 is (136+4+4) or (34 dwords

then 144-52 = 92 (not causes sign)

then = 92 or 23* dwords

b) 52> D > 0.

eg D = 32

32 is (24+4+4) or (11 dwords+retadr+obp)

then 32-52= -20 (cause sign)

then -20+44 = 24 or 11 dwords passed

then = 24 or 11* dw's

now take the sub eax, 4. substract a dword marked with * from a)23 and b)11, you get 22 and 10 dwords this is the number of times that you will repush an argument......

That is what I can say, i not think is correct, specially when D>52, you can see the 12 dword(limit i think) diference in some parts of a, eg:

I think it will only run for stack frames like this:

obp stand for old base pointer

where not exist locals like this

___ebp

because the distance between the stack frames is: 8*4, then 32-52 = -20, then -20+44 = 24 or 6 dwords in or 20 ;)... is counting locals!!!! in my point of view sure...

I will draft a posible best.. solution...

First, you know that inside you will trash eax, then is not problem trash before... :D

then before thecallvar you need do:

for masm Is the same:

I think it should work.

Nice day or night.

44 or 12 dwords are the maximun arguments passed.

the first two lines is for calculate the distance between frames.

Here you can have two options:

a)one that pass the limit 52 (as is 12 dwords + ret addr + o bp) and

b) one that the distance is less or equal to 52.

```
```

sub eax,52

jns @F

add eax,44

@@:

mov [cbParams],eax

with add eax, 44 you are calculating the number of arguments inside this, they can only be 0<arguments<12.

if the jump is taked, then I think the maximun numerb of args is 12, and are taked from ebp+eax+8

a explanation for

*a*and*b*.? let D be distance between stack frames a positive integer. (first to lines) 0<D< MAX

? check againt the limit 52 or the maximus of 12 args +

a) D > 52.

eg D=144

144 is (136+4+4) or (34 dwords

*or arguments*+retadr+obp)then 144-52 = 92 (not causes sign)

then = 92 or 23* dwords

*see the diference between 144 and 92 = 52 or***13 dwords**-1 is the maximun args, but is not apliedb) 52> D > 0.

eg D = 32

32 is (24+4+4) or (11 dwords+retadr+obp)

then 32-52= -20 (cause sign)

then -20+44 = 24 or 11 dwords passed

*(the next 12 is the maximun = 36)*then = 24 or 11* dw's

now take the sub eax, 4. substract a dword marked with * from a)23 and b)11, you get 22 and 10 dwords this is the number of times that you will repush an argument......

That is what I can say, i not think is correct, specially when D>52, you can see the 12 dword(limit i think) diference in some parts of a, eg:

*144 is (136+4+4)*or*(34 dwords and = 92 or 23* dwords*because 23 minux a dword is 22, and 34 dwords- 22 dwords = 12 dwords, this characteristic is showed in the last line where i say: "but is not aplied", this diference of 12.I think it will only run for stack frames like this:

obp stand for old base pointer

where not exist locals like this

___ebp

because the distance between the stack frames is: 8*4, then 32-52 = -20, then -20+44 = 24 or 6 dwords in or 20 ;)... is counting locals!!!! in my point of view sure...

I will draft a posible best.. solution...

First, you know that inside you will trash eax, then is not problem trash before... :D

then before thecallvar you need do:

**mov eax, esp**

invoke thecallvar, ptrfunct, sss,...

!!!!!!!!!!!!invoke thecallvar, ptrfunct, sss,...

```
```

funct thecallvar pFunction, args

local cbParams, dword

sizef 4 ;only one local :P

sub eax,ebp

mov [.cbParams],eax

sub eax,4

.pushOtherArgument:

push [ebp+eax+8] ;the +8 is for skip ret addr and obp

sub eax,4

jnz .pushOtherArgument

call dword[.pFunction]

mov eax,[.cbParams]

sub eax,4 ; did not use the first dword

add esp,eax

endfunct

this will function in nasm.
for masm Is the same:

```
```

callvararg proc C pFunction:DWORD,args:VARARG

LOCAL cbParams :DWORD

sub eax,ebp

mov [cbParams],eax

sub eax,4

@@:

push [ebp+eax+8] ;the +8 is for skip ret addr and obp

sub eax,4

jnz @B

call dword[pFunction]

mov eax,[cbParams]

sub eax,4 ; did not use the first dword

add esp,eax

ret

callvararg endp

I think it should work.

Nice day or night.