I have an update tp do on a code in Fortran 77 and I had the surprise to see a call to GETARG() function with 3 arguments:
CALL GETARG(IARG,CHARARG,INT2)
Of course it is not compiling with gfortran and I was wondering if suchsyntax really existed in Fortran 77 and what it meant?
Related
I'm writting a program in C++ that calls some functions I had written in Fortran. I was going to test a very basic example in which I call a function called toRadians from the C++ code:
real function toRadian(degree)
implicit none
real, intent(in) :: degree
real :: radians
radians = (degree*PI)/180
return
end function toRadian
And so I wonder, is this "worth it"? When I finish the whole thing that function will be called within Fortran where the bulk of the computations will be done, but doing this basic example got me thinking about if, for a simple computation like this, is calling the Fortran function more expensive than just having that function in C++?
Sorry for my ignorance I'm not very sure about how the linking between these compiled codes works. (I'm also very new with Fortran so if you want to make any remark about the previous function please go ahead).
Thanks for your time and have a nice day.
Calling a Fortran function is as cheap as calling another C++ function. Usually.
The problem is the compatibility between the two languages. The best way to start this in Fortran is to use iso_c_binding so that the function has a C calling convention.
Then the other issue is that both languages require their own runtime libraries, and there are no linker flag to use both. So the usual practice is to create a shared library for the Fortran code and link it against the C++ application (and vice-versa when it's calling C++ from Fortran).
Intel CPU
Windows 10 64bit
C++
x86 assembly
I have two programs, both written by me in C++. For the sake of simplicity I will refer to them as program A and program B. They do not do anything special really, I am just using them to test things out and have some fun in the process.
The idea is that program A injects code into program B and that injected code will set the parameters of a function in program B and will call a function in program B.
I must say I have learned a lot from this experiment. As I needed to open up a handle to a process with proper permissions and then construct assembly code to inject, call it with CreateRemoteThread and clean up afterwards.
I ve managed to do this and call a function from program B and that function takes one parameter of type UINT64.
I do this by injecting the following assembly code:
b9 paramAddr
e8 funcAddr
c3
By calling this code snippet from program A with CreateRemoteThread in program B I manage to call a function at an address and with a parameter passed. And this works fine. Nothing too complex just call a function that takes one param. One thing to note here is that I have injected the parameter prior to this code and just provided a parameter address to b9.
Now what I am failing to do is call a function in program B from program A that takes two parameters.
Function Example:
myFunction(uint num1, int num2)
The procedure for injection is the same, and all that works just fine windows API provides plenty of well documented functionalities.
What I do not seam to be able to do is pass the two parameters to the function. This is where my troubles begin. I have been looking at x86 assembly function call conventions. And what they do is either just
push param2
push param1
call functAddr
retn
or
perform a mov to esi
Could anyone please clarify,explain and provide a clear example of how to call a function in x86 assembly that takes two parameters or type uint and int.
Thank you all for your time and effort.
Since you are looking for a way to understand and clarify what is happening internally, I recommend to start with generating an assembler file for the specific machine you are working with. If you are using gcc or g++ you can use the -S flag to generate the associated assembler files. For the beginning you can implement a function with two arguments and call that function inside your main function. Using the assembler files, you should get a really good picture of how the stack is filled before your function is called and where your return value is put. In the next step you should compare what you see in the assembler file with the x86 calling convetion.
I was trying to develop a better understanding of the linkers and how they work, so I tried to call the simple function(printf) from the c library (MSVCRTD.lib) but with assembly code on MASM.
I dissected the external symbols from the "MSVCRTD.lib" library which has many printf's functions like:
__imp__printf
_printf
___imp___printf_l
;and more ...
I had 2 challenges (linking/building) and (running).
as for the first challenge linking my assembly code to the library was not a problem at all, I could link my assembly code with any call to any external function of the library,all I needed just to mimic the decorated (Mangled) name of the function so the linker can recognize it. I first tried the second one "_printf" which locked shorter and nicer, and after disassembling it's code I knew that it takes 2 parameters on the stack and it's a cdecl calling convention, so I write the code it needs and it was:
.386
.model flat,stdcall
.stack 4096
option casemap :none
Extern printf :PROC ; MASM will decorate it to be "_printf"
.data
message byte "Hello C library, this is MASM calling"
.code
main proc
push 0
push offset message
call printf
add esp,8 ; clean the stack
retn
main endp
end
and shoot! every thing was smooth .
but when I tried the same thing with "_imp__printf" the problems start.
BTY: this function is the one that the c compiler calls when you write the famous hello world! c application
the linker successfully build the program but when I run the program it crashes!
I read the linker output messages and every thing looks normal except for the line that says: " Discarded _printf from MSVCRTD.lib(MSVCR100D.dll)".
I debugged the program with OllyDBG and I found that the call instruction that should land on the function actually lands on an area that is recognized as DATA ! in the .rdata section
why the "_printf" function succeed and the "__imp__printf" didn't :( , any idias?
Thanks for Mr. Jester and Mr. Raymond Chen
they provided the solution for the problem in the comments.
it was the declaration of the __imp__printf. that is declared as a PROC like the working example _printf but there were DATA so declaring.
Extern _imp__printf :DWORD
will makes it work as printf
thank you so much , both of you
EDIT: this is not the solution , but I will leave it for later reference. the solution in the next answer.
I think I'm close to figure out why calling _imp__printf external function failed because of a problem in the jumping instruction, here is what I did..
I tried to build the hello world! C program to see how the _imp__printf function will look like in the symbols table if the file compiled as a C program instead of assembly , I then dumped the OBJ file that was compiled from both calling program (the MASM/ and the c ), and the results were very interesting , here is the _imp__printf in the OBJ compiled from the C file
and here is the _imp__printf in the OBJ compiled from the MASM file
Interesting! and after referencing to the COFF documentation It seems that the relocation type REL32 will force the linker not to process the import address table correctly so the jump instruction will fall as it happened before.
now my question is "how I can tell MASM to assemble the file with _imp__printf symbol type "DIR32" ?
I am using IMSL with Intel Virtual Fortran with MKL. I tried to use a routine from IMSL. It was compiled fine, but when I try to execute the file it came up with an error saying:
MKL ERROR: Parameter 7 was incorrect on entry to SGEEVX
*** TERMINAL ERROR 2 from EVCRG. The required storage cannot be allocated.
*** The specified N may be too large, where N = 1064682127.
The following is the code I am using:
PROGRAM test_evcrg
include 'link_fnl_static.h'
!DEC$ OBJCOMMENT lib:'libiomp5mt.lib'
IMPLICIT NONE
REAL, Dimension(2,2) :: p,vr
REAL, Dimension(2) :: w
p = RESHAPE([0.7, 0.3, 0.5,0.5],[2,2])
CALL EVCRG (p,w,vr)
WRITE (*,*), w
WRITE (*,*)
WRITE (*,*), vr
END PROGRAM test_evcrg
How can I fix this problem?
AFTER I ADDED
USE EVCRG_INT
IT GIVES THE ERROR INFOMATION:
test_evcrg.f90(14): error #6285: There is no matching specific subroutine for this generic subroutine call. [EVCRG]
CALL EVCRG(p,w,vr)
---------^
compilation aborted for test_evcrg.f90 (code 1)
THANKS.
In the IMSL USER'S GUIDE, it says:
FORTRAN 90 Interface
Generic: CALL EVCRG (A, EVAL, EVEC [,…])
Specific: The specific interface names are S_EVCRG and D_EVCRG.
I don't know IMSL enough, but I think there is a mismatch of interfaces. Because you do not use any IMSL module, you are not using the Fortran 90 interface, but the Fortran 77 interface, which requires more arguments. See IMSL manual. Either use the module, or change the call to something like CALL EVCRG (2, p, 2,w, vr, 2).
The use statement you can use is probably USE numerical_libraries.
---- EDIT ----
It means, that adding the use was the good thing. Now it exposes, that there really was an error in the call. The arguments are wrong. Arguments 2 and 3, i.e. EVAL and EVEC must be COMPLEX!
Is it possible to pass fortran 77 function as a callback function pointer to C/C++?
if so, how?
information I found on the web relates to fortran 90 and above, but my legacy code base is in 77.
many thanks
If it can be done in FORTRAN 77, it will be compiler and platform specific. The new ISO C Binding of Fortran 2003 provides a standard way of mixing Fortran and C, and any language that follows or can follow the calling conventions of C, such as C++. While formally a part of Fortran 2003, and while there are extremely few Fortran compilers that fully support the entirety of Fortran 2003, the ISO C Binding is supported by numerous Fortran 95 compilers, including gfortran, g95, Sun, ifort, etc. So I recommend using one of these Fortran 95 compilers and the ISO C Binding method rather than figuring out some method for a particular method. Since FORTRAN 77 is a subset of of Fortran 95, why not compile your legacy code with one of these compilers, using Fortran 95 to add this new feature?
I have called Fortran procedures from C using the ISO C Binding, but haven't passed them as pointers. It should be possible. The steps are:
1) you declare the Fortran function with the Bind(C) attribute,
2) you declare all of the arguments using special types, such as integer(c_int), that match the types of C.
Steps 1 & 2 make the Fortran function interoperable with C.
3) You obtain a C-pointer to this Fortran function with the Fortran instrinsic function "c_funloc", assigning the pointer value to a pointer of type "c_funptr".
4) In the Fortran code, you declare the C routine that you want to pass the function pointer to with an Interface, declaring it in in Fortran terms, but using the Bind(C) attribute and interoperable types so that the Fortran compiler knows to use the C-calling convention -- making the C routine interoperable with Fortran.
Then when you call the C-routine in the Fortran code, you can pass it the function pointer created in step 3.
UPDATE: Code example: The Fortran main program "test_func_pointer" passes a pointer to the Fortran function "my_poly" to the C routine "C_Func_using_Func_ptr" and receives the result back from that C function.
module func_pointer_mod
use, intrinsic :: iso_c_binding
implicit none
interface C_func_interface
function C_Func_using_Func_ptr ( x, Func_ptr ) bind (C, name="C_Func_using_Func_ptr")
import
real (c_float) :: C_Func_using_Func_ptr
real (c_float), VALUE, intent (in) :: x
type (c_funptr), VALUE, intent (in) :: Func_ptr
end function C_Func_using_Func_ptr
end interface C_func_interface
contains
function my_poly (x) bind (C, name="my_poly")
real (c_float) :: my_poly
real (c_float), VALUE, intent (in) :: x
my_poly = 2.0 * x**2 + 3.0 * x + 5.0
return
end function my_poly
end module func_pointer_mod
program test_func_pointer
use, intrinsic :: iso_c_binding
use func_pointer_mod
implicit none
type (c_funptr) :: C_func_ptr
C_func_ptr = c_funloc ( my_poly )
write (*, *) C_Func_using_Func_ptr ( 2.5_c_float, C_func_ptr )
stop
end program test_func_pointer
and
float C_Func_using_Func_ptr (
float x,
float (*Func_ptr) (float y)
) {
return ( (*Func_ptr) (x) );
}