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.
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 |
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.
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.
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.
Arrays are stored in row-major order. Arrays (and records with one, two, or four bytes) are passed directly on the stack.
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.
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.
QuickPascal records are byte-aligned.
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.
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.
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.