www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Linux 64bit Calling Convention

reply "Maxime Chevalier" <maximechevalierb gmail.com> writes:
I'm implementing a JIT compiler and having to call into D 
functions from machine code I generated. Unfortunately, I seem to 
be experiencing a problem where the arguments are passed in the 
reverse order of what I would expect.

The functions I'm calling are global functions with 2 class 
pointer arguments. E.g.:

void foo(ClassA ptrA, ClassB ptrB) { ... }

The ABI page on dlang.org seems to imply that D uses the C 
calling convention on Linux. Now, using the C convention on 
64-bit linux, this should mean that the first class pointer 
(ptrA) get passed in register RDI, and the second one (ptrB) in 
RSI. This is what I would expect but when I actually call a D 
function, the two arguments are reversed.

I understand that this isn't necessarily super clear without 
looking at code, but I just wanted to know if there was something 
obvious I might be overlooking with regards to the D calling 
convention on Linux/AMD64.

Is it because ptrA automatically gets treated as a "this" 
pointer, as if the function were a method of ClassA?
Feb 27 2013
next sibling parent reply "Maxime Chevalier" <maximechevalierb gmail.com> writes:
I did some further testing:

void foo(int a, int b)
{
     writefln("a: %s", a);
     writefln("b: %s", b);
}

unittest
{
     foo(1, 2);

     asm
     {
         mov RDI, 1;
         mov RSI, 2;
         call foo;
     }
}

Produces:

a: 1
b: 2
a: 2
b: 1

Unless I'm mistaken, DMD does not respect the C calling 
convention on Linux/AMD64.
Feb 27 2013
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 2/27/2013 5:03 PM, Maxime Chevalier wrote:
 Unless I'm mistaken, DMD does not respect the C calling convention on
Linux/AMD64.

