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


6.29.1 Definitions in assembly language

Gforth は、 アセンブリ言語でワードを実装する方法(abi-codeend-code を使用)と、 任意の実行時の振る舞いを持つ定義ワードを定義する方法(does> のようなの)を提供し、 ここで、 この実行時の振る舞いを(does> とは異なり、) Forth ではなくアセンブリ言語で定義します。

ただし、 Gforth のマシン非依存の性質により、 いくつかの問題が生じます。 まず、 Gforth は複数のアーキテクチャ上で実行されるため、 標準のアセンブラを提供できません。 ただし、 実行されるいくつかのアーキテクチャ用のアセンブラは提供されています。 さらに言えば、 Gforth ではシステムに依存しないアセンブラを使用したり、 ,c, を使用してマシン・コードを直接コンパイルしたりできます。

もう 1 つの問題は、Gforth の仮想マシンのレジスタ(スタック・ポインタと仮想マシン命令ポインタ)がインストールとエンジンに依存することです。 また、 どのレジスタを自由に使用できるかは、 インストールとエンジンによって異なります。 したがって、 Gforth 仮想マシンのコンテキストで実行するように記述されたコードは、 基本的に、 そのコードが開発されたインストールとエンジンに限定されます(たまたま、 他の場所でも動く可能性はありますが、 それに頼ることはできません)。

幸いなことに、 同じ呼び出し規約(ABI)を持つプラットフォーム上で実行されている Gforth に移植可能(portable)な abi-code ワードを Gforth で定義できます。 通常、 これは同じアーキテクチャと OS の組み合わせへの移植性を意味し、 しばしば OS の境を越えることができます。

assembler ( ) tools-ext “assembler”

ボキャブラリ: 検索順序スタック(the search order)のTOSのワードリストを assembler ワードリストに置き換えます。

init-asm ( ) gforth-0.2 “init-asm”

assembler ワードリストを検索順序スタック(the search order)にプッシュします(訳注:つまり assembler ワードリストが検索順序スタックのTOSになる)。

abi-code ( "name" – colon-sys  ) gforth-1.0 “abi-code”

C言語プロトタイプ(C-prototype)に対応するプラットフォームの ABI 規則を使用して呼び出されるネイティブ・コード定義を開始します:

Cell *function(Cell *sp, Float **fpp);

ここで、 FP スタック・ポインタは、 FP スタック・ポインタを含むメモリ位置への参照を提供することによって渡され、 (必要な場合)変更された FP スタック・ポインタをそこに格納することによって渡されます。

;abi-code ( ) gforth-1.0 “semicolon-abi-code”

コロン定義を終了しますが、 実行時に最後に定義されたワード X (create で作られたワードである必要があります)の変更もして、 C言語プロトタイプに対応するプラットフォームの ABI 規約を使用してネイティブ・コードを呼び出します:

Cell *function(Cell *sp, Float **fpp, Address body);

FP スタック・ポインタは、 FP スタック・ポインタを含むメモリ位置への参照を提供することによって渡され、 変更された FP スタック・ポインタをそこに格納することによって渡されます(必要な場合)。 パラメータ bodyX の本体です。

end-code ( colon-sys –  ) gforth-0.2 “end-code”

コード定義を終了します。 ABI 呼び出しからの戻り(abi-code の場合)、 または次の VM 命令へのディスパッチ(code および ;code の場合)を自分でアセンブルする必要があることに注意してください。

code ( "name" – colon-sys  ) tools-ext “code”

Gforth 仮想マシン(エンジン)のコンテキストで実行されるネイティブ・ード定義を開始します。 このような定義は Gforth インストール間で移植できないため、 code の代わりに abi-code を使用することをお勧めします。 code 定義は、 次の仮想マシン命令へのディスパッチで終了する必要があります。

;code ( compilation. colon-sys1 – colon-sys2  ) tools-ext “semicolon-code”

;code の後のコードが、 最後に定義されたワード(create されたワードである必要があります) の振る舞いになります。 code の場合と同じ注意事項が適用されるため、 代わりに ;abi-code を使用することをお勧めします。

flush-icache ( c-addr u – ) gforth-0.2 “flush-icache”

プロセッサの命令キャッシュ(存在する場合)の c-addru バイト以降に古いデータが含まれていないことを確認してください。 END-CODEflush-icache を自動的に実行します。 注意(Caveat): flush-icache はあなたのインストール環境では機能しない可能性があります。 これは通常、 マシンでダイレクト・スレッドがサポートされておらず(machine.h を確認してください)、 マシンに別個の命令キャッシュがある場合に当てはまります。 このような場合、 flush-icache は命令キャッシュをフラッシュする代わりに何も行いません。

flush-icache が正しく動作しない場合、 abi-code ワードなども(まず確実に)動作しません。

これらのワードの一般的な使用法は、 同等の高レベルの定義ワードから類推することで最も簡単に示すことができます:

: foo                              abi-code foo
   <high-level Forth words>              <assembler>
;                                  end-code
                                
: bar                              : bar
   <high-level Forth words>           <high-level Forth words>
   CREATE                             CREATE
      <high-level Forth words>           <high-level Forth words>
   DOES>                              ;code
      <high-level Forth words>           <assembler>
;                                  end-code

abi-code を使用する場合は、 あなたのプラットフォームの ABI ドキュメントを参照して、 パラメーターがどのように渡されるか(スタック・ポインターをどこで取得するかがわかります)、 戻り値がどのように渡されるか(データ・スタック・ポインタがどこに返されるかがわかります)を確認してください。 ABI のドキュメントでは、 どのレジスタが呼び出し元によって保存されるか(caller-saved)や、 コード内で自由に破棄できるかや、 どのレジスタが呼び出されたワードによって保存される必要があるか(callee-saved)についても説明されています。 あなたはそれらを使用する前に保存し、 後で復元します。 一部のアーキテクチャと OS については、適切なセクションで呼び出し規約の各部分の短い概要を示します。 リバース・エンジニアリング志向の人々は、 see abi-call を通じてスタック・ポインタの受け渡しと戻りについて知ることもできます。

ほとんどの ABI はレジスタを介してパラメータを渡しますが、 一部の ABI(特に最も一般的な 386 (別名 IA-32) 呼び出し規約) はアーキテクチャ・スタック上でパラメータを渡します。 共通の ABI はすべてレジスタで戻り値を渡します。

abi-code を使用する際に知っておく必要があるその他のことは、 Gforth ではデータと FP スタックの両方が下方向(下位アドレスに向かって)に成長し、 セルあたりのサイズは 1 cells になり、 FP 値ごとのサイズは 1 floats になるということです。

386 アーキテクチャで abi-code を使用する例を以下に示します:

abi-code my+ ( n1 n2 -- n )
4 sp d) ax mov \ sp into return reg
ax )    cx mov \ tos
4 #     ax add \ update sp (pop)
cx    ax ) add \ sec = sec+tos
ret            \ return from my+
end-code

この例の AMD64 バリエーションは AMD64 (x86_64) Assembler にあります。

386 で FP 値を扱う例を以下に示します:

abi-code my-f+ ( r1 r2 -- r )
8 sp d) cx mov  \ load address of fp
cx )    dx mov  \ load fp
.fl dx )   fld  \ r2
8 #     dx add  \ update fp
.fl dx )   fadd \ r1+r2
.fl dx )   fstp \ store r
dx    cx ) mov  \ store new fp
4 sp d) ax mov  \ sp into return reg
ret             \ return from my-f+
end-code

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