MASM C vararg function and its calling from C language

Started by MazeGen, April 11, 2005, 11:10:59 AM

Previous topic - Next topic

MazeGen

Hi,
I'm coding a function using C calling convention with variable argument count. It will be called from MASM code and also from C code in future.

The MASM programmer's manual says that I should use something like the following prototype:

addup3 PROTO C, argcount:DWORD, args:VARARG

That's clear for me, but...
Altough I've seen some of C vararg function prototypes, it is not clear to me where the compiler puts the argcount argument, so my question is whether such order of arguments will work also if called from C module (I don't know C code generation).

BTW, I've already read chapter 12 in MASM programmer's manual, The C Calling Convention, but I haven't found the answer.

MichaelW

For the C calling convention, one possibility would be to determine the number of arguments from the stack adjustment instruction at the return address. I have not tested this called from C, but it seems to me that it should work.

; ««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    .486                       ; create 32 bit code
    .model flat, stdcall       ; 32 bit memory model
    option casemap :none       ; case sensitive

    include \masm32\include\windows.inc
    include \masm32\include\masm32.inc
    include \masm32\include\kernel32.inc
    includelib \masm32\lib\masm32.lib
    includelib \masm32\lib\kernel32.lib
    include \masm32\macros\macros.asm

    testproc PROTO C :VARARG
; ««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    .data
    .code
; ««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
start:
; ««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    invoke testproc,1
    print ustr$(eax)
    print chr$(13,10)
    invoke testproc,1,2
    print ustr$(eax)
    print chr$(13,10)
    invoke testproc,1,2,3
    print ustr$(eax)
    print chr$(13,10)
    mov   eax,input(13,10,"Press enter to exit...")
    exit

    testproc proc C args:VARARG
        mov   eax,[ebp+4]
        movzx eax,BYTE PTR[eax+2]
        shr   eax,2
        ret
    testproc endp
; ««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
end start

eschew obfuscation

MazeGen

Thanks Michael,
I simply love your ready-to-compile examples  :U

But your method is rather tricky. It fails at least if:

  • the compiler will emit SUB ESP,-x instead of ADD ESP,x
  • the compiler will use some optimizations and the stack is adjusted later after few calls
  • the code page will be not readable

I believe there is some safe and documented way instead.

rea

Perhaps this one can help http://217.160.247.193/index.php?topic=16474.0


But watching at it, I think now that have a error :P, Im to lazy for do test??? :).


By the way, the function normally dosent know how many arguments you will pass, but normally there exist a "centinel" (or any like is called) where you can "know" at runtime how many arguments are passing, for example the string formatting "hola %s I have %d years old." here the function know that you have two arguments, one is a pointer (4b) and the other a integer (xb).

Also when you make a function that have a "format" for example only recieve integers, or all the arguments are integers escept the last one that is a real8, you should know what your function will do for handle the varargs, in this cases where is "not necesary" the size/type of the arguments because you before have maked the choice (diferent than a thing like the formatting string) is only necesary to know how many arguments you wil have to handle in the function.



By the way, like proposed that time, you "can" make a autoadjustable vararg call, some like this:


mov eax, esp
invoke AddressOfFunction, arg1, arg2, arg3, ....., argn
sub esp, register
.
.
.
AddressOfFunction:
sub eax, esp
sub eax, 4 ; the return address is "deleted" when return
sub esp, 4
mov [esp], eax ; save the "distance"
sub esp, SizeOfLocals
; The anterior lines for allocate local space+ sizeOfArguments can be joined :P 4+SizeOfLocals and watching where is the location of the "distance"
.
.
; do things here
.
.
mov register, [esp+SizeOfLocals] ;get in register the "distance"
add esp, SizeOfLocals+4
ret



Perhaps a dirty way, but I supose work ok ;).

There is added 3 instruction at the start of each rutine like this and 1 extra instruction at the end and trashed a extra register at return, and around the call, there are added other 2 instructions... In total 6 extra instructions for have a automatic balancing of stack...


Perhaps make more clear the things ;).

PellesC

As already stated, the C compiler will not do anything special regarding the argument count. It's handled through an agreement between the caller and the callee (function). Either you pass a counter as one of the argument, usually the first, or you pass a format string, that indirectly will tell you the number of arguments...

Pelle

MazeGen

Hello rea,
thanks for your contribution. As for the "autoadjustable" call, it seems to me like too specific way of calling in multi-language envirovment. But it is interesting  :8)

Hello Pelle
I know you code C compiler, so you have to know something about it :toothy You've reassured me that there is no one standard way. I'll use the method recommended by the programmer's guide.