- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I am porting some legacy code from CVF to Intel Visual Fortran. I am trying to call some subroutines in a C++ DLL. I have include the C++ DLL's .lib file in my INCLUDE path but the linker isn't finding the routines. This code works in CVF. The C++ code has
[cpp]
extern "C"
{
_declspec(dllexport) Result __declspec stdcall Foo1(long Num, long numPts, MyStruct *MyStructPtr);
_declspec(dllexport) Result __declspec stdcall Foo2(long Num, long numPts, MyStruct *MyStructPtr);
_declspec(dllexport) Result __declspec stdcall Foo3(long Num, double length);
};
[/cpp]
In the .lib file I can see these functions are called _Foo1@12, _Foo2@12, and _Foo3@12.
My Fortran interface looks like
[fortran]
MODULE My_Interface
IMPLICIT NONE
INTERFACE
TYPE(RESULT) FUNCTION Foo1( Num, NumPts, MyStructPts )
!DEC$ ATTRIBUTES DLLIMPORT,STDCALL :: Foo1
!DEC$ ATTRIBUTES DECORATE, ALIAS:'Foo1' :: Foo1
!DEC$ ATTRIBUTES VALUE :: Num, NumPts
!DEC$ ATTRIBUTES REFERENCE :: MyStruct,
integer(4),intent(in) :: Num
integer(4),intent(in) :: NumPts
type(MyStruct),intent(in) :: MystructPts(0:NumPts)
END FUNCTION Foo1
END INTERFACE
INTERFACE
TYPE(RESULT) FUNCTION Foo2( Num, NumPts, MyStructPts )
!DEC$ ATTRIBUTES DLLIMPORT,STDCALL :: Foo2
!DEC$ ATTRIBUTES DECORATE, ALIAS:'Foo2' :: Foo2
!DEC$ ATTRIBUTES VALUE :: Num, NumPts
!DEC$ ATTRIBUTES REFERENCE :: MyStruct
integer(4),intent(in) :: Num
integer(4),intent(in) :: NumPts
type(MyStruct),intent(in) :: MyStructPts(0:NumPts)
END FUNCTION Foo2
END INTERFACE
INTERFACE
TYPE(RESULT) FUNCTION Foo3( Num, length )
!DEC$ ATTRIBUTES DLLIMPORT,STDCALL :: Foo3
!DEC$ ATTRIBUTES DECORATE, ALIAS:'Foo3' :: Foo3
!DEC$ ATTRIBUTES VALUE :: Num, length
integer(4),intent(in) :: Num
real(8),intent(in) :: length
END FUNCTION Foo3
END INTERFACE
END MODULE My_Interface
[/fortran]
In CVF the linker will look for the routines _Foo1@12, _Foo2@12, and _Foo3@12 and the link is satisfied. In intel fortran the linker is looking for _Foo1@16, _Foo2@16 and _Foo3@16. Why is this? Is there a compiler option to coreect the problem? Does it have something to do with the return argument? I know there were changes here from CVF to IVF and I read the porting apps from CVF whitepaper and none of it seemed to apply to my situation.
Thanks in advance for any insight.
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The C++ was compiled in Visual Studio 6, and I don't have the ability to recompile the code. I have hundereds of these interfaces throughout my code base and these are the only 3 that aren't working. They are also the only 3 that are functions rather than subroutines.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I suspect it has to do with the function returning a structure. Intel Fortran is passing a hidden argument for this. I will take a look at it tomorrow. What is the declaration of type RESULT?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
If the size in bytes of an object of type "RESULT" is big enough (more than 64 bits) then the compiler passes an additional hidden address to receive the function result value - hence the additional four bytes in the @nn.
Please show the C and Fortran declarations of this type.
(oops, sorry for the redundancy)
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Lines 11 and 29 should probably say
!DEC$ ATTRIBUTES REFERENCE :: MyStructPts
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I have tried some experiments and can't reproduce a problem. I recognize that the code posted is NOT the real code and is a paraphrase, with all of the inherent errors and omissions that introduces. The declaration of type Result in both the C++ and Fortran code is critical to understanding the issue.
As Ian says, if the size of type RESULT is 64-bits or less, then no hidden argument is passed, and my experiments with IVF show that to be the case. We need more information - ideally, a buildable example.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
In Fortran the RESULT is defined as
[fortran]
TYPE RESULT
LOGICAL(4) :: flag
INTEGER(4) :: firstListLoc
INTEGER(4) :: lastListLoc
INTEGER(4) :: errorCode
END TYPE
[/fortran]
In C++
[cpp]
struct Result
{
long flag;
long firstListLoc;
long lastListLoc;
long ec;
};
[/cpp]
I will try to create a buildable example. Thanks for the help.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I've created an example where everything is used exactly as it would be in my code. The compiler is trying to link against _Foo@16. Unfortunately, I have no ability to create a C++ library to use in the example. I am contractually obligated to keep my computer free of any files with an extension associated with C++ or C, with the exception of header files.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Unfortunately, I have no ability to create a C++ library to use in the example.Not a problem, since we can see, by compiling the sources that you provided, that the external names generated are __imp_Foo1@16, __imp_Foo2@16 and __imp_Foo3@16. Since the function return value occupies 16 bytes (in IA32 code), and therefore cannot be returned in %eax, an extra argument is pushed on the stack to receive the return value. CVF 6.6C does the same thing, but does not include this extra argument in computing the value of nn in the @nn name decoration used with Stdcall. If further checking shows that it is only the name decoration that causes a problem, and that the calling sequence is otherwise compatible with your C++ DLL, a simple fix may be possible that does not require rebuilding the DLL, if rebuilding is not feasible
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Ok - I can reproduce the difference, but am still trying to figure out how C++ is returning the result. I note that MSVC gives the routine the @4 suffix ven though logic suggests it should be @8. Stay tuned.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Alright, my mind is officially blown...
MSVC does something truly bizarre in this case. For a function returning a struct larger than 8 bytes, it expects the address of a place to store the return value to be passed as a "hidden" first argument, just as Fortran does. But.. If you declare the routine with __stdcall, MSVC inexplicably omits this hidden argument when creating the @n name decoration. In the case at hand, where there are 16 bytes pushed on the stack - and the C routine ends with a "ret 16", MSVC uses @12 as the suffix! I can't find any documentation explaining this - it is horribly inconsistent with everything I have read.
Now something even more strange. If in CVF you explicitly give the function the STDCALL attribute, then it will also ignore the hidden argument when computing the suffix. But not if you leave it off - and remember that CVF defaults to STDCALL!
My guess is that somewhere along the way we noticed this inconsistency and fixed it. If you had a Fortran function returning a 16-byte derived type and compiled it with CVF, its name would have @16 at the end.
So, what to do? We can't "fix" this in the compiler, because it would break calls to Fortran functions that have the STDCALL convention. The workaround for you is to not use DECORATE and explicitly put the full name in the ALIAS, such as '_Foo1@12'. IVF will call the routine correctly and you'll work around the name mismatch.

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