As of version 0.9.7, Free Pascal supports Intel syntax for the Intel family of Ix86 processors in it's asm blocks.
The Intel syntax in your asm block is converted to AT&T syntax by the compiler, after which it is inserted in the compiled source. The supported assembler constructs are a subset of the normal assembly syntax. In what follows we specify what constructs are not supported in Free Pascal, but which exist in Turbo Pascal:
mov al, byte ptr MyWord -- allowed, mov al, byte(MyWord) -- allowed, mov al, shortint(MyWord) -- not allowed.
const s= 10; const t = 32767;in Turbo Pascal:
mov al, byte(s) -- useless typecast. mov al, byte(t) -- syntax error!In this parser, either of those cases will give out a syntax error.
mov al,byte ptr ['c'] -- not allowed. mov al,byte ptr [100h] -- not allowed.(This is due to the limitation of Turbo Assembler).
mov al,[ds:bx] -- not alloweduse instead:
mov al,ds:[bx]
const myscale = 1; ... mov al,byte ptr [esi+ebx*myscale] -- not allowed.use:
mov al, byte ptr [esi+ebx*1]
@: -- not alloweduse instead, for example:
@1: -- allowed
lds si,@mylabel -- not allowed
mov al,[byte ptr myvar] -- not allowed.use:
mov al,byte ptr [myvar] -- allowed.
The Intel inline assembler supports the following macros :
Section:[Base + Index*Scale + Offs]is written in AT&T syntax as :
Section:Offs(Base,Index,Scale)Where Base and Index are optional 32-bit base and index registers, and Scale is used to multiply Index. It can take the values 1,2,4 and 8. The Section is used to specify an optional section register for the memory operand.
More information about the AT&T syntax can be found in the as manual, although the following differences with normal AT&T assembly must be taken into account :
const myid = 10; ... movl $myid,%eax -- allowed movl myid(%esi),%eax -- not allowed.
The AT&T inline assembler supports the following macros :
Function results are returned in the accumulator, if they fit in the register.
The registers are not saved when calling a function or procedure. If you want to call a procedure or function from assembly language, you must save any registers you wish to preserve.
When you call an object method from assembler, you must load the ESI register with the self pointer of the object or class.
The first thing a procedure does is saving the base pointer, and setting the base pointer equal to the stack pointer. References to the pushed parameters and local variables are constructed using the base pointer.
When the procedure or function exits, it clears the stack.
When you want your code to be called by a C library or used in a C program, you will run into trouble because of this calling mechanism. In C, the calling procedure is expected to clear the stack, not the called procedure. In other words, the arguments still are on the stack when the procedure exits. To avoid this problem, Free Pascal supports the export modifier. Procedures that are defined using the export modifier, use a C-compatible calling mechanism. This means that they can be called from a C program or library, or that you can use them as a callback function.
This also means that you cannot call this procedure or function from your own program, since your program uses the Pascal calling convention. However, in the exported function, you can of course call other Pascal routines.
As of version 0.9.8, the Free Pascal compiler supports also the cdecl and stdcall modifiers, as found in Delphi. The cdecl modifier does the same as the export modifier, and stdcall does nothing, since Free Pascal pushes the paramaters from right to left by default. In addition to the Delphi cdecl construct, Free Pascal also supports the popstack directive; it is nearly the same a the cdecl directive, only it still mangles the name, i.e. makes it into a name such as the compiler uses internally.
All this is summarized in table (Calling) . 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. Finally, the last column specifies if registers are used to pass parameters to the function.
More about this can be found in chapter Linking on linking.
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.
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.
asm ... end ['R1',...,'Rn'];Here R1 to Rn are the names of the 32-bit registers you modify in your assembly code.
As an example :
asm movl BP,%eax movl 4(%eax),%eax movl %eax,__RESULT end ['EAX'];This example tells the compiler that the EAX register was modified.
The compiler has different register conventions, depending on the target processor used.
When optimizations are on, no register can be freely modified, without first being saved and then restored. Otherwise, EDI is usually used as a scratch register and can be freely used in assembler blocks.
Registers which can be freely modified without saving are registers D0, D1, D6, A0, A1, and floating point registers FP2 to FP7. All other registers are to be considered reserved and should be saved and then restored when used in assembler blocks.