Walter: D asm syntax not consistent nor calling convention with C++
Adam Sansier via Digitalmars-d
digitalmars-d at puremagic.com
Sat Jul 16 23:10:14 PDT 2016
D is not consistent with C++ in asm and calling convention.
I have the exact same code in both C++ and D, the exact same
assembler code, but.
D's
enum VS = (void*).sizeof;
enum SA = 6;
enum OF = 0;
void createBuffers(iASIO a, void* funcptr, void *buf, int num,
int size, void* callbacks)
{
asm
{
naked;
enter 0 * 4, 0;
push dword ptr [EBP + VS + SA*VS - OF*VS - 0*VS]; //
Callbacks
push dword ptr [EBP + VS + SA*VS - OF*VS - 1*VS]; //
bufferSize
push dword ptr [EBP + VS + SA*VS - OF*VS - 2*VS]; //
numChannels
push dword ptr [EBP + VS + SA*VS - OF*VS - 3*VS]; //
bufferInfos
call dword ptr [EBP + VS + SA*VS - OF*VS - 4*VS]; // call fnc
leave;
ret;
}
}
C's:
#define SA 6
#define VS 4
#define OF 0
__declspec(naked) ASIOError ASIOCreateBuffers(void* ptr, void*
fnc, ASIOBufferInfo *bufferInfos, long numChannels, long
bufferSize, ASIOCallbacks *callbacks)
{
__asm
{
enter 0 * 4, 0;
push [EBP + VS + SA*VS - OF*VS - 0*VS]; // Callbacks
push [EBP + VS + SA*VS - OF*VS - 1*VS]; // bufferSize
push [EBP + VS + SA*VS - OF*VS - 2*VS]; // numChannels
push [EBP + VS + SA*VS - OF*VS - 3*VS]; // bufferInfos
call [EBP + VS + SA*VS - OF*VS - 4*VS]; // call fnc
leave;
ret;
}
}
1. C++ allows lower case, D does not. This is somewhat annoying
but not a big deal. Strange that one would mark the block naked
by not the function.
2. C++ defaults to dword ptr, D to word ptr. Copying and pasting
the code results in hard to find bugs.
3. D does not allow () in offset calculation. Notice the
verbosity simply because parenthesis are not allowed.
---------------------------------
**4**. D's calling convention is different than C++'s. I'm not
sure what is going on. Major source of headaches.
---------------------------------
Also, all this is because D crashes when trying to simply call
the function directly while C++ works fine: All the arg values
are correct and exactly the same as verified by comparing memory
values.
C++'s stack frame: 00d1ff3c 00000014 000000c0 00d210f8
D's Stack frame: 0038c258 000000c0 00000014 003972f8
They are reversed!
The function is marked marked extern(C++) but extern(C) and
extern(Windows) doesn't change the order either.
Surely there is something wrong with the calling convention? This
is COM Stuff. I copied the interface right out of the C++ version
and added extern(C++)(crashes with extern(Windows)).
// The Asio COM interface
extern(C++) interface iASIO : IUnknown
{
extern(C++){
...
ASIOError createBuffers(sASIOBufferInfo *bufferInfos, size_t
numChannels, size_t bufferSize, sASIOCallbacks *callbacks);// 19
...
}
}
Hopefully you can spend 20 mins thinking about this as I've spent
2 days trying to figure out WTF is going on here. Why? Reversing
the parameters doesn't solve the problem, it eventually crashes.
The function does get the correct values as one can see the
memory change for the buffers and such.
The magic?
D Version:
asm
{
naked;
enter 0 * 4, 0;
push dword ptr [EBP + VS + SA*VS - OF*VS - 3*VS]; //
bufferInfos
push dword ptr [EBP + VS + SA*VS - OF*VS - 2*VS]; //
numChannels
push dword ptr [EBP + VS + SA*VS - OF*VS - 1*VS]; //
bufferSize
push dword ptr [EBP + VS + SA*VS - OF*VS - 0*VS]; //
Callbacks
push dword ptr [EBP + VS + SA*VS - OF*VS - 5*VS]; // this
call dword ptr [EBP + VS + SA*VS - OF*VS - 4*VS]; // call fnc
leave;
ret;
}
Push `this` on the stack and it works! Notice the order though!
Not what one would expect. It's as if D is passing `this` last
instead of first!
Hence I had to go from
//auto res = theAsioDriver->createBuffers(bufferInfos,
numChannels, bufferSize, callbacks); return res;
To all that assembly just to figure it all out. It seems there is
a bug in the calling convention somewhere, or that D needs
another calling convention. Im going to have to wrap every
interface function with this sort of mess both for x86 and x64.
BTW, why does D use enter/leave when it is slower than push/pop?
This has been a very frustrating experience with D! Maybe it's
just one of those illusive `kick your ass bugs`, it sure kicked
mine!
More information about the Digitalmars-d
mailing list