I've got questions about calling and conventions of masm procs from c/c++..

Using MemCopy.asm as my test proc cauz it is simplistic yet functional:

1.) extern "C" __cdecl void MemCopy(char *, char *, long);
will give me a 'memory read error', if I specify __stdcall then it runs fine. What gives, am I not cleaning up the stack properly, and if I am not then how do I?

2.) does my 'void MemCopy()..' tell the c++ compiler that this function returns nothing? I assume it is correct and seems like a silly question. The 'ret' in the asm proc I am guessing is returning control of the code back to the program although control was never really given away ;)

3.) what is the difference between cdecl and stdcall, I have researched this until I had headaches because every single answer I found is different is some respect. From what I thought and gathered, stdcall is for making use of the C runtime library (msvcrt) and the cdecl is for not. I would prefer for the not. wsprintf does not but you have to clean up the stack... where could I find info on cleaning up the stack (see question 1)? sprintf is part of the c runtimes and therefore needs to stack cleaning? am i confused yet?

Any help is greatly appreciated.
Posted on 2003-04-11 03:08:30 by drarem
The reason you gotta use __stdcall is because of this line in memcopy.asm
.model flat, stdcall

stdcall means that the callee cleans up the stack, and cdecl means the caller cleans up the stack.

So when you specified __cdelc for memcopy, the memcopy function cleaned up the stack (because its defined as stdcall in memcopy.asm), then c++ generated some code to clean up the stack (because you told c++ it was cdelc). So you cleaned up the stack twice, hence the memory problem.

Dont get confused by the void thingie in c++, a function's return value is whatever value is currently in the eax regester... since the eax regester is always there, and always contains some value, then every function returns a value... all the 'void' in c++ does, is tell the c++ compiler that the return value of that function should not be used for anything... so its basically error checking, just like the other 90% of c++ is.

I dont know anything about the c library stuff, but i can tell you why wsprintf cannot use stdcall. wsprintf takes a variable number of arguments so there is no way for wsprintf to clean up the stack. Just think if you were tasked to write the function wsprintf... how many bytes would you add to esp at the end of the procedure? 12 would work if only 3 arguments were passed... but what if the caller passed 4 arguments instead of 3? then you would have to add 16 bytes... one solution is to make a bunch of different versions of wsprintf, like 'wsprintf3 (3 arguments)', 'wsprint4', 'wsprintf5', etc.... but its more efficient just to make the caller of the function clean up the stack, since it will know how many arguments it passed in the first place.


push arg3
push arg2
push arg1
call wsprintf
add esp, 12 ; i know i passed 3 arguments, therefore i know to add 12 bytes...

push arg4
push arg3
push arg2
push arg1
call wsprintf
add esp, 16 ; this time i passed 4 arguments, so i gotta add 16... its impossible
; for the wsprintf function to clean up the stack, because the number
; that must be added to esp each time changes.... hurray for cdelc
Posted on 2003-04-11 03:53:46 by BubbaFate
thank you for your quick reply.. then how would I use cdecl in the memcopy.asm file?

If I have it declared like:
.386
.model flat, cdecl
option casemap :none ; case sensitive

it give me a syntax error, cdecl not recognized. What am i missing, besides my brains?
Posted on 2003-04-11 15:44:12 by drarem
The acceptable parameters are C, BASIC, FORTRAN, PASCAL, SYSCALL, or STDCALL.

C is the equivalent to c++'s __cdelc.
Posted on 2003-04-11 15:48:18 by BubbaFate
thank you for helping clear some things up for me. it executes clean now.
Posted on 2003-04-11 15:58:23 by drarem