In earlier versions, Free Pascal used only the gnu as assembler to generate its object files for the Intel x86 processors. Only after some time, an internal assembler was created, which wrote directly to an object file.
Since the gnu assembler uses AT&T assembly syntax, the code you write should use the same syntax. The differences between AT&T and Intel syntax as used in Turbo Pascal are summarized in the following:
The opcode names include the size of the operand. In general, one can say that the AT&T opcode name is the Intel opcode name, suffixed with a ’l’, ’w’ or ’b’ for, respectively, longint (32 bit), word (16 bit) and byte (8 bit) memory or register references. As an example, the Intel construct ’mov al, bl is equivalent to the AT&T style ’movb %bl,%al’ instruction.
AT&T immediate operands are designated with ’$’, while Intel syntax doesn’t use a prefix for immediate operands. Thus the Intel construct ’mov ax, 2’ becomes ’movb $2, %al’ in AT&T syntax.
AT&T register names are prefixed with a ’%’ sign. They are not delimited in Intel syntax.
AT&T indicates absolute jump/call operands with ’*’, Intel syntax doesn’t delimit these addresses.
The order of the source and destination operands is reversed. AT&T syntax uses ’Source, Dest’, while Intel syntax features ’Dest, Source’. Thus the Intel construct ’add eax, 4’ transforms to ’addl $4, %eax’ in the AT&T dialect.
Immediate long jumps are prefixed with the ’l’ prefix. Thus the Intel ’call/jmp section:offset’ is transformed to ’lcall/ljmp $section,$offset’. Similarly, the far return is ’lret’, instead of the Intel ’ret far’.
Memory references are specified differently in AT&T and Intel assembly. The Intel indirect memory reference
Segment:[Base + Index*Scale + Offs]
is written in AT&T syntax as:
Segment: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 Segment is used to specify an optional segment 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:
Only the following directives are presently supported:
The following directives are recognized but are not supported:
Eventually they will be supported.
Directives are case sensitive, other identifiers are not case sensitive.
Contrary to gas, local labels/symbols must start with .L.
The not operator ’!’ is not supported.
String expressions in operands are not supported.
CBTW,CWTL,CWTD and CLTD are not supported, use the normal Intel equivalents instead.
Constant expressions which represent memory references are not allowed, even though constant immediate value expressions are supported. Examples:
const myid = 10; ... movl $myid,%eax -- allowed movl myid(%esi),%eax -- not allowed.
When the .globl directive is found, the symbol immediately following it is made public and is immediately emitted. Therefore label names with this name will be ignored.
Only Single and Double FPU opcodes are supported.
The AT&T inline assembler supports the following macros:
represents the function result return value.
represents the object method pointer in methods.
represents the old base pointer in recursive routines.