Next: , Previous: , Up: Assembler and Code Words   [Contents][Index]


6.29.5 AMD64 (x86_64) Assembler

AMD64 アセンブラは、 386 アセンブラをわずかに変更したバージョンであり、 構文の大部分を共有しています。 2 つの新しい接頭辞 .q.qa が、 それぞれ 64 ビット・サイズのオペランドやアドレスを選択するために提供されています。 64 ビット・サイズがデフォルトであるため、 通常は他のプレフィックスを使用するだけで済みます。 また、 追加のレジスタ・オペランド R8R15 もあります。

レジスタには「e」または「r」プレフィックスがありません。 64 ビット・モードでも、 raxax と呼ばれます。 すべてのレジスタで最下位バイトを参照するために追加のレジスタ・オペランドを使用できます: 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

Next: Alpha Assembler, Previous: 386 Assembler, Up: Assembler and Code Words   [Contents][Index]