To use the C calling convention, specify "extern (C)" for the function. BTW, if this did not work, very little of D would work, as there's a lot of reliance on the C standard library and the Linux API functions.
Feb 27 2013
parent Walter Bright <newshound2 digitalmars.com> writes:
On 2/27/2013 6:36 PM, Maxime Chevalier wrote:
 The ABI page (http://dlang.org/abi.html) doesn't make it very clear what
calling
 convention DMD uses by default.

Should file a bugzilla report about that!
Feb 27 2013
prev sibling next sibling parent "Maxime Chevalier" <maximechevalierb gmail.com> writes:
 BTW, if this did not work, very little of D would work, as 
 there's a lot of reliance on the C standard library and the 
 Linux API functions.

The ABI page (http://dlang.org/abi.html) doesn't make it very clear what calling convention DMD uses by default.
Feb 27 2013
prev sibling next sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Thursday, 28 February 2013 at 02:36:07 UTC, Maxime Chevalier 
wrote:
 BTW, if this did not work, very little of D would work, as 
 there's a lot of reliance on the C standard library and the 
 Linux API functions.

The ABI page (http://dlang.org/abi.html) doesn't make it very clear what calling convention DMD uses by default.

Be careful with that page. Other compiler may use other ABI.
Feb 27 2013
prev sibling next sibling parent "Trass3r" <un known.com> writes:
On Thursday, 28 February 2013 at 01:03:08 UTC, Maxime Chevalier 
wrote:
 I did some further testing:

 void foo(int a, int b)
 {
     writefln("a: %s", a);
     writefln("b: %s", b);
 }

 unittest
 {
     foo(1, 2);

     asm
     {
         mov RDI, 1;
         mov RSI, 2;
         call foo;
     }
 }

 Produces:

 a: 1
 b: 2
 a: 2
 b: 1

 Unless I'm mistaken, DMD does not respect the C calling 
 convention on Linux/AMD64.

True. For extern(D) dmd passes parameters in reverse order on Win64 and Linux64! What the heck?
Oct 25 2014
prev sibling next sibling parent "Trass3r" <un known.com> writes:
On Thursday, 28 February 2013 at 02:02:09 UTC, Walter Bright 
wrote:
 On 2/27/2013 5:03 PM, Maxime Chevalier wrote:
 Unless I'm mistaken, DMD does not respect the C calling 
 convention on Linux/AMD64.

To use the C calling convention, specify "extern (C)" for the function.

This is about extern(D).
Oct 25 2014
prev sibling next sibling parent "Trass3r" <un known.com> writes:
Looking at the code extern(D) is in the _revfunc list in optabgen.
Which seems to cause params to be reversed independent of the 
architecture in FuncDeclaration::toObjFile // Reverse params[] 
entries.
Meaning Linux x32 would also be affected.

This totally smells like a remnant as the code matches the 
initial custom Win32 D ABI.
Oct 25 2014
prev sibling next sibling parent "Sean Kelly" <sean invisibleduck.org> writes:
On Saturday, 25 October 2014 at 15:20:53 UTC, Trass3r wrote:
 This totally smells like a remnant as the code matches the 
 initial custom Win32 D ABI.

Yep. I thought the D calling convention matched the C calling convention on 64-bit. Didn't Walter even state this explicitly at some point?
Oct 25 2014
prev sibling next sibling parent "Trass3r" <un known.com> writes:
Yes it's clearly stated on the ABI page (and sane).
Nobody ever noticed cause it's hard to spot this in assembly.
But it was very salient and disturbing in llvm IR.
Oct 25 2014
prev sibling next sibling parent "Trass3r" <un known.com> writes:
https://github.com/D-Programming-Language/dmd/pull/4092
Oct 27 2014
prev sibling next sibling parent "David Nadlinger" <code klickverbot.at> writes:
Ping.

I'm all for the proposal, as it brings DMD and LDC in line with 
what the docs say (or rather do not say) and also with what GDC 
does. However, as this is a breaking change (think naked inline 
asm), I want to be sure that DMD is on board before going through 
with it on our (LDC) side.

Cheers,
David
Nov 14 2014
prev sibling next sibling parent Iain Buclaw via Digitalmars-d <digitalmars-d puremagic.com> writes:
On 25 October 2014 17:14, Trass3r via Digitalmars-d
<digitalmars-d puremagic.com> wrote:
 Yes it's clearly stated on the ABI page (and sane).
 Nobody ever noticed cause it's hard to spot this in assembly.
 But it was very salient and disturbing in llvm IR.

Really? I say this all the time. (OK, maybe not so much over the last 5 or so months :)
Nov 14 2014
prev sibling next sibling parent "David Nadlinger" <code klickverbot.at> writes:
On Friday, 14 November 2014 at 20:19:56 UTC, Iain Buclaw via 
Digitalmars-d wrote:
 Really? I say this all the time. (OK, maybe not so much over 
 the last
 5 or so months :)

Yeah, and if I remember correctly, we both went to DConf 2013 intending to pester Walter about it. Unfortunately, I don't recall if we actually did, or what his response was. David
Nov 14 2014
prev sibling next sibling parent "safety0ff" <safety0ff.dev gmail.com> writes:
On Saturday, 25 October 2014 at 16:14:30 UTC, Trass3r wrote:
 Yes it's clearly stated on the ABI page (and sane).
 Nobody ever noticed cause it's hard to spot this in assembly.

I've hit it a few times, I wasn't sure if it was me or the compiler that was mistaken so I didn't create a report, I just swapped my registers and moved on. On Friday, 14 November 2014 at 19:42:54 UTC, David Nadlinger wrote:
 However, as this is a breaking change (think naked inline asm)

I'm probably not the only user who has adjusted their registers and moved on. As usual, this is the biggest hindrance to fixing the bug, silently swapping the registers between versions is unacceptable.
Nov 14 2014
prev sibling parent Iain Buclaw via Digitalmars-d <digitalmars-d puremagic.com> writes:
On 14 November 2014 20:27, David Nadlinger via Digitalmars-d
<digitalmars-d puremagic.com> wrote:
 On Friday, 14 November 2014 at 20:19:56 UTC, Iain Buclaw via Digitalmars-d
 wrote:
 Really? I say this all the time. (OK, maybe not so much over the last
 5 or so months :)

Yeah, and if I remember correctly, we both went to DConf 2013 intending to pester Walter about it. Unfortunately, I don't recall if we actually did, or what his response was.

Suddenly I have a reason to be vocal about it again. https://github.com/D-Programming-Language/dmd/pull/3670 You wouldn't need to swap around the parameters if DMD passed parameters in the right order.
Nov 15 2014