-1

I'm building a C program which explicitly dynamically loads DLLs as part of a plugin system. I'm using GCC with MinGW on Windows 7.

What calling convention should the exported functions in the DLLs use, in order to be as robust as possible: run successfully on different Windows machines, survive different compiler versions, etc.

I know that the main executable and the DLLs need only use the same calling convention. How is this normally managed?

Currently I'm only aiming at supporting Windows (even though answers referring also to the same subject on Linux will be welcome as well).

EDIT:

Please let me clarify the question, as discussed in a comment section with @S. S. Anne.

I'm less concerned about the particular calling convention. I'm more concerned with what is the standard way to ensure compatibility between a binary built on machine X and a DLL (plugin thing) built by somebody else on machine Y, which might have a different OS etc.

One approach I can think of, is that in the header file distributed to plugin developers, we define a macro that specifies the expected calling convention of functions exposed by the plugin to the main program. These functions will be defined by the plugin developer using this macro.

For example, the api.h header, supplied to plugin developers, defines #define CALL __cdecl. And after doing #include "api.h", the exported functions in the plugin DLL are declared like so: void CALL func(void);.

Is this solution used in practice? Are there different approaches?

S.S. Anne
  • 15,171
  • 8
  • 38
  • 76
Aviv Cohn
  • 15,543
  • 25
  • 68
  • 131
  • 1
    I would suggest the default calling convention. – ssbssa Apr 03 '20 at 13:31
  • On x64, use fastcall: https://learn.microsoft.com/en-us/cpp/build/x64-calling-convention . On x86, most win32 API use stdcall, some cdecl (for var args): https://learn.microsoft.com/en-us/cpp/cpp/argument-passing-and-naming-conventions. I would use stdcall, but it's not mandatory. https://learn.microsoft.com/en-us/cpp/cpp/stdcall – Simon Mourier Apr 14 '20 at 14:54
  • I don't know why this got two downvotes. The day that I saw this, it was the most interesting question I'd seen all day. – S.S. Anne Apr 20 '20 at 21:26

1 Answers1

1

Edit following question edit

No, you will not have to "ensure compatibility between a binary built on machine X and a DLL (plugin thing) built by somebody else on machine Y, which might have a different OS etc" unless the OS that binary X was built for is completely different from the OS that binary Y was built on. For context, this is a list of operating systems that are not compatible with each other:

  • Windows
  • Linux
  • Mac
  • BSD

You do not need to manually specify any calling convention. You don't even need to think about any calling conventions.

Your solution is not used in practice. The different approach required is to do nothing.

Original answer

For x86_64 Windows, the default Microsoft x64 ABI calling convention is what's used across the board. This should be enabled by default.

For x86 Windows, the image is a bit muddier: Most Windows API calls use __stdcall, but __cdecl is the default convention for user-defined functions. The difference between the two is that in the former, the callee cleans the stack, while in the latter, the caller cleans the stack.

In this case, I would go with __cdecl, as this is the default for both MSVC++ and GCC targeting Windows.

See __cdecl or __stdcall on Windows? for more information on this.

On Linux, you should always go with the default calling convention for your architecture. This option is always the most portable.

In conclusion, using the default calling convention should be fine across the board. You shouldn't have any problems with it.

S.S. Anne
  • 15,171
  • 8
  • 38
  • 76
  • Hi, thanks for your answer. I'm less concerned about the particular calling convention. I'm more concerned with what is the standard way to ensure compatibility between a binary built on machine X and a DLL (plugin thing) built by somebody else on machine Y, which might have a different OS etc. One approach I can think of, is that in the header file distributed to plugin developers, I define a macro that specifies the expected calling convention of functions exposed by the plugin to the main program. And these functions will be defined by the plugin developer using this macro. [next comment] – Aviv Cohn Apr 14 '20 at 17:05
  • Is this approach generally the way this thing is done? Or do you know of a different approach? – Aviv Cohn Apr 14 '20 at 17:06
  • E.g. in the API header file of the main program: `#define APPCALL __cdecl`. And when the plugin declares an exported function: `void APPCALL func(void);` – Aviv Cohn Apr 14 '20 at 17:08
  • @AvivCohn All of these are the defaults and have been for a long time. They'll be just fine. – S.S. Anne Apr 14 '20 at 17:15
  • You shouldn't have to manually specify the calling convention unless you're using assembly or you really care about code size. But if you're looking for portability then you probably won't do either of these. – S.S. Anne Apr 14 '20 at 17:27
  • @AvivCohn Thanks for your question edit, I've added a clarification of my own. – S.S. Anne Apr 15 '20 at 13:09