[comp.lang.c] linking with Fortran subroutines

rr@linus.UUCP (Robert Rifkin) (12/28/87)

I am trying to link C code with some canned Fortran routines
(the NAG math library) on a Unix-based system. 
I understand that Fortran subroutines
pass arguments by address, so the calling C code must use
addresses to be compatible.  However, one snag that I still have
is that the Fortran routine passes a function name through the
subroutine call e.g.
       external function
       .
       .
       call x (function, a,b,c...)
where "function" is the function , and a,b,and c are variables.
I believe that what Fortran does is that "function" passes the address
of where the actual function begins.  
   I've tried C-code calls like
     double precision *functioin( );
     .
     .
     x_(function, &a,&b,&c);
to no avail.  Does anyone have any suggestions for solving this
problem?


-- 
    Robert Rifkin               Phone: (617) 271-2302
    The MITRE Corporation       ARPA: linus!rr@MITRE-BEDFORD
    Bedford, MA  01730		UUCP: decvax!linus!rr

gwk@mitre-bedford.arpa (Glenn Karcher MITRE/D74) (12/29/87)

Concerning the passing of an external address, let me suggest a method that
I have used in the past, namely, use a compiler option to generate the
equivalent assembly language code for the FORTRAN compiler that you are
dealing with (fortunately, most compilers have this option).  Of course,
the exact linkage mechanism is going to vary depending on the exact
compiler/machine system you will be working on, and it is a bit tedious,
but it does get the job done.  NOTE:  You might have to apply the same method
to both the calling program and the called program in order to find out
how each language handles the problem.

As an example, I did the following on under ULTRIX (in case you hadn't
read the header, I also work here at MITRE in the software center), on
the MBUNIX machine.  I used the "f77" command with the -S option to get the
object code listing for FORTRAN.  I also used the "cc" command with -S option
for the C language.  The following should work, as it turns out for this
system, you can achieve the desired results by just passing the procedure
as a parameter, without the use of indirection.

The following FORTRAN program generates the assembly code that is interspersed.
I cut out some of the overhead code to hopefully make it simpler:

C
C  Test of code generation for external function call
C
       REAL A, B, C
       EXTERNAL XYZ
C
C  The offending call
C
       CALL MYFUNC ( XYZ, A, B, C )

>>
>> -- generated assembly code for FORTRAN
>>
>> addl3	$v.4-v.1,r11,r0
>> pushl	r0                 ; address of C, longword
>> addl3	$v.3-v.1,r11,r0
>> pushl	r0                 ; address of B, longword
>> addl3	$v.2-v.1,r11,r0
>> pushl	r0                 ; address of A, longword
>> pushl	$_xyz_             ; address of XYZ, longword
>> calls	$4,_myfunc_        ; call the function

       END

The following C routine should represents the same calling sequence from C.

main ()
{
  float A, B, C ;
  float xyz_ () ;       /* note the procedure name to get correct 
                           characters and trailing underscore     */
  void  MYFUNC () ;

  MYFUNC ( xyz_, &A, &B, &C ) ;

>>
>> -- generated assembly code for C
>>
>> subl3	$12,fp,r0           ; address of C
>> pushl	r0
>> subl3	$8,fp,r0            ; address of B
>> pushl	r0
>> subl3	$4,fp,r0            ; address of A
>> pushl	r0
>> pushl	$_xyz_              ; address of xyz
>> calls	$4,_MYFUNC          ; procedure call

}

I hope that this is the answer you needed.  If there is more, please feel
free to call me.  I have had to do this kind of activity on a few different
machines in the past, and it can be fun (strange sense of fun, isn't it).
Let me know how it works out.

Regards,

Glenn Karcher      (MITRE/D74)  Phone: 377-6873
                                   Yes, that is the base (dial 122-3-6873)
                                   from inside of MITRE.

flaps@dgp.toronto.edu (Alan J Rosenthal) (01/03/88)

In article <20615@linus.UUCP> rr@linus.UUCP (Robert Rifkin) writes:
 >I believe that what Fortran does is that "function" passes the address
 >of where the actual function begins.  
 >   I've tried C-code calls like
 >     double precision *function( );
 >     .
 >     .
 >     x_(function, &a,&b,&c);
 >to no avail.

I believe you might mean "double (*function)()" not "double *function()".

-- 
"Bill Joy uses EMACS."  - D. Hugh Redelmeier