20.3.2 The FORTRAN/MASM Interface

This section summarizes the specific details important to calling FORTRAN procedures or receiving arguments from FORTRAN routines that call MASM routines. It includes a sample MASM and FORTRAN module. A FORTRAN procedure follows the Pascal calling convention by default. This convention passes arguments in the order listed, and the calling procedure removes the arguments from the stack. The naming convention determines that exported names are uppercase.

Compatible Data Types

This list shows the FORTRAN data types that are equivalent to the MASM 6.0 data types.

FORTRAN Type Equivalent MASM Type  
CHARACTER*1 BYTE  
INTEGER*1 SBYTE  
INTEGER*2 SWORD  
REAL*4 REAL4  
INTEGER*4 SDWORD  
REAL*8, DOUBLE PRECISION REAL4  

Naming Restrictions

FORTRAN allows 31 characters for identifier names. A digit or an underscore cannot be the first character in an identifier name.

Argument-Passing Defaults

By default, FORTRAN passes arguments by reference as far addresses if the FORTRAN module is compiled in large or huge memory model. It passes them as near addresses if the FORTRAN module is compiled in medium model. Versions of FORTRAN prior to Version 4.0 always requires large model.

The FORTRAN compiler passes an argument by value when declared with the VALUE attribute. This declaration can occur either in a FORTRAN INTERFACE block (which determines how to pass an argument) or in a function or subroutine declaration (which determines how to receive an argument).

In FORTRAN you can apply the NEAR (or FAR) attribute to reference param-eters. These keywords override the default. They have no effect when they specify the same method as the default.

Changing the Calling Convention

A call to a FORTRAN function or subroutine declared with the PASCAL or C attribute passes all arguments by value in the parameter list (except for parameters declared with the REFERENCE attribute). This change in default passing method applies to function and subroutine definitions as well as to the functions and subroutines described by INTERFACE blocks.

Equivalent Arrays

When you declare FORTRAN arrays, you can specify any integer for the lower bound (the default is 1). The FORTRAN compiler stores all arrays in column-major order—that is, the leftmost subscript increments most rapidly. For example, the first seven elements of an array defined as A[3,4] are stored as

A[1,1], A[2,1], A[3,1], A[1,2], A[2,2], A[3,2], A[1,3]

Summary: FORTRAN strings do not have an end-of-string delimiter.

String Format

FORTRAN stores strings as a series of bytes at a fixed location in memory, with no delimiter at the end of the string. When passing a variable-length FORTRAN string to another language, you need to devise a method by which the target routine can find the end of the string.

Consider the string declared as

CHARACTER*14 MSG

MSG = 'String of text'

The string is stored in 14 bytes of memory like this:

Strings are passed by reference. Although FORTRAN has a method for passing length, the variable-length FORTRAN strings cannot be used in a mixed-language interface because other languages cannot access the temporary variable that FORTRAN uses to communicate string length. However, fixed-length strings can be passed if the FORTRAN INTERFACE statement declares the length of the string in advance.

External Data

FORTRAN routines can directly access external data. In FORTRAN you can declare data to be external by adding the EXTERN attribute to the data declaration. You can also access a FORTRAN variable from MASM if it is declared in a COMMON block.

A FORTRAN program can call an external assembly procedure with the use of the INTERFACE statement. However, the INTERFACE statement is not strictly necessary unless you intend to change one of the FORTRAN defaults.

Structure Alignment

By default, FORTRAN uses word alignment (packed storage) for all data objects larger than one byte. This storage method specifies that occasional bytes may be added as padding, so that word and doubleword objects start on an even boundary. In addition, all nested structures and records start on a word boundary. MASM's default is byte-alignment, so specify an alignment of 2 for MASM structures or use the /Zp1 option when compiling in FORTRAN.

Compiling and Linking

Use the same memory model for the MASM and FORTRAN modules.

Returning Values

You must use a special convention to return floating-point values, records, user-defined types, arrays, and values larger than four bytes to a FORTRAN module from an assembly procedure. The FORTRAN module creates space in the stack segment to hold the actual return value. When the call to the assembly procedure is made, an extra parameter is passed. This parameter is the last one pushed. The segment address of the return value is contained in SS.

In the assembly procedure, put the data for the return value at the location pointed to by the return value offset. Then copy the return-value offset (located at BP + 6) to AX, and copy SS to DX. This is necessary because the calling module expects DX:AX to point to the return value.

Structures, Records, and User-Defined Data Types

The FORTRAN structure variable, defined with the STRUCTURE keyword and declared with the RECORD statement, is equivalent to the Pascal RECORD and the C struct. You can pass structures as arguments by value or by reference (the default).

Summary: MASM structures can be compatible with FORTRAN COMPLEX types.

The FORTRAN types COMPLEX*8 and COMPLEX*16 are not directly implemented in MASM. However, you can write structures that are equivalent. The type COMPLEX*8 has two fields, both of which are four-byte floating-point numbers; the first contains the real component, and the second contains the imaginary component. The type COMPLEX is equivalent to the type COMPLEX*8.

The type COMPLEX*16 is similar to COMPLEX*8. The only difference is that each field of the former contains an eight-byte floating-point number.

A FORTRAN LOGICAL*2 is stored as a one-byte indicator value (1=true, 0=false) followed by an unused byte. A FORTRAN LOGICAL*4 is stored as a one-byte indicator value followed by three unused bytes. The type LOGICAL is equivalent to LOGICAL*4, unless $STORAGE:2 is in effect.

To pass or receive a FORTRAN LOGICAL type, declare a MASM structure with the appropriate fields.

Varying Number of Arguments

In FORTRAN, you can call routines with a variable number of arguments by including the VARYING attribute in your interface to the routine, along with the C attribute. You must use the C attribute because a variable number of arguments is possible only with the C calling convention. The VARYING attribute prevents FORTRAN from enforcing a matching number of parameters.

Summary: LOCNEAR and LOCFAR determine addresses.

Pointers and Addresses

FORTRAN programs can determine near and far addresses with the LOCNEAR and LOCFAR functions. Store the result as INTEGER*2 (with the LOCNEAR function) or as INTEGER*4 (with the LOCFAR function). If you pass the result of LOCNEAR or LOCFAR to another language, be sure to pass by value.

Example

In the following example, the FORTRAN module calls an assembly procedure that calculates A*2^B, where A and B are the first and second parameters, respectively. This is done by shifting the bits in A to the left B times.

INTERFACE TO INTEGER*2 FUNCTION POWER2(A, B)

INTEGER*2 A, B

END

PROGRAM MAIN

INTEGER*2 POWER2

INTEGER*2 A, B

A = 3

B = 5

WRITE (*, *) '3 TIMES 2 TO THE B OR 5 IS ',POWER2(A, B)

END

To understand how to write the assembly procedure, consider how the param-eters are placed on the stack, as illustrated in Figure 20.4.

Figure 20.4 assumes that the FORTRAN module is compiled in large model. If you compile the FORTRAN module in medium model, then each argument is passed as a two-byte, not four-byte, address. The return address is four bytes long because procedures called from FORTRAN must always be FAR.

The assembler code looks like this:

.MODEL LARGE, FORTRAN

Power2 PROTO FORTRAN, factor:FAR PTR SWORD, power:FAR PTR SWORD

.CODE

Power2 PROC FORTRAN, factor:FAR PTR SWORD, power:FAR PTR SWORD

les bx, factor

mov ax, ES:[bx]

les bx, power

mov cx, ES:[bx]

shl ax, cl

ret

Power2 ENDP END