www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - D's exact stack convention for D and C/C++

reply Adam Sansier <Adam.Sansier gmail.com> writes:
I am trying to debug some really messed up code that makes no 
sense. It calls in some code that doesn't seem to be using the 
standard calling convention. The function definitions are exactly 
the same in both D and C++.

->func(param1, param2, param3, param4);

The call stack setup by C++ before the call is

001fa18d 002aff3c 00000014 000000c0 002b10f8 00c7fa34 001f16cc 
7f383000

The order is ret EIP, param1, param2, param3, param4, this

For D(naked asm)

00403ff3 002dc108 000000c0 00000014 002e73e8 026236f0 02ae4a78 
0019fe54

The order is ret EIP, param4, param3, param2, param1,

as one can see, the order is reversed. The functions are declared 
exactly the same in C++ and D(I just copied to D and marked 
extern(C++). It is part of a method(It is COM but that shouldn't 
matter?)).

Forget all that, What I'm really interested in is the exact 
calling conventions used in D and C and C++ and what they mean so 
I can make sure I know whats going on, cause something funky is 
happening and it's not on my end(I'm not messing with the order 
of this stuff directly).

So,

extern(C) = ?
extern(D) = ?
extern(C++) = ?
extern(Windows) = ?

C++ standard convention = ?
C standard convetion = ?
D standard convention = ?

Also, how is this pointer passed in method calls? ECX? Stack? If 
Stack, first or last? Does it change with calling convention?

I'm looking for only the facts, hopefully from the man himself.
Jul 16 2016
next sibling parent Joakim <dlang joakim.fea.st> writes:
On Sunday, 17 July 2016 at 01:30:31 UTC, Adam Sansier wrote:
 I am trying to debug some really messed up code that makes no 
 sense. It calls in some code that doesn't seem to be using the 
 standard calling convention. The function definitions are 
 exactly the same in both D and C++.

 ->func(param1, param2, param3, param4);

 The call stack setup by C++ before the call is

 001fa18d 002aff3c 00000014 000000c0 002b10f8 00c7fa34 001f16cc 
 7f383000

 The order is ret EIP, param1, param2, param3, param4, this

 For D(naked asm)

 00403ff3 002dc108 000000c0 00000014 002e73e8 026236f0 02ae4a78 
 0019fe54

 The order is ret EIP, param4, param3, param2, param1,

 as one can see, the order is reversed. The functions are 
 declared exactly the same in C++ and D(I just copied to D and 
 marked extern(C++). It is part of a method(It is COM but that 
 shouldn't matter?)).

 Forget all that, What I'm really interested in is the exact 
 calling conventions used in D and C and C++ and what they mean 
 so I can make sure I know whats going on, cause something funky 
 is happening and it's not on my end(I'm not messing with the 
 order of this stuff directly).

 So,

 extern(C) = ?
 extern(D) = ?
 extern(C++) = ?
 extern(Windows) = ?

 C++ standard convention = ?
 C standard convetion = ?
 D standard convention = ?

 Also, how is this pointer passed in method calls? ECX? Stack? 
 If Stack, first or last? Does it change with calling convention?

 I'm looking for only the facts, hopefully from the man himself.
According to the spec, "The extern (C) and extern (D) calling convention matches the C calling convention used by the supported C compiler on the host system." https://dlang.org/spec/abi.html There are tests for C and C++ compatibility that you can look at, from the compiler testsuite: https://github.com/dlang/dmd/blob/master/test/runnable/cpp_abi_tests.d https://github.com/dlang/dmd/blob/master/test/runnable/cppa.d https://github.com/dlang/dmd/blob/master/test/runnable/cabi1.d The corresponding C/C++ files can be found here: https://github.com/dlang/dmd/tree/master/test/runnable/extra-files
Jul 16 2016
prev sibling next sibling parent Guillaume Piolat <first.last gmail.com> writes:
On Sunday, 17 July 2016 at 01:30:31 UTC, Adam Sansier wrote:
 Forget all that, What I'm really interested in is the exact 
 calling conventions used in D and C and C++ and what they mean 
 so I can make sure I know whats going on, cause something funky 
 is happening and it's not on my end(I'm not messing with the 
 order of this stuff directly).
If you don't use naked asm, you won't have to know this. And you get other benefits like being able to use the same x86 code across OSes (and sometimes across x86 and x86_64). The problem with calling conventions is that they can be sublty different eg. between OS X and Linux 64-bit. It's a big trap that is worth avoiding.
Jul 17 2016
prev sibling parent bitwise <bitwise.pvt gmail.com> writes:
On Sunday, 17 July 2016 at 01:30:31 UTC, Adam Sansier wrote:
 I am trying to debug some really messed up code that makes no 
 sense. It calls in some code that doesn't seem to be using the 
 standard calling convention. The function definitions are 
 exactly the same in both D and C++.

 ->func(param1, param2, param3, param4);

 The call stack setup by C++ before the call is

 001fa18d 002aff3c 00000014 000000c0 002b10f8 00c7fa34 001f16cc 
 7f383000

 The order is ret EIP, param1, param2, param3, param4, this

 For D(naked asm)

 00403ff3 002dc108 000000c0 00000014 002e73e8 026236f0 02ae4a78 
 0019fe54

 The order is ret EIP, param4, param3, param2, param1,

 as one can see, the order is reversed. The functions are 
 declared exactly the same in C++ and D(I just copied to D and 
 marked extern(C++). It is part of a method(It is COM but that 
 shouldn't matter?)).

 Forget all that, What I'm really interested in is the exact 
 calling conventions used in D and C and C++ and what they mean 
 so I can make sure I know whats going on, cause something funky 
 is happening and it's not on my end(I'm not messing with the 
 order of this stuff directly).

 So,

 extern(C) = ?
 extern(D) = ?
 extern(C++) = ?
 extern(Windows) = ?

 C++ standard convention = ?
 C standard convetion = ?
 D standard convention = ?

 Also, how is this pointer passed in method calls? ECX? Stack? 
 If Stack, first or last? Does it change with calling convention?

 I'm looking for only the facts, hopefully from the man himself.
Is this a member function or global function that you're talking about? If you mean that you made a D class and then marked the function extern(C++), I don't believe that is the correct way to do it. You need to use an interface instead of a class in D, as described here: https://dlang.org/spec/cpp_interface.html I'm not sure if it has been fixed at this point, but classes with virtual destructors were not working for me last time I used this stuff. If it's a global function, then you could try changing it to extern(C) instead, and your mark your C++ functions extern"C". extern(C++) seemed to be giving me compiler-dependant difficulties last time I tried it. Bit
Jul 17 2016