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