Thread overview
Linkage question
Jan 24, 2022
frame
Jan 24, 2022
Stanislav Blinov
Jan 24, 2022
frame
Jan 24, 2022
Paul Backus
Jan 25, 2022
duser
January 24, 2022

If I declare a function as extern(C) inside a DLL, I have also to cast the function pointer as extern(C) or it fails calling, eg.

// --- my.dll
export extern (C) void log(int mode, string a, string b, string c) {
  /* stuff */
}

// --- main.d
alias T = extern (C) void function(int, string, string, string);
auto fnPtr = cast(T)GetProcAddress(/* stuff */);

I understand that the linkage must match but besides the name mangling, what's happen here? What is the difference if I remove the extern (C) part from the T alias?

Doing that supplies 2nd and 3rd paramter as fine pointers but the 1st argument comes wrong (eg. 10 becomes -218697648) and the last argument is garbage too, so the D-linkage format is something different.

Would like to know where the linkage format is defined, thx.

January 24, 2022

On Monday, 24 January 2022 at 17:23:01 UTC, frame wrote:

>

I understand that the linkage must match but besides the name mangling, what's happen here? What is the difference if I remove the extern (C) part from the T alias?

The difference is in how arguments are being passed, which you seem to have discovered already :)

>

Would like to know where the linkage format is defined, thx.

It should be here: https://dlang.org/spec/abi.html although IIRC it might not be 100% up to date.

January 24, 2022

On Monday, 24 January 2022 at 18:30:02 UTC, Stanislav Blinov wrote:

>

The difference is in how arguments are being passed, which you seem to have discovered already :)

>

Would like to know where the linkage format is defined, thx.

It should be here: https://dlang.org/spec/abi.html although IIRC it might not be 100% up to date.

Ah, yes. Thanks. Maybe I should read it more carefully =)

It claims that the D calling convention matches C. But it seems that the arguments are pushed in order whereas C does it in reverse order and the -218697648 value is indeed my 3rd string pointer.

January 24, 2022

On Monday, 24 January 2022 at 19:41:30 UTC, frame wrote:

>

It claims that the D calling convention matches C. But it seems that the arguments are pushed in order whereas C does it in reverse order and the -218697648 value is indeed my 3rd string pointer.

Windows has two calling conventions for C functions, cdecl and stdcall. In D, cdecl is called extern (C) and stdcall is called extern (Windows). Windows API functions use the stdcall convention [1], so you need to use extern (Windows) when calling them from D.

[1] https://docs.microsoft.com/en-us/cpp/cpp/stdcall?view=msvc-170

January 25, 2022

On Monday, 24 January 2022 at 19:41:30 UTC, frame wrote:

>

On Monday, 24 January 2022 at 18:30:02 UTC, Stanislav Blinov wrote:

>

The difference is in how arguments are being passed, which you seem to have discovered already :)

>

Would like to know where the linkage format is defined, thx.

It should be here: https://dlang.org/spec/abi.html although IIRC it might not be 100% up to date.

Ah, yes. Thanks. Maybe I should read it more carefully =)

It claims that the D calling convention matches C. But it seems that the arguments are pushed in order whereas C does it in reverse order and the -218697648 value is indeed my 3rd string pointer.

that's a bug with dmd or the spec, arguments are currently passed in reverse order compared to C on 64-bit even though they should be the same

see:
https://issues.dlang.org/show_bug.cgi?id=20204
https://github.com/dlang/dmd/pull/13287
https://github.com/dlang/dlang.org/pull/3120