AMD64 アセンブラーは、 386 アセンブラーをわずかに変更したバージョンであり、 構文の大部分を共有しています。 2 つの新しい接頭辞
.q と .qa が、 それぞれ 64 ビット・サイズのオペランドやアドレスを選択するために提供されています。 64
ビット・サイズがデフォルトであるため、 通常は他のプレフィックスを使用するだけで済みます。 また、 追加のレジスター・オペランド R8
~ R15 もあります。
レジスターには「e」または「r」プレフィックスがありません。 64 ビット・モードでも、 rax は ax と呼ばれます。
すべてのレジスターで最下位バイトを参照するために追加のレジスター・オペランドを使用できます: R8L 〜 -R15L,
SPL, BPL, SIL, DIL
Linux-AMD64 の呼び出し規則では、 最初の 6 つの整数パラメーターを rdi, rsi, rdx, rcx, r8, r9 で渡し、 結果を
rax , rdx で返します。 最初の 8 つの FP パラメータを xmm0 ~ xmm7 に渡し、 FP 結果を xmm0 ~ xmm1
に返します。 したがって、abi-code ワードは、 di でデータ・スタック・ポインターを取得し、 si
で FP スタック・ポインターのアドレスを取得し、 リターン時は ax にデータ・スタック ポインターをセットします。
呼び出し元が保存する他のレジスターは、 r10, r11 xmm8 ~ xmm15 です。 この呼び出し規約は、 Microsoft 以外の他の OS
でも使用されていると報告されています。
Windows x64 は、 最初の 4 つの整数パラメーターを rcx, rdx, r8, r9 に渡し、 整数の結果を rax に返します。 他の、呼び出し元保存レジスターは r10 と r11 です。
https://uclibc.org/docs/psABI-x86_64.pdf の 21ページによると、 Linux プラットフォームでは、 レジスター AX CX DX SI DI R8 R9 R10 R11 が自由(scratch)に使えます。
AMD64 のアドレッシング・モードは以下のとおりです:
\ ご注意: ワード A を実行すると、レジスターが初期化されていないため、 メモリー・エラーが発生します ;-)
ABI-CODE A ( -- )
500 # AX MOV \ immediate
DX AX MOV \ register
200 AX MOV \ direct addressing
DX ) AX MOV \ indirect addressing
40 DX D) AX MOV \ base with displacement
DX CX I) AX MOV \ scaled index
DX CX *4 I) AX MOV \ scaled index
40 DX CX *4 DI) AX MOV \ scaled index with displacement
DI AX MOV \ SP Out := SP in
RET
END-CODE
AMD64 abi-code ワードの例をいくつか示します:
abi-code my+ ( n1 n2 -- n3 ) \ SP passed in di, returned in ax, address of FP passed in si 8 di d) ax lea \ compute new sp in result reg ( 結果として di+8 → ax つまり drop と同じ) di ) dx mov \ get old tos ( [di] つまり n2 → dx ) dx ax ) add \ add to new tos ( dx + [ax] → [ax] ret end-code
\ Do nothing
ABI-CODE aNOP ( -- )
DI ) AX LEA \ SP out := SP in
RET
END-CODE
\ Drop TOS
ABI-CODE aDROP ( n -- )
8 DI D) AX LEA \ SPout := SPin - 1
RET
END-CODE
\ Push 5 on the data stack
ABI-CODE aFIVE ( -- 5 )
-8 DI D) AX LEA \ SPout := SPin + 1
5 # AX ) MOV \ TOS := 5
RET
END-CODE
\ Push 10 and 20 into data stack
ABI-CODE aTOS2 ( -- n n )
-16 DI D) AX LEA \ SPout := SPin + 2
10 # 8 AX D) MOV \ TOS - 1 := 10
20 # AX ) MOV \ TOS := 20
RET
END-CODE
\ Get Time Stamp Counter as two 32 bit integers
\ The TSC is incremented every CPU clock pulse
ABI-CODE aRDTSC ( -- TSCl TSCh )
RDTSC \ DX:AX := TSC
$FFFFFFFF # AX AND \ Clear upper 32 bit AX
0xFFFFFFFF # DX AND \ Clear upper 32 bit DX
AX R8 MOV \ Tempory save AX
-16 DI D) AX LEA \ SPout := SPin + 2
R8 8 AX D) MOV \ TOS-1 := saved AX = TSC low
DX AX ) MOV \ TOS := Dx = TSC high
RET
END-CODE
\ Get Time Stamp Counter as 64 bit integer
ABI-CODE RDTSC ( -- TSC )
RDTSC \ DX:AX := TSC
$FFFFFFFF # AX AND \ Clear upper 32 bit AX
32 # DX SHL \ Move lower 32 bit DX to upper 32 bit
AX DX OR \ Combine AX wit DX in DX
-8 DI D) AX LEA \ SPout := SPin + 1
DX AX ) MOV \ TOS := DX
RET
END-CODE
VARIABLE V
\ Assign 4 to variable V
ABI-CODE V=4 ( -- )
BX PUSH \ Save BX, used by gforth
V # BX MOV \ BX := address of V
4 # BX ) MOV \ Write 4 to V
BX POP \ Restore BX
DI ) AX LEA \ SPout := SPin
RET
END-CODE
VARIABLE V
\ Assign 5 to variable V
ABI-CODE V=5 ( -- )
V # CX MOV \ CX := address of V
5 # CX ) MOV \ Write 5 to V
DI ) AX LEA \ SPout := SPin
RET
END-CODE
ABI-CODE TEST2 ( -- n n )
-16 DI D) AX LEA \ SPout := SPin + 2
5 # CX MOV \ CX := 5
5 # CX CMP
0= IF
1 # 8 AX D) MOV \ If CX = 5 then TOS - 1 := 1 <--
ELSE
2 # 8 AX D) MOV \ else TOS - 1 := 2
THEN
6 # CX CMP
0= IF
3 # AX ) MOV \ If CX = 6 then TOS := 3
ELSE
4 # AX ) MOV \ else TOS := 4 <--
THEN
RET
END-CODE
\ Do four loops. Expect : ( 4 3 2 1 -- )
ABI-CODE LOOP4 ( -- n n n n )
DI AX MOV \ SPout := SPin
4 # DX MOV \ DX := 4 loop counter
BEGIN
8 # AX SUB \ SP := SP + 1
DX AX ) MOV \ TOS := DX
1 # DX SUB \ DX := DX - 1
0= UNTIL
RET
END-CODE
以下は、FP 値を扱う AMD64 用の例です:
abi-code my-f+ ( r1 r2 -- r ) \ SP passed in di, returned in ax, address of FP passed in si si ) dx mov \ load fp 8 dx d) xmm0 movsd \ r2 dx ) xmm0 addsd \ r1+r2 xmm0 8 dx d) movsd \ store r 8 # si ) add \ update fp di ax mov \ sp into return reg ret end-code