From: Kenny Tilton
Subject: stdcall vs c vs cdecl vs pascal vs whosyerdaddy
Date: 
Message-ID: <3E5D1D10.10803@nyc.rr.com>
I was compiling all this to ask a question, kinda think I answered it 
along the way (pascal means stdcall) but then figured, what the hell, 
someday someone struggling with FFI may be searching Google....

MicroSoft MSDN (hissssssss):
"cdecl:
This is the default calling convention for C and C++ programs. Because 
the stack is cleaned up by the caller, it can do vararg functions. The 
__cdecl calling convention creates larger executables than __stdcall, 
because it requires each function call to include stack cleanup code... 
[snip]...Because the C naming and calling conventions are the default, 
the only time you need to use __cdecl is when you have specified the /Gz 
(stdcall) or /Gr (fastcall) compiler option. The /Gd compiler option 
forces the __cdecl calling convention."

and:
"The __stdcall calling convention is used to call Win32 API functions. 
The callee cleans the stack..."

Corman:
"define-foreign-function:
[parameter]linkage-type should be either :c or :pascal, with :c being 
the default. With :c linkage, the called function is not expected to 
remove the parameters from the stack when it returns. With :pascal 
linkage, it is assumed that the called function will remove the passed 
parameters."

[kenny: ok, so Corman :c is MS _cdecl and :pascal is _stdcall]

then under the C->lisp FFI generator:
"pascal
This parameter should be a string or a list of strings (or symbols, in 
which case their names are used). Functions that have one of these 
tokens in their prototype will have :pascal linkage, other functions 
will have the default :c linkage. Very often, working with Win32 
declarations, this parameter would have "WINAPI" as its value.

[Kenny: right, "The __stdcall [aka pascal] calling convention is used to 
call Win32 API functions" even tho cdecl is the MSVC default.]

Lispworks:
"calling-convention
-------------------
Specifies the calling convention used. :stdcall is the calling 
convention used to call Win32 API functions and matches the C
declarator "__stdcall". :cdecl is the default calling convention for
C/C++ programs and matches the C declarator "__cdecl"."

[kenny: thx for not mentioning pascal <g>]

AllegroCL:
"[calling] convention:
This argument allows the specialization of calling conventions due to 
language or operating-system distinctions. The default convention is :c, 
and is adequate for most situations. (Note that on NT and Windows95 the 
c/stdcall convention distinction is required for callbacks using 
defun-foreign-callable, but is not required in def-foreign-call)."

[kt: cool, detected automatically?]

"Other than :c, (the default and suitable for most purposes), the 
:fortran convention is defined. This convention generally causes a 
conversion of most atomic arguments to pass-by-reference."

[kt: thx for not mentioning pascal. now about that "fortran"... <g>]

-- 

  kenny tilton
  clinisys, inc
  http://www.tilton-technology.com/
  ---------------------------------------------------------------
"Cells let us walk, talk, think, make love and realize
  the bath water is cold." -- Lorraine Lee Cudmore
From: Roger Corman
Subject: Re: stdcall vs c vs cdecl vs pascal vs whosyerdaddy
Date: 
Message-ID: <3e5dbcc4.442967293@news.sf.sbcglobal.net>
On Wed, 26 Feb 2003 19:54:13 GMT, Kenny Tilton <·······@nyc.rr.com> wrote:


>AllegroCL:
>"[calling] convention:
>This argument allows the specialization of calling conventions due to 
>language or operating-system distinctions. The default convention is :c, 
>and is adequate for most situations. (Note that on NT and Windows95 the 
>c/stdcall convention distinction is required for callbacks using 
>defun-foreign-callable, but is not required in def-foreign-call)."
>
>[kt: cool, detected automatically?]

You don't really need to detect it. If you just stash the esp (stack pointer)
value somewhere (pretty much anywhere but on the stack) before pushing arguments
(or afterward, but storing the value the stack pointer had prior to pushing the
arguments), and then restore it when the call returns, you will be OK. If it was
a cdecl, then restoring esp clears the arguments. If the caller cleared them
(__stdcall), then it's a noop. 

The only thing that can be tricky is finding an appropriate place to stash the
stack pointer. If you are not running multi-threaded a global variable will
probably work. Otherwise you need a per-thread slot or a  register. Functions in
Windows are required to maintain edi, esi and ebp (and I think ebx).

However:
Callbacks still need the correct declarations because the caller is not
necessarily going to be as flexible (you don't control it). It is going to
assume you left the stack pointer positioned correctly and may not restore it.

Also, callbacks open up the possibility that you may call into foreign functions
recursively, so the per-thread storage slot becomes a stack, and unwinding can
mess things up. A save register is probably the best bet.

In Corman Lisp I didn't do this, and just prefer to make the foreign function
programmer use the right declaration. Since any errors in the declaration pretty
much wreck the call, it's just one more detail. 
Roger Corman
Corman Technologies
www.cormanlisp.com