- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Can anyone tell me where the Fortran calling conventions are documented? I have found brief charts in the Fortran docs, but they do not cover some important details.
I am asking because I have found an incompatibility in C++ calling Fortran, which suggests that STDCALL routines do not remove their args from the stack under certain circumstances.
I have been trying to get an answer from Premier Support, but no luck so far.
I am asking because I have found an incompatibility in C++ calling Fortran, which suggests that STDCALL routines do not remove their args from the stack under certain circumstances.
I have been trying to get an answer from Premier Support, but no luck so far.
Link Copied
8 Replies
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Calling conventions are documented, at least partially, in the Mixed Language Programming section of the Building Applications manual. However, a problem of the nature you describe would not be addressed there. What you describe sounds more like a bug, or perhaps a misunderstanding. What's the Premier Support issue number?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Premier support # 376754.
I have explained the details there, but in summary, I believe the problem that for some reason, /iface:stdref does not remove the args in the called function. The situation is out of the ordinary because the function returns a user-defined type, and therefore has one "hidden" argument.
Fortran subprograms in the same module know somehow that function Reduce does not clean up the stack, and include code to do so, but C++ callers assume _stcall means the called function will remove the args, which it is not doing.
BTW, I also noticed that the compiler is generating an extra instruction just before the 'leave' instruction, which loads the address of the return value into eax. That instruction does nothing, unless it is part of the calling convention.
I have explained the details there, but in summary, I believe the problem that for some reason, /iface:stdref does not remove the args in the called function. The situation is out of the ordinary because the function returns a user-defined type, and therefore has one "hidden" argument.
Fortran subprograms in the same module know somehow that function Reduce does not clean up the stack, and include code to do so, but C++ callers assume _stcall means the called function will remove the args, which it is not doing.
BTW, I also noticed that the compiler is generating an extra instruction just before the 'leave' instruction, which loads the address of the return value into eax. That instruction does nothing, unless it is part of the calling convention.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Oh, so it's you who is "Ann O'Nymous". I had wondered. Some of our support engineers hadn't picked up on the joke.
What you are seeing is correct behavior, though it is different from CVF. It's a difference that only recently came to my attention and I'll admit is not well documented.
In CVF, functions that returned a user-defined type by a hidden first argument, as you note in a follow-up to your issue. But Intel Fortran returns such values in the EAX or EAX and EDX registers, if the size is 8 bytes or less. This is consistent with C and matches the published IA-32 calling convention. This means that there will be one fewer argument to remove from the stack and the move to EAX you see is the return value.
To deal with this, either change the Fortran code to be a subroutine with a new first argument, or change the C code to declare the routine as returning a struct.
I'll let Sachin, the support engineer who's been helping you, know of this discussion.
What you are seeing is correct behavior, though it is different from CVF. It's a difference that only recently came to my attention and I'll admit is not well documented.
In CVF, functions that returned a user-defined type by a hidden first argument, as you note in a follow-up to your issue. But Intel Fortran returns such values in the EAX or EAX and EDX registers, if the size is 8 bytes or less. This is consistent with C and matches the published IA-32 calling convention. This means that there will be one fewer argument to remove from the stack and the move to EAX you see is the return value.
To deal with this, either change the Fortran code to be a subroutine with a new first argument, or change the C code to declare the routine as returning a struct.
I'll let Sachin, the support engineer who's been helping you, know of this discussion.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Steve, thanks for your help. What you say makes sense, and I will check it out. Now the remaining problem is why all the messages about disagreement of number of arguments when /iface:CVF is used to compile.
Steve_Lionel wrote:
In CVF, functions that returned a user-defined type by a hidden first argument, as you note in a follow-up to your issue. But Intel Fortran returns such values in the EAX or EAX and EDX registers, if the size is 8 bytes or less. This is consistent with C and matches the published IA-32 calling convention. This means that there will be one fewer argument to remove from the stack and the move to EAX you see is the return value.
To deal with this, either change the Fortran code to be a subroutine with a new first argument, or change the C code to declare the routine as returning a struct.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
But, one other thing:
Reduce is not removing any args from the stack. That means it is not obeying the documented STDCALL convention, and I can only specify _stdcall or _cdecl as the calling convention in C++. How can I tell C++ that the callee leaves the args on the stack?
Reduce is not removing any args from the stack. That means it is not obeying the documented STDCALL convention, and I can only specify _stdcall or _cdecl as the calling convention in C++. How can I tell C++ that the callee leaves the args on the stack?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
That's not what I see when I compile with the CVF option:
The "ret 8" pops off the one argument plus the saved ebp pushed at the beginning.
$LN479:
mov eax, DWORD PTR [ebp+8] ;320.2
leave ;320.2
ret 8 ;320.2
The "ret 8" pops off the one argument plus the saved ebp pushed at the beginning.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I switched from CVF to STDREF per Sachin's instructions. That was needed to get the "correct" name decoration. It is the STDREF compilation that produces leave/ret, rather than leave/ret 8. I sent Sachin a copy of that assembler code.
Going back to CVF, the correct name decoration will be @4, rather than @8, but we will have the original problem, which is a large number of warnings that the number or type of args differs.
It is necessary to get all 3 of these right:
1) Stack cleaned up properly.
2) Global symbol accessible to C++ pgm.
3) Consistent calling interface, so no warnings are produced.
We seem to have a choice of 2/3.
P.S. 'leave' pops the saved ebp, so 'ret 8' is popping 2 args. I believe in this case one is the pointer to the return value; see the prologue to the function in the assembler listing.
Going back to CVF, the correct name decoration will be @4, rather than @8, but we will have the original problem, which is a large number of warnings that the number or type of args differs.
It is necessary to get all 3 of these right:
1) Stack cleaned up properly.
2) Global symbol accessible to C++ pgm.
3) Consistent calling interface, so no warnings are produced.
We seem to have a choice of 2/3.
P.S. 'leave' pops the saved ebp, so 'ret 8' is popping 2 args. I believe in this case one is the pointer to the return value; see the prologue to the function in the assembler listing.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I'll have to look at this more next week.

Reply
Topic Options
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page