November 01, 2006
Is D's functions calling convention somewhere documented?

I've been tinkering with a reflection module for D.
Gaining access to all dynamic and static symbols is
currently possible as well as calling C functions
(see below) but calling functions with D linkage isn't
yet implemented:

#
# import kuehne.reflection;
#
# int main(){
#    Symbol s = symbols["strlen"];
#
#    char* test = "unter den Birnen";
#    size_t len = 0;
#
#    Argument[] arg = new Argument[1];
#    arg[0].size = test.sizeof;
#    arg[0].data = &test;
#
#    Argument[] result;
#    result = s.call(CallingConvention.C, arg);
#    foreach(x; result){
#    	if(x.type == "<?>"){
#    		len = *(cast(size_t*) x.data);
#    		break;
#    	}
#    }
#
#    printf("strlen('%s') -> %zu", test, len);
#    return 0;
# }

output:
>
> strlen('unter den Birnen') -> 16
>

Thomas


November 01, 2006
Thomas Kuehne wrote:
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
> 
> Is D's functions calling convention somewhere documented?

Not really. It's callee clean stack, args pushed right to left, last arg passed in EAX.
November 01, 2006
Walter Bright wrote:
> Thomas Kuehne wrote:
>> -----BEGIN PGP SIGNED MESSAGE-----
>> Hash: SHA1
>>
>> Is D's functions calling convention somewhere documented?
> 
> Not really. It's callee clean stack, args pushed right to left, last arg passed in EAX.

Could you please copy & paste that into the "Function Calling Conventions" part of the ABI page on the spec? It's better than nothing.
And maybe add 'this pointer passed in EBX' (if that's true).
November 01, 2006
On Wed, 01 Nov 2006 05:40:18 -0500, Walter Bright <newshound@digitalmars.com> wrote:

> Thomas Kuehne wrote:
>> -----BEGIN PGP SIGNED MESSAGE-----
>> Hash: SHA1
>>  Is D's functions calling convention somewhere documented?
>
> Not really. It's callee clean stack, args pushed right to left, last arg passed in EAX.

Can you please explain some more...

For variadic functions, the caller probably cleans up and the last arg not put in EAX.

What if the last arg does not fit in EAX; e.g. a char[], is half put in EAX / half on the stack, or all on the stack?

Return value: EAX, or also I believe EAX and EDX for 64-bit values.

Returning floating point: in floating point register?

Bigger return types probably first push a pointer to a return buffer?

Variadic TypeInfo[] _arguments pushed last or first or something else?
November 01, 2006
> I've been tinkering with a reflection module for D.

Attached is rudimental reflection module for D.

limitations:
* only supported on *nix systems (porting to Windows should be straight forward)
* read permissions required in addition to execution permission for finding symbols
* the symbol sizes generated by DMD are defective, thus no class/struct support
* the D calling convention is undocumented, thus unsupported

license:
ZLIB

Thomas


November 01, 2006
"Chris Miller" <chris@dprogramming.com> wrote in message news:op.tib3szvnpo9bzi@tanu...
> Can you please explain some more...

Here's all that I've researched:

DMD FUNCTION CALLING CONVENTION:

params are passed, in general, l-to-r.

in functions with varargs, all params are passed r-to-l, and are all pushed. varargs also push the _arguments array as the last (furthest left) param. caller is responsible for cleaning up params to vararg function.

typesafe variadic functions just take an array as their variadic arg; the
array is
built by the caller and passed as a regular array - because it's basically
a non-vararg function, params are passed l-to-r.

all kinds of ints, pointers, class refs, bools, char, wchar, dchar, func
pointers:
 if not last, push; else, put in EAX

longs:
 push hi, push lo

float, ifloat:
 push

double, idouble:
 push hi, push lo

real, ireal:
 push really hi, push hi, push lo

cfloat:
 push float im, push float re

cdouble:
 push double im, push double re

creal:
 push real im, push real re

arrays:
 push pointer (hi), push length (lo)

delegates:
 push address, push context ptr ('this' or frame ptr)

structs:
 push the whole damn thing, starting at the beginning

D METHOD CALLING CONVENTION:

Similar to above, with following differences:

all kinds of ints, ptrs, refs etc:
 push

'this' goes into EAX

D DELEGATE CALLING CONVENTION:

put context in both EAX and EBX -- EBX is not actually used in the delegate
though
put address in EDX
call EDX

> For variadic functions, the caller probably cleans up and the last arg not put in EAX.

Right.

> What if the last arg does not fit in EAX; e.g. a char[], is half put in EAX / half on the stack, or all on the stack?

It's pushed entirely.

> Return value: EAX, or also I believe EAX and EDX for 64-bit values.

I'm pretty sure longs are put in EDX:EAX as you say.

> Returning floating point: in floating point register?

Ooh, not sure about that one.

> Bigger return types probably first push a pointer to a return buffer?

Hmm, guess I didn't do much return type research :S

> Variadic TypeInfo[] _arguments pushed last or first or something else?

It's pushed last, so it's technically the furthest-left param (before all other params).


November 01, 2006
Jarrett Billingsley wrote:
> "Chris Miller" <chris@dprogramming.com> wrote in message news:op.tib3szvnpo9bzi@tanu...
>> Can you please explain some more...
> 
> Here's all that I've researched:
> 
[snip]

A great collection! How about tidying it up, and giving the whole thing to Walter to put into the spec?

>> Returning floating point: in floating point register?
> 
> Ooh, not sure about that one.

Yes, they are returned on top of the x87 floating point stack.
This applies to complex types as well:

Example:

// Calculate cos(y) + i sin(y).
creal expi(real y)
{
        asm
        {
            fld y;
            fsincos;
            fxch st(1), st(0);
        }
}
November 01, 2006
Don Clugston wrote:
> Could you please copy & paste that into the "Function Calling Conventions" part of the ABI page on the spec? It's better than nothing.
> And maybe add 'this pointer passed in EBX' (if that's true).

I just uploaded a new http://www.digitalmars.com/d/abi.html with more complete information on the D calling convention.
November 01, 2006
Jarrett Billingsley schrieb am 2006-11-01:
> "Chris Miller" <chris@dprogramming.com> wrote in message news:op.tib3szvnpo9bzi@tanu...
>> Can you please explain some more...
>
> Here's all that I've researched:
>
> DMD FUNCTION CALLING CONVENTION:

Thanks.

> params are passed, in general, l-to-r.
>
> in functions with varargs, all params are passed r-to-l
<snip>

Wouldn't it be easier and less bug prone to use r-to-l for all?

Even unidirectional __cdecl/extern(C) seems hard to implement: "Random Testing of C Calling Conventions"; Christian Lindig; 2005 http://www.st.cs.uni-sb.de/~lindig/papers/quest/quest.pdf

> > Bigger return types probably first push a pointer to a return buffer?
> 
> Hmm, guess I didn't do much return type research :S

Defining that seems to be crucial.
The C++ people have serious problems with structs:

http://www.agner.org/optimize/calling_conventions.pdf

Table 7(methods for returning structure, class and union objects) shows how everybody and his dog uses a different approach.

Thomas


November 01, 2006
That looks a way more complete, great!

On Wed, 2006-11-01 at 11:33 -0800, Walter Bright wrote:
> Don Clugston wrote:
> > Could you please copy & paste that into the "Function Calling Conventions" part of the ABI page on the spec? It's better than nothing. And maybe add 'this pointer passed in EBX' (if that's true).
> 
> I just uploaded a new http://www.digitalmars.com/d/abi.html with more complete information on the D calling convention.

« First   ‹ Prev
1 2
Top | Discussion index | About this forum | D home