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.


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

When using objects that need virtual methods, the compiler uses two help procedures that are in the run-time library. They are called FPC_HELP_DESTRUCTOR and FPC_HELP_CONSTRUCTOR. They are used to allocate the necessary memory if needed, and to insert the Virtual Method Table (VMT) pointer in the newly allocated object.

When the compiler encounters a call to an object's constructor, it sets up the stack frame for the call, and inserts a call to the FPC_HELP_CONSTRUCTOR procedure before issuing the call to the real constructor. The helper procedure allocates the needed memory (if needed) and inserts the VMT pointer in the object. After that, the real constructor is called.

A call to FPC_HELP_DESTRUCTOR is inserted in every destructor declaration, just before the destructor's exit sequence, it deallocates the memory allocated in the constructor.

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:

   unlk   a6
   move.l (sp)+,a0     ; Get return address
   add.l  #xx,sp       ; Remove allocated stack
   move.l a0,-(sp)     ; Put back return address on top of the stack

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).

2 Processor limitations

Certain processors have limitations on the size of the parameters which can be passed to routine. This is shown in table (CPUStackLimits) .


Table: Maximum parameter sizes for processors
Processor Limit (in Bytes)
Intel 80x86 64K
Motorola 680x0 32K



Free Pascal Compiler
2001-09-22