CALL
しかし、それでは、指示の理由もありません。結局のところ、次の方法で通話をシミュレートできます。
sub esp,4
mov [esp-4], offset return_address
jmp myproc
RET
また、次の方法でシミュレートできるため、命令も必要ありません。
mov eax,[esp]
add esp,4
jmp [eax]
よく見ると、他の命令を組み合わせてシミュレートできる命令がたくさんあります。ポイントは何ですか?
この種の質問に対する答えは、x86 プロセッサ ファミリの長い歴史と、それ以前のプロセッサに根ざしています。設計者は、プログラマがプロセッサをどのように使用するかを研究し、実行速度とメモリ使用の点で効率的な命令セットを作成しました。
70 年代後半には、64 キロバイトは大量の RAM であり、RAM ははるかに低速でした。すべての命令バイトは貴重であり、メモリから命令をフェッチするだけで膨大な量のオーバーヘッドがありました。命令フェッチが実行よりも長くかかることは珍しくありませんでした。そのため、可能な限り少ない命令バイトでエンコードすることで、パフォーマンスが大幅に向上しました。
RAM は、CPU のクロック速度と比較すると依然として信じられないほど遅いため、できるだけ少ない命令バイトでエンコードすることで得られる利点があります。分岐予測やプリフェッチ ロジックと同様に、大規模な CPU キャッシュが大いに役立つことは事実ですが、RAM から CPU キャッシュに転送されるすべてのバイトは依然として高価です。命令エンコーディングを倹約することは報われます。
呼び出し手順について:
アセンブリ言語でプロシージャを呼び出す標準的な方法は、パラメータをプッシュしてからプロシージャをプッシュするcall
ことです。たとえば、これは 2 つの dword 値を渡します。
push eax
push ebx
call proc ; pushes the return address and jumps to proc
...
proc:
; at this point, [esp] contains the return address
命令はret
戻りアドレスを命令ポインターにポップします。
もちろん、誰かがスタックをクリーンアップする必要があります。呼び出し元は、スタック ポインターをインクリメントすることで、スタックをクリーンアップできます。または、呼び出されたプロシージャは、を使用してスタックをクリーンアップできます。これによりret 8
、リターン アドレスがポップされ、スタック ポインタがインクリメントされます。
呼び出し規則の詳細については、 http://www.delorie.com/djgpp/doc/ug/asm/calling.htmlを参照してください。