[fpc-pascal] Mozilla XPCOM

José Mejuto joshyfun at gmail.com
Mon Jun 7 17:11:17 CEST 2010


Hello FPC-Pascal,

Monday, June 7, 2010, 4:25:59 PM, you wrote:

>> It is "silently" changed by stdcall do not ?
JM> It is completely ignored. So it is the same as the default calling
JM> convention (which is register on i386, and stdcall=register=cdecl=...
JM> on other platforms).

Wow, that looks "dangerous" at least it should produce a warning when
used in interfaces, or as safecall is a form of stdcall (with return
values check) replace by stdcall.

>> JM> a) the result is passed as a hidden parameter by reference
>> JM> b) the actual function results becomes an error code
>> Plain function result is in EAX, if I call (in ASM) QueryInterface
>> with garbaged IIDs I get "$80004002" in the EAX (NOT_INTERFACE). Just
>> the same as in Windows using safecall except the stack clean.

The functions declared in the interfaces now with "cdecl" crashes the
program as the stack remains unbalanced after call due extra 4 bytes
in it, which i think it is the "hidden parameter result".

JM> Ok. In the mean time I found some more info about how XPCOM works:
JM> http://benjamin.smedbergs.us/blog/2008-09-26/allocated-memory-and-shared-library-boundaries/
JM>   : apparently, all code that makes use of XPCOM via C/C++ is supposed
JM> to be written in IDL, which is then transformed into C++ code that
JM> conforms to the safecall conventions (apart from the caller rather
JM> than the callee cleaning up).

Yes, that's the "whole picture".

>> To check this I must compile something with GCC and I do not have it
>> installed and I do not have a source to compile with it. I should
>> investigate following other paths.
JM> At first sight that does not happen in XPCOM, even on Windows (but
JM> since we do it on Windows, maybe we should also do it elsewhere for
JM> consistency reasons).

Maybe, but that's not a great problem, maybe do it only in the case of
"Verify method calls" ?

JM> In C, "const" does not modify how a parameter is passed in any way. If
JM> a parameter is passed by value without "const", then it's also passed
JM> by value with "const". The problems are
JM> a) in Pascal, the behaviour of const is completely undefined (the
JM> compiler can do whatever it wants)
JM> b) a lot of people use Pascal "const" as translation for C's "const *"
JM> for record parameters, which is wrong (but which sometimes works by
JM> accident)

Yes, but removing the "const" still passes the parameter as 16 bytes,
and defining it as "var" creates problems when passing an interface to
extract the GUID instead passing the interface reference. Anyway most
of this problems are quite easy to be bypassed with some source
changes which still remain compatible between windows and linux.

The great problem now is the extra parameter in the stack which
imposes me to wrap all interfaces in some kind of assembler functions
to compensate the stack.

JM> Moreover, in FPC not all platforms consistently treat const record
JM> parameters the same as a regular parameters for cdecl (at least ARM
JM> currently always passes const records by reference for some reason).
JM> In short: "const" is a mess as far as predicting how it affects  
JM> passing record parameters, and hence it should never be used in record
JM> parameter declarations for external C functions.

I understand, but now the question is which one to use instead ? const
passes 16 bytes, var does not allow to pass a constant and no
definition passes also 16 bytes. Maybe use a formal parameter ?

>> I'm asking because now I have changed
>> my interface definition to use PGUID instead (both windows and linux)
>> and it works more or less, but now I have a problem in the
>> TInterfacedObject which seems to be the cause of some crashes, but I
>> can not say by now if it is related to XPCOM exposing a different
>> "IUnknown" (maybe cdecl instead stdcall) or TGUID related. I'll
>> investigate further.
JM> I think that nobody who understands both on the code generator and the
JM> RTL side of COM interfaces ever worked on XPCOM interoperability on
JM> non-Windows.

This has been solved the "QueryReferent" function must be stdcall and
pass TGUID because it is being called by fpc.

>> One question, is there any way in fpc to "define" the calling
>> convention as a C define ? Just something like:
JM> Yes, it is possible with {$macro on}. Example from the opengl unit:
JM> {$MODE Delphi}
JM> {$MACRO ON}
JM> {$IFDEF Windows}
JM>    {$DEFINE extdecl := stdcall}
JM> {$ELSE}
JM>    {$DEFINE extdecl := cdecl}
JM>    {$IFDEF MorphOS}
JM>      {$INLINE ON}
JM>      {$DEFINE GL_UNIT}
JM>    {$ELSE}
JM>      {$LINKLIB c}
JM>    {$ENDIF}
JM> {$ENDIF}
JM> ...
JM> var
JM>    glAccum: procedure(op: GLenum; value: GLfloat); extdecl;

Ok, I'll use it. I hate macros, but this time they seems quite useful.

JM> I'm personally not really interested in fixing this whole mess though.
JM> I spend a lot of time in the past disabling safecall in the compiler
JM> for all non-Windows platforms because it always generated wrong code
JM> elsewhere. Now it seems it should be
JM> a) enabled everywhere, and then
JM> b) fixed for all platforms, which requires modification to the  
JM> parameter managers of most architectures (since most don't contain any
JM> support for safecall)

That looks as a hard job :( I can only help testing XPCOM in both
windows and linux, but I doubt that I can help in the compiler side :(

Maybe it is possible in some way to define some kind of plugable
calling convention generator ? Just like a script to define the
calling convention when it is not any of the standard ? Thinking
again, it does not look like a great idea :( Now I must think in how
to solve the extra integer in the stack when calling functions :(

-- 
Best regards,
 José




More information about the fpc-pascal mailing list