The 386 assembler included in Gforth was written by Bernd Paysan, it’s available under GPL, and originally part of bigFORTH.
The 386 disassembler included in Gforth was written by Andrew McKewan and is in the public domain.
The disassembler displays code in an Intel-like prefix syntax.
The assembler uses a postfix syntax with AT&T-style parameter order (i.e., destination last).
The assembler includes all instruction of the Athlon, i.e. 486 core instructions, Pentium and PPro extensions, floating point, MMX, 3Dnow!, but not ISSE. It’s an integrated 16- and 32-bit assembler. Default is 32 bit, you can switch to 16 bit with .86 and back to 32 bit with .386.
There are several prefixes to switch between different operation sizes,
.b for byte accesses,
.w for word accesses,
double-word accesses. Addressing modes can be switched with
for 16 bit addresses, and
.da for 32 bit addresses. You don’t
need a prefix for byte register names (
AL et al).
For floating point operations, the prefixes are
.fl (IEEE double),
.fd (double-word), and
.fq (quad-word). The
.fx, so you need to specify
when dealing with Gforth FP values.
The MMX opcodes don’t have size prefixes, they are spelled out like in the Intel assembler. Instead of move from and to memory, there are PLDQ/PLDD and PSTQ/PSTD.
The registers lack the ’e’ prefix; even in 32 bit mode, eax is called
ax. Immediate values are indicated by postfixing them with
3 #. Here are some examples of addressing modes in various
Gforth Intel (NASM) AT&T (gas) Name .w ax ax %ax register (16 bit) ax eax %eax register (32 bit) 3 # offset 3 $3 immediate 1000 #) byte ptr 1000 1000 displacement bx ) [ebx] (%ebx) base 100 di d) 100[edi] 100(%edi) base+displacement 20 ax *4 i#) 20[eax*4] 20(,%eax,4) (index*scale)+displacement di ax *4 i) [edi][eax*4] (%edi,%eax,4) base+(index*scale) 4 bx cx di) 4[ebx][ecx] 4(%ebx,%ecx) base+index+displacement 12 sp ax *2 di) 12[esp][eax*2] 12(%esp,%eax,2) base+(index*scale)+displacement
You can use
LI) instead of
DI) to enforce 32-bit displacement fields (useful for
Some example of instructions are:
ax bx mov \ move ebx,eax 3 # ax mov \ mov eax,3 100 di d) ax mov \ mov eax,100[edi] 4 bx cx di) ax mov \ mov eax,4[ebx][ecx] .w ax bx mov \ mov bx,ax
The following forms are supported for binary instructions:
<reg> <reg> <inst> <n> # <reg> <inst> <mem> <reg> <inst> <reg> <mem> <inst> <n> # <mem> <inst>
The shift/rotate syntax is:
<reg/mem> 1 # shl \ shortens to shift without immediate <reg/mem> 4 # shl <reg/mem> cl shl
Precede string instructions (
movs etc.) with
.b to get
the byte version.
The control structure words
UNTIL etc. must be preceded
by one of these conditions:
vs vc u< u>= 0= 0<> u<= u> 0< 0>= ps
pc < >= <= >. (Note that most of these words shadow some Forth words
assembler is in front of
forth in the search path,
code words). Currently the control structure words use
one stack item, so you have to use
roll instead of
to shuffle them (you can also use
Based on the Intel ABI (used in Linux),
abi-code words can find
the data stack pointer at
4 sp d), and the address of the FP
stack pointer at
8 sp d); the data stack pointer is returned in
dx are caller-saved, so
you do not need to preserve their values inside the word. You can
return from the word with
ret, the parameters are cleaned up by
For examples of 386
abi-code words, see Assembler Definitions.