20.3.5 The QuickPascal/MASM Interface

The QuickPascal implementation of Pascal uses several data types and defaults that are different from version 4.0 of the Microsoft Pascal compiler. This section summarizes the techniques for calling MASM procedures from QuickPascal and for accessing QuickPascal data and routines from MASM. The following information also applies to other compilers that are compatible with QuickPascal.

The Pascal calling convention pushes arguments in the order listed and exports identifiers in uppercase.

Compatible Data Types

This list gives the QuickPascal data types that are equivalent to the MASM 6.0 data types.

QuickPascal Type Equivalent MASM Type  
Char, Boolean BYTE  
Byte, ShortInt SBYTE  
Word WORD  
Integer SWORD  
Single REAL4  
LongInt SDWORD  
Real FWORD  
Comp, Double REAL8  
Extended REAL10  

Naming Restrictions

The first 63 characters of QuickPascal identifiers are significant. Identifiers are not case sensitive and the first character must be a letter or an underscore character (_). Digits can be used in the indentifier's name.

Summary: By default, Pascal passes arguments by value.

Register Preservation

Procedures called by QuickPascal must preserve the values of the BP, SP, SS, and DS registers. BP and SP are preserved by standard entry and exit code. If you need to alter DS or SS, you must preserve the current values.

Argument-Passing Defaults

When an argument is passed by value, QuickPascal takes different actions depending on the data type and size. This convention for value parameters is not shared by other Microsoft high-level languages, which always push arguments passed by value directly onto the stack.

Enumerated type arguments are passed as unsigned bytes if the enumeration has 256 or fewer values; otherwise they are passed as an unsigned word.

Types Single (4 bytes), Real (6 bytes), Double (8 bytes), Comp (8 bytes), and Extended (10 bytes) are passed on the stack.

Pointer types are passed as doublewords. The segment is pushed before the offset so the offset is lowest in memory.

If the value parameter is Char, Boolean, any pointer, any Integer, or any floating-point type, QuickPascal pushes the argument onto the stack.

If the argument is a string or set type, QuickPascal passes a pointer to the data. This action is really the same as passing by reference. If you want to avoid any possibility of altering the data, make a temporary copy of the data and then work with the temporary data.

If the argument is an array or record type and if it is not more than four bytes long, QuickPascal pushes the variable directly onto the stack. Otherwise, it pushes a pointer to the data.

When an argument is passed by reference, QuickPascal pushes a four-byte pointer to the data. The offset portion of the pointer is always pushed first and is therefore higher in memory.

Changing the Calling Convention

QuickPascal supports only the Pascal calling convention.

Equivalent Arrays

Arrays are stored in row-major order. Arrays (and records with one, two, or four bytes) are passed directly on the stack.

String Format

In the STRING format, the first byte of the string stores the string length. In the CSTRING format, there is no length indicator and there is a terminating null byte.

External Data

You cannot declare public data in a data segment of the MASM module for the QuickPascal module to reference. QuickPascal can use private, static data in MASM modules; however, the data declared in the MASM module must be initialized with ?. MASM can reference data in a QuickPascal unit.

Structure Alignment

QuickPascal records are byte-aligned.

Compiling and Linking

For QuickPascal to access an assembled MASM module (named MASMMOD.OBJ), include this line at the beginning of your QuickPascal program:

{$L QPEX.OBJ}

Summary: You do not need to use LINK or any other utility to produce executable files.

QuickPascal sets up the link to the MASM module by copying the MASM object file into the program and changing the file into its own internal object-code format. The disk-based object file is left unchanged.

Returning Values

To return a value to a QuickPascal module, follow these conventions:

For a String, CSTRING, Comp, or floating-point type other than Real, QuickPascal passes an additional argument. This argument is pushed first and is a pointer to a temporary storage location. The function must place the result of the function in this location and not remove this pointer.

For ordinal types, (including Char, Boolean, and any integer), place the result in AL if one byte, in AX if two bytes, and in DX:AX if a doubleword (in which DX holds the most-significant byte).

QuickPascal does not support functions that return array or record types. However, you can set the value of an array or record if QuickPascal passes it as a VAR parameter.

Example

This example includes a Pascal program to call the assembly module Power2.

{$L QPEX.OBJ}

program Asmtest( input, output );

function POWER2( factor:integer; power:integer ): integer; external;

begin

writeln( '3 times 2 to the power of 5 is ', POWER2( 3, 5 ) );

end.

This is the assembly module to be called from the Pascal program.

Power2 PROTO PASCAL factor:WORD, power:WORD

CODESEGMENT WORD PUBLIC

ASSUME CS:CODE

Power2 PROC PASCAL factor:WORD, power:WORD

mov ax, factor ; Load factor into AX

mov cx, power ; Load power into CX

shl ax, cl ; AX = AX * (2 to power of CX)

; Leave return value in AX

ret

Power2 ENDP

CODE ENDS

END

You cannot use the /Zi command-line option when assembling a module to be called from QuickPascal.