_stdcall and _cdecl are only used to know in what way the compiler should do the passing of arguments, where you should use is extern "C" nameOfFuntion(arguments);

or a block one with the names that you whant to be exported with the C decoration.

extern "C"{}

Have a nice day or night.
Posted on 2004-06-07 08:20:10 by rea
Maybe I should clarify my situation. I understand __stdcall and __cdecl, I understand when to use extern "C" also. What I want to build/achieve is a .lib file (object library) with 1 particular function in it. The function must use __stdcall naming convention, eg. _center@8. I've tried adding __stdcall to the function declaration, but it still produces a __cdecl naming convention file. All I do, very simple! I create a .cpp file with this code in it:
__stdcall Center(unsigned int sDim, unsigned int wDim)

{
return (unsigned int) (sDim - wDim) / 2;
}
I don't add anything else, no headers, nothing! But when I compile (and lib.exe the file) and dumpbin.exe the resulting .lib file, the _center@8 function is listed as ?Center@@YGHII@Z under "public symbols". My assembler version is perfect! And I can call it from C code! Also, further down the file, the __cdecl 'syntax' of the function is listed as "int __stdcall Center(unsigned int,unsigned int))".
Posted on 2004-06-07 08:57:24 by SubEvil
the decorated names you get is not because of __cdecl calling convention - it's because of C++ name decoration. You will need to add a function prototype before declaring the function, and put that in a extern "C" block...



extern "C" __stdcall Center(unsigned int sDim, unsigned int wDim);

__stdcall Center(unsigned int sDim, unsigned int wDim)
{
return (unsigned int) (sDim - wDim) / 2;
}

(using a single extern "C" and not a block here, as there's only one function)
Posted on 2004-06-07 09:07:49 by f0dder
You could also rename file.cpp to file.c ;)
Posted on 2004-06-07 09:14:32 by Scali
my sincere apologies, i was half-asleep when i posted that snippet.
Yes, i forgot about return values, how stupid of me! it should, instead, be something like this:



center:
pop ebp
pop ecx
pop eax
sub eax,ecx
shr eax,1
push ebp
ret


that should handle it. Also, i never really knew what the prologue and epilogue options did, now i do :)
Posted on 2004-06-07 12:45:30 by Drocon
Hmm, popping the EIP-value, then pushing it and RET'ing... won't that affect speculative decoding, especially the CALL+RET stuff in P4's?
Posted on 2004-06-07 12:50:03 by f0dder
pop ebp is NOT a good idea.
You destroy the stackframe of the calling function.
And even if you would use pop reg, why don't you do jmp reg instead of push ret?
Posted on 2004-06-07 13:07:01 by Scali
damn, another error. c convention requires ebp to be preserved. change ebp to another register, like edx.
heh, i'm so silly. :grin:

there's no particular reason i use push/ret opposed to jmp reg. both are 2 bytes long ;) ret just gives me a sense of closure :rolleyes:




center:
pop edx
pop ecx
pop eax
sub eax,ecx
shr eax,1
push edx
ret
Posted on 2004-06-07 13:14:50 by Drocon
c convention doesn't say anything about register preservation (like, duh) - however, win32 (and linux and most other 32bit OSes prolly follow the same rules) do. So, popping return-eip to edx? You tie up a register, have to save it if you are going to call external code, etc... plus this method of returning is probably more expensive than a normal ret. What's the point? Ok, small code... but small != fast :)
Posted on 2004-06-07 13:21:05 by f0dder
i meant vc++ convention. It requires that ebx edi esi and ebp be preserved (but ebp is unusable under normal circumstances...), the rest are trashed. almost all of the win32 APIs were done using the VC++ compiler, thus if you are to call any other API, only those 4 will be preserved. It's best to follow this convention, so ebp should be preserved (even in masm, since it's used as stack frame).
Posted on 2004-06-07 13:25:15 by Drocon
It's not just VC++ convention, it's operating system convention... and you'll see the same not just under win32, but other OSes as well - and it makes sense.
Posted on 2004-06-07 13:28:08 by f0dder
Thanx guys, got it working, very confusing! These issues of 'name mangling', calling convention etc. Anyway, I have another questions, why, when I write this:
__stdcall unsigned int Center(unsigned int sDim, unsigned int wDim)
Do I get these warnings and errors?:
C:\Dev\C++\Projects\TestLib\main.cpp(21) : warning C4518: 'unsigned int ' : storage-class or type specifier(s) unexpected here; ignored

C:\Dev\C++\Projects\TestLib\main.cpp(21) : warning C4230: anachronism used : modifiers/qualifiers interspersed; qualifier ignored
C:\Dev\C++\Projects\TestLib\main.cpp(22) : error C2556: 'int Center(unsigned int,unsigned int)' : overloaded function differs only by return type from 'unsigned int Center(unsigned int,unsigned int)'
C:\Dev\C++\Projects\TestLib\main.cpp(9) : see declaration of 'Center'
C:\Dev\C++\Projects\TestLib\main.cpp(22) : error C2371: 'Center' : redefinition; different basic types
C:\Dev\C++\Projects\TestLib\main.cpp(9) : see declaration of 'Center'
The compiler won't allow me to specify a 'return type', it defaults to int, I'm scared it will make some strange transformations etc. Also, when I write a 'void' function, the compiler forces me to specify a return value? I'm scared it will then go and load 'something' into eax! What gives, how damn limited is this compiler?
Posted on 2004-06-08 02:22:46 by SubEvil
The compiler is doing its job. The calling convention is _not_ a storage class modifier. To understand how calling convention is different from storage classes, it may be helpful to dig up old DOS compiler books, where all those confusing near/far/interrupt modifiers to the calling convetion are explained in detail. Say, when you don't get confused by char far *near f(int), you know where is the right place to put __stdcall.
Posted on 2004-06-08 03:30:22 by Starless
change it to



unsigned int __stdcall Center(unsigned int sDim, unsigned int wDim)
Posted on 2004-06-08 04:09:20 by stormix
Thanx stormix! Worked like a charm. Any idea how to do the same thing to a 'structure' variable? eg:
	struct Application {

HINSTANCE hInstance;
HANDLE Heap;
long ScreenWidth;
long ScreenHeight;
MSG msg;
SYSTEM_INFO SystemInfo;
} __stdcall App;

I've tried:
struct __stdcall Application {


and

struct Application __stdcall {

and

__stdcall struct Application {
All without success! :( All I want is the compiler to generate a variable name in the .obj file like this "_App" instead of ?App@@3UApplication@@A

Thanx!
Posted on 2004-06-08 06:18:12 by SubEvil
It's getting more and more like a C help thread. Why don't we move this to heap and discuss more about C storage class and C linkage in C++? And, you need to review the storage class modifier, which does _not_ include __stdcall.
Posted on 2004-06-08 08:14:51 by Starless
Sorry dude ;)

Actually, I'd prefer to have a C/C++ Forum here :D. Anyway, I must confess, assembler was much easier to implement, but I got it working in any event!

Regards!
Posted on 2004-06-08 09:15:57 by SubEvil
A struct is not a function, hence it cannot be called, and calling conventions do not apply. So __stdcall or anything else should not be used there.
You want extern "C" as said before, to disable the C++ namespaces and the name decorations that go with it.
Posted on 2004-06-08 09:26:40 by Scali
Should work some like:



struct Application {
HINSTANCE hInstance;
....
SYSTEM_INFO SystemInfo;
};

extern "C" struct Application app;


Also see that the onmly to be exported is the start in memory in the object file, without C++ decoration, for know the 'offsets' of each member you need to convert the struct declaration to the assembler of your choice (masm).

Have a nice day or night.
Posted on 2004-06-08 10:05:20 by rea