Subsections


6 Code issues

This chapter gives detailed information on the generated code by Free Pascal. It can be useful to write external object files which will be linked to Free Pascal created code blocks.


1 Register Conventions

The compiler has different register conventions, depending on the target processor used; some of the registers have specific uses during the code generation. The following section describes the generic names of the registers on a platform per platform basis. It also indicates what registers are used as scratch registers, and which can be freely used in assembler blocks.

1 accumulator register

The accumulator register is at least a 32-bit integer hardware register, and is used to return results of function calls which return integral values.

2 accumulator 64-bit register

The accumulator 64-bit register is used in 32-bit environments and is defined as the group of registers which will be used when returning 64-bit integral results in function calls. This is a register pair.

3 float result register

This register is used for returning floating point values from functions.

4 self register

The self register contains a pointer to the actual object or class. This register gives access to the data of the object or class, and the VMT pointer of that object or class.

5 frame pointer register

The frame pointer register is used to access parameters in subroutines, as well as to access local variables. References to the pushed prameters and local variables are constructed using the frame pointer. [*].

6 stack pointer register

The stack pointer is used to give the address of the stack area, where the local variables and parameters to subroutines are stored.

7 scratch registers

Scratch registers are those which can be used in assembler blocks, or in external object files without requiring any saving before usage.

8 Processor mapping of registers

This indicates what registers are used for what purposes on each of the processors supported by Free Pascal. It also indicates which registers can be used as scratch registers.

1 Intel 80x86 version


Table: Intel 80x86 Register table
Generic register name CPU Register name
accumulator EAX
accumulator (64-bit) high / low EDX:EAX
float result FP(0)
self ESI
frame pointer EBP
stack pointer ESP
scratch regs. N/A

2 Motorola 680x0 version


Table: Motorola 680x0 Register table
Generic register name CPU Register name
accumulator D0[*]
accumulator (64-bit) high / low D0:D1
float result FP0[*]
self A5
frame pointer A6
stack pointer A7
scratch regs. D0, D1, A0, A1, FP0, FP1


2 Name mangling

Contrary to most C compilers and assemblers, all labels generated to pascal variables and routines have mangled names[*]. This is done so that the compiler can do stronger type checking when parsing the pascal code. It also permits function and procedure overloading.

1 Mangled names for data blocks

The rules for mangled names for variables and typed constants are as follows:

Currently, in Free Pascal v1.0, if you declare a variable in unit name tunit, with the name _a, and you declare the same variable with name a in unit name tunit_, you will get the same mangled name. This is a limitation of the compiler which will be fixed in release v1.1.

Examples

unit testvars;

interface

const
 publictypedconst : integer = 0;
var
 publicvar : integer;

implementation
const
 privatetypedconst : integer = 1;
var
 privatevar : integer;

end.

Will give the following assembler output under GNU as :

	.file "testvars.pas"

.text

.data
# [6] publictypedconst : integer = 0;
.globl	TC__TESTVARS$$_PUBLICTYPEDCONST
TC__TESTVARS$$_PUBLICTYPEDCONST:
	.short	0
# [12] privatetypedconst : integer = 1;
TC__TESTVARS$$_PRIVATETYPEDCONST:
	.short	1

.bss
# [8] publicvar : integer;
	.comm	U_TESTVARS_PUBLICVAR,2
# [14] privatevar : integer;
	.lcomm	_PRIVATEVAR,2

2 Mangled names for code blocks

The rules for mangled names for routines are as follows:

The following constructs

unit testman;

interface
type
  myobject = object
   constructor init;
   procedure mymethod;
  end;

implementation

  constructor myobject.init;
  begin
  end;

  procedure myobject.mymethod;
  begin
  end;

  function myfunc: pointer;
  begin
  end;

  procedure myprocedure(var x: integer; y: longint; z : pchar);
  begin
  end;

end.

will result in the following assembler file for the Intel 80x86 target:

	.file "testman.pas"

.text
	.balign 16
.globl	_TESTMAN$$_$$_MYOBJECT_$$_INIT
_TESTMAN$$_$$_MYOBJECT_$$_INIT:
	pushl	%ebp
	movl	%esp,%ebp
	subl	$4,%esp
	movl	$0,%edi
	call	FPC_HELP_CONSTRUCTOR
	jz	.L5
	jmp	.L7
.L5:
	movl	12(%ebp),%esi
	movl	$0,%edi
	call	FPC_HELP_FAIL
.L7:
	movl	%esi,%eax
	testl	%esi,%esi
	leave
	ret	$8
	.balign 16
.globl	_TESTMAN$$_$$_MYOBJECT_$$_MYMETHOD
_TESTMAN$$_$$_MYOBJECT_$$_MYMETHOD:
	pushl	%ebp
	movl	%esp,%ebp
	leave
	ret	$4
	.balign 16
_TESTMAN$$_MYFUNC:
	pushl	%ebp
	movl	%esp,%ebp
	subl	$4,%esp
	movl	-4(%ebp),%eax
	leave
	ret
	.balign 16
_TESTMAN$$_MYPROCEDURE$INTEGER$LONGINT$PCHAR:
	pushl	%ebp
	movl	%esp,%ebp
	leave
	ret	$12

3 Modifying the mangled names

To make the symbols externally accessible, it is possible to give nicknames to mangled names, or to change the mangled name directly. Two modifiers can be used:

cdecl:
A function that has a cdecl modifier, will be used with C calling conventions, that is, the caller clears the stack. Also the mangled name will be the name exactly as it is declared. cdecl is part of the function declaration, and hence must be present both in the interface and implementation section of a unit.

alias:
The alias modifier can be used to assign a second assembler label to your function. This label has the same name as the alias name you declared. This doesn't modify the calling conventions of the function. In other words, the alias modifier allows you to specify another name (a nickname) for your function or procedure.

The prototype for an aliased function or procedure is as follows:

Procedure AliasedProc; alias : 'AliasName';
The procedure AliasedProc will also be known as AliasName. Take care, the name you specify is case sensitive (as C is).

Furthermore, the exports section of a library is also used to declare the names that will be exported by the shared library. The names in the exports section are case-sensitive (while the actual declaration of the routine is not). For more information on the creating shared libraries, chapter libraries.


3 Calling mechanism

Procedures and Functions are called with their parameters on the stack. Contrary to Turbo Pascal, all parameters are pushed on the stack, and they are pushed right to left, instead of left to right for Turbo Pascal. This is especially important if you have some assembly subroutines in Turbo Pascal which you would like to translate to Free Pascal.

Function results are returned in the accumulator, if they fit in the register. Methods calls (from either objects or clases) have an additional invisible parameter which is self. This parameter is the leftmost parameter within a method call (it is therefore the last parameter passed to the method).

When the procedure or function exits, it clears the stack.

Other calling methods are available for linking with external object files and libraries, these are summarized in table (CallingTable) . The first column lists the modifier you specify for a procedure declaration. The second one lists the order the paramaters are pushed on the stack. The third column specifies who is responsible for cleaning the stack: the caller or the called function. The alignment column indicates the alignment of the parameters sent to the stack area. Finally, the fifth column indicates if any registers are saved in the entry code of the subroutine.


Table: Calling mechanisms in Free Pascal
Modifier Pushing order Stack cleaned by alignment registers saved
<none> Right-to-left Function default None
cdecl Right-to-left Caller GCC alignment GCC registers
interrupt Right-to-left Function default all registers
pascal Left-to-right Function default None
safecall Right-to-left Function default GCC registers
stdcall Right-to-left Function GCC alignment GCC registers
popstack Right-to-left Caller default None
register Left-to-right Caller default None

More about this can be found in chapter Linking on linking. Information on GCC registers saved, GCC stack alignment and general stack alignment on an operating system basis can be found in Appendix [*]. The register modifier is currently not supported, and maps to the default calling convention.

Furthermore, the saveregisters modifier can be used with any of the calling mechanism specifiers. When saveregisters is used, all registers will be saved on entry to the routine, and will be restored upon exit. Of course, if the routine is a function, and it normally returns its retun value in a register, that register will not be saved. Also, if the self register is used, it will also neither be saved nor restored.


4 Nested procedure and functions

When a routine is declared within the scope of a procedure or function, it is said to be nested. In this case, an additional invisible parameter is passed to the nested routine. This additional parameter is the frame pointer address of the calling routine. This permits the nested routine to access the local variables and parameters of the calling routine.

The resulting stack frame after the entry code of a simple nested procedure has been executed is shown in table (NestedStackFrame32) .

Table: Stack frame when calling a nested procedure (32-bit processors)
Offset from frame pointer What is stored
+x parameters
+8 Frame pointer of parent routine
+4 Return address
+0 Saved frame pointer


5 Constructor and Destructor calls

Constructor and destructors have special invisible parameters which are passed to them. These invisible parameters are used internally to instanciate the objects and classes.

1 objects

The actual invisible declaration of an object constructoir is as follows:

  constructor init(_vmt : pointer; _self : pointer ...);

Where _vmt is a pointer to the virtual method table for this object. This value is nil if a constructor is called within the object instance (such as calling an ihnerited constructor).

_self is either nil if the instance must be allocated dynamically (object is declared as pointer), or the address of the object instance if the object is declared as a normal object (stored in the data area) or if the object instance has already been allocated.

The allocated instance (if allocated via new) (self) is returned in the accumulator.

The declaration of a destructor is as follows:

  destructor done(_vmt : pointer; _self : pointer ...);

Where _vmt is a pointer to the virtual method table for this object. This value is nil if a destructor is called within the object instance (such as calling an ihnerited constructor), or if the object instance is a variable and not a pointer.

_self is the address of the object instance.

2 classes

The actual invisible declaration of a class constructoir is as follows:

  constructor init(_vmt: pointer; flag : longint; ..);

_vmt is either nil if called from the instance or if calling an inherited constructor, otherwise it points to the address of the virtual method table.

Where flag is zero if the constructor is called within the object instance or with an instance qualifier otherwise this flag is set to one.

The allocated instance (self) is returned in the accumulator.

The declaration of a destructor is as follows:

  destructor done(_self : pointer; flag : longint ...);

_self is the address of the object instance.

flag is zero if the destructor is called within the object instance or with an instance qualifier otherwise this flag is set to one.

6 Entry and exit code

Each Pascal procedure and function begins and ends with standard epilogue and prologue code.

1 Intel 80x86 standard routine prologue / epilogue

Standard entry code for procedures and functions is as follows on the 80x86 architecture:
   pushl   %ebp
   movl    %esp,%ebp

The generated exit sequence for procedure and functions looks as follows:

   leave
   ret  $xx

Where xx is the total size of the pushed parameters.

To have more information on function return values take a look at section RegConvs.

2 Motorola 680x0 standard routine prologue / epilogue

Standard entry code for procedures and functions is as follows on the 680x0 architecture:

   move.l  a6,-(sp)
   move.l  sp,a6

The generated exit sequence for procedure and functions looks as follows (in the default processor mode):

   unlk   a6
   rtd    #xx

Where xx is the total size of the pushed parameters.

To have more information on function return values take a look at section RegConvs.


7 Parameter passing

When a function or procedure is called, then the following is done by the compiler:

  1. If there are any parameters to be passed to the procedure, they are pushed from right to left on the stack.
  2. If a function is called that returns a variable of type String, Set, Record, Object or Array, then an address to store the function result in, is pushed on the stack.
  3. If the called procedure or function is an object method, then the pointer to self is pushed on the stack.
  4. If the procedure or function is nested in another function or procedure, then the frame pointer of the parent procedure is pushed on the stack.
  5. The return address is pushed on the stack (This is done automatically by the instruction which calls the subroutine).

The resulting stack frame upon entering looks as in table (StackFrame) .

Table: Stack frame when calling a procedure (32-bit model)
Offset What is stored Optional?
+x parameters Yes
+12 function result Yes
+8 self Yes
+4 Return address No
+0 Frame pointer of parent procedure Yes

1 Parameter alignment

Each parameter passed to a routine is guaranteed to decrement the stack pointer by a certain minimum amount. This behavior varies from one operating system to another. For example, passing a byte as a value parameter to a routine could either decrement the stack pointer by 1, 2, 4 or even 8 bytes depending on the target operating system and processor. The minimal default stack pointer decrement value is given in Appendix [*].

For example, on FREEBSD, all parameters passed to a routine guarantee a minimal stack decrease of four bytes per parameter, even if the parameter actually takes less then 4 bytes to store on the stack (such as passing a byte value parameter to the stack).


8 Processor limitations

Certain processors have limitations on the size of the parameters and local variables in routines. This is shown in table (CPULimits) .


Table: Maximum limits for processors
Processor Parameters Local variables
Intel 80x86 (all) 64K No limit
Motorola 68020 (default) 32K No limit
Motorola 68000 32K 32K

Furthermore, the m68k compiler, in 68000 mode, limits the size of data elements to 32K (arrays, records, objects, etc.). This restriction does not exist in 68020 mode.




2004-02-13