-
-
Notifications
You must be signed in to change notification settings - Fork 379
spec: abi: clarify calling convention for other architectures other than x86 #3120
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
…han x86 Observing the assembly generated by the following source file in either DMD and LDC: ```d extern (C) void ccall( size_t a, size_t b, size_t c ); extern (D) void dcall( size_t a, size_t b, size_t c ); //... ccall( a, b, c ); // RDI, RSI, RDX dcall( a, b, c ); // RDX, RSI, RDI ``` The parameters are passed in the reverse order in functions with `extern(D)` linkage. Furthermore, on x86 the calling convention seems to be what is described by the current subsections, not only matching Windows x86, but also appears to be the same behaviour on System V ABI. Fixes #20204 . Signed-off-by: Luís Ferreira <[email protected]>
Thanks for your pull request, @ljmf00! Bugzilla references
|
Except that the extern (D) calling convention for Windows x86 is described here. | ||
) | ||
$(P Functions with $(D extern (C)) linkage matches the C calling | ||
convention used by the supported C compiler on the host system.) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I still think that used by the supported C compiler on the host system
is to vague
|
||
$(P Functions with $(D extern (D)) linkage matches the calling | ||
convention used by $(D extern (C)) functions with the parameters | ||
pushed in the reverse order, except for 32-bit x86 architecture, which |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not really, parameters are just evaluated from left to right.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you elaborate? Look into the godbolt link and issue attached to the PR description for context. Maybe I expressed myself wrongly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The real intent is left to right evaluation of parameters.
Dmd passing arguments in reverse is just an implementation detail, because Walter doesn't want to use too many scratch registers to hold intermediate values before calling the function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think it is an implementation detail. If the specification is correct, then the compiler is behaving wrongly. I interpret implementation details as different implementation behaviour that doesn't affect specification conformance.
In practice, if I try to link a function generated by DMD with another binary generated by a compiler that generates a conformant convention call, bad things may happen, if the order matters, because the registers are reversed and therefore the parameters are passed wrongly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
GDC is spec conformant. ;-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
GDC is spec conformant. ;-)
That is good to know and makes sense. So only LDC/DMD is wrong. What about the 32-bit x86 on GDC? Since the spec only mentions Windows, it is also conformant. I don't know about Windows x86 since I don't use Windows, but should we deviate from the standard calling convention there too?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
GCC only supports MinGW or Cygwin, so I only follow what is the ABI for that target.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
GCC only supports MinGW or Cygwin, so I only follow what is the ABI for that target.
Doesn't MinGW try to mimic the same ABI as Windows? Anyway, it is not so explicit that way, so GDC seems to conform with it, only DMD and LDC do not. See dlang/dmd#13287 where we can discuss the problem more in-depth and a possible fix for this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
extern(C) code may be compatible, but MinGW uses Itanium ABI for C++, not MSVC.
I've always regarded this as an ABI spec violation of both DMD and LDC, unfortunately not that simple to fix mainly because of existing DMD-style inline asm in druntime/Phobos and user code. If given the choice, I'd definitely fix the implementation rather than the spec. |
I agree with you because it doesn't make much sense. I don't get the rationale for the x86 special case either. On the other hand, changing the implementation make binaries incompatible leading to a huge breaking change with old shared objects. I'm kinda divided here, to be honest, but inclined to the "clean way", which is to fix the implementation. |
That's not that big a deal, we have had numerous breaking ABI changes in the past, so binaries compiled with different compiler versions aren't expected to be compatible. The only real problem I see is that efforts should probably be synchronized across DMD and LDC, in order to tell people that from D 2.100 on (or so), the params aren't reversed for I'm more than happy to finally do this for LDC (I've had a go at this some 5 years ago already). |
This parameter reversal has been a PITA at multiple occasions, e.g., dlang/dmd#11630. |
Sure, I can see what I can do about it. I'm not into deep backend stuff like target codegen. What about the 32-bit x86? Why is the calling convention different there too?
At a first glance, it appears to me that this is being fixed in the wrong place. This parameter reverse order behaviour appears to be intentional on the IR generation: https://github.com/dlang/dmd/blob/master/src/dmd/e2ir.d#L5261 |
Observing the assembly generated by the following source file in either DMD and
LDC:
The parameters are passed in the reverse order in functions with
extern(D)
linkage. Furthermore, on x86 the calling convention seems to be what is
described by the current subsections, not only matching Windows x86, but also
appears to be the same behaviour on System V ABI.
Fixes #20204 .
Signed-off-by: Luís Ferreira [email protected]
For more context: https://godbolt.org/z/sWz4x37bb