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
- AT&T indicates absolute jump/call operands with ’*’, Intel syntax doesn’t delimit
- 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
Segment:[Base + Index*Scale + Offs]
is written in AT&T syntax as:
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
- 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
- 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.