From: jgrandje AT supelec-rennes DOT fr (Jerome GRANDJEAN) Subject: using a Cygnus dll with VC++ : impossible ? 6 Jun 1998 07:27:21 -0700 Message-ID: <01bd90d0$f4097620$922846c0.cygnus.gnu-win32@JEROME.supelec-rennes.fr> Mime-Version: 1.0 Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: 7bit To: "Cygnus List" Hi, I have some questions and observations about using a dll made by using Cygnus with MS VC++. 1. First, I never manage to use the functions malloc, free, realloc in my dll. I had to use pointer instead, and Initialized them in my VC progam with functions malloc, realloc and free of VC. This prevent me from using system functions which use malloc, realloc or free, like fdopen, sscanf... I don't know if this is a normal behaviour or not. 2. The struct FILE are totally different, so you can't call a function using you VC FILE* or VC std[in/out]. 3. Moreover, Cygnus doesn't seem to call functions the same way as VC does : For instance, with the declarations : typedef struct { int n1; int n2; int n3; int n4; } quad; quad Associe(int n1, int n2, int n3, int n4) // function with complex result { quad pRes; pRes.n1=n1; pRes.n2=n2; pRes.n3=n3; pRes.n4=n4; return(pRes); } int nRendPreums(int,int); // function with simple argument In my program, I get : for the simple function : ------- with Cygnus 46 nI=nRendPreums(1,2); 0x4011ef : pushl $0x2 0x4011f1 : pushl $0x1 0x4011f3 : call 0x40159c 0x4011f8 : addl $0x8,%esp 0x4011fb : movl %eax,%eax 0x4011fd : movl %eax,0xfffffff4(%ebp) -- with VC++ 74: nTest=nRendPreums(1,2); 004012A4 push 2 004012A6 push 1 004012A8 call dword ptr [_nRendPreums(0x00416fdc)] 004012AE add esp,8 004012B1 mov dword ptr [nTest],eax ------- and for the complex function : ------- with Cygnus : 52 MonQuad=Associe(1,2,3,4); 0x4011f7 : leal 0xfffffff0(%ebp),%eax 0x4011fa : pushl $0x4 0x4011fc : pushl $0x3 0x4011fe : pushl $0x2 0x401200 : pushl $0x1 0x401202 : pushl %eax // the address of MonQuad is stored on the stack before calling Associe 0x401203 : call 0x401040 0x401208 : addl $0x10,%esp -- with VC++ 78: MonQuad=Associe(1,2,3,4); 004012A9 push 4 004012AB push 3 004012AD push 2 004012AF push 1 004012B1 lea ecx,dword ptr [ebp-54h] 004012B4 push ecx 004012B5 call @ILT+25(?Associe@@YA?AUquad@@HHHH AT Z)(0x00401019) // call to Associe 004012BA add esp,14h 004012BD mov edx,dword ptr [eax] // the 1st result value is stored in edx 004012BF mov dword ptr [ebp-44h],edx // then put on the stack 004012C2 mov ecx,dword ptr [eax+4] 004012C5 mov dword ptr [ebp-40h],ecx // idem for 2nd result with ecx 004012C8 mov edx,dword ptr [eax+8] 004012CB mov dword ptr [ebp-3Ch],edx // idem for 3rd, edx 004012CE mov eax,dword ptr [eax+0Ch] 004012D1 mov dword ptr [ebp-38h],eax // and the 4th, eax 004012D4 mov ecx,dword ptr [ebp-44h] 004012D7 mov dword ptr [MonQuad],ecx // MonQuad.n1 is set 004012DA mov edx,dword ptr [ebp-40h] 004012DD mov dword ptr [ebp-1Ch],edx // MonQuad.n2 too 004012E0 mov eax,dword ptr [ebp-3Ch] 004012E3 mov dword ptr [ebp-18h],eax // MonQuad.n3 004012E6 mov ecx,dword ptr [ebp-38h] 004012E9 mov dword ptr [ebp-14h],ecx // MonQuad.n4 --------- Here, functions are _cdecl, but the result is the same with __stdcall functions (exect for the "add xxx, esp") So, for function whose result is not longer than 32 bits (the length of a register), wa can see than the call is done the same way : - The arguments are put on the stack from right to left - The result is store in eax However, if the result is larger than 32 bits, Cygnus and VC++ don't behave the same way : - after the arguments, Cygnus put on the stack the address of the object modified by the function. - VC doesn't. Instead, the address of the result is stored in eax. After the call, the result is store in the object. This means that a VC function can't call a Cygnus function whose result is larger than a register (larger than an int or a pointer). Moreover, this test was made in debug mode for both sides. I don't know what the optimisations could change in the way arguments are stored on the stack. As I'm not a crack about C, compilers and Windows, I still ahve a few questions : - Is there any standard for calling a function in a Windows'dll ? - Is there another keyword which could make one of the compiler behave like the other ? Today, it seems to me that I must have in my dll functions that don't use malloc directly or inderectly but import such functions (for instance, I import within a dll malloc, realloc free and sscanf, with other names of course), and that returns only pointer on struct and not struct themselves. Of course, you can also rewrite a function in VC++ with an _asm section calling your function the good way, it seems to work fine. Well, that's all, I hope that someone could say me if I really missed something, for the memory functions and for functions call, and then explain how to make VC and Cygnus work one with the other simply. Bye -------------------------------------------------------------- Jerome GRANDJEAN SUPELEC Email : jgrandje AT supelec-rennes DOT fr 51 bis Bd de Sevigne Tel : 02.99.38.20.77 35700 RENNES TAM TAM : 06.01.43.57.60 FRANCE - For help on using this list (especially unsubscribing), send a message to "gnu-win32-request AT cygnus DOT com" with one line of text: "help".