このアセンブラコードを見てください。 32ビットx86用に設計されており、nasmによってコンパイルされます。
...
my_function:
pop %eax
...
ret
main:
Push 0x08
call my_function
私はずっと前に、メインプログラムと関数の間でパラメータを渡すためにスタックを使用できることを学びました。 eaxには0x08が含まれていると思いますが、これは偽であり、理由を説明できません。関数パラメーターを取得するにはどうすればよいですか?
まず、プラットフォーム上の他の言語またはライブラリとのインターフェイスを探している場合は、そのプラットフォーム用に定義されたインターフェイスを必ず読んでください。使用される可能性のあるさまざまな呼び出しメカニズムがあります。
あなたの場合、call
命令は戻りアドレスをスタックにプッシュしています。算術演算とesp
を使用して、パラメーターにアクセスできます。 eax
を使用しているため、32ビットコード(および32ビットスタック幅)を想定します。私は何も調べずにそれを書くことができるので、インテルの構文を使用しています:
my_function:
mov eax, [esp+4] ; Move the contents of ESP+4 into EAX
; ESP should be pointing at the 32 bit RIP.
; ESP+4 should be the pushed parameter.
...
ret
main:
Push 0x08
call my_function
この回答に関して、これがメモリリークを表しているかどうかをコメントでお尋ねください。答えはいいえだ。"理由は、callerがスタックに追加するものをすべてクリーンアップする責任があるためです。作成された他のコメントに基づくより完全な例は、次のようになります。
my_function:
Push ebp ; Store the current stack frame
mov ebp, esp ; Preserve ESP into EBP for argument references
and esp, 0xfffffff0; Align the stack to allow library calls
mov eax, [ebp+8] ; Move the contents of EBP+4 into EAX
; EBP should be pointing at the 32 bit RIP.
; EBP+4 should be the pushed parameter.
... ; Do lots of cool stuff
mov esp, ebp ; Restore the stack and ebp
pop ebp
ret
main:
Push 0x08
call my_function
pop ebx ; Clean up the stack
スタックを16バイト境界に揃える場合(これがなぜ発生するのかわからない場合、プラットフォームの呼び出し標準を調べるとすぐに見つかります)、どのように理解することも試みないことに注意してください多くのesp
が変更されました。 ebp
は「しおり」として機能するため、esp
を移動させて、他のことを考慮せずにアライメントやローカル変数の割り当てを行うことができます。
関数のエピローグでは、ebp
をesp
に戻し、関数が呼び出されたときにesp
を元の値に復元します。これにより、起こりました。最後に、pop ebp
スタックから離れ、関数内のスタックの最終値として戻りポインターを残します。戻りました。
戻った後、ポップでクリーンアップします。
または、スタックで解放するバイト数を指定する戻り値でスタックをクリーンアップすることもできます。それはすべて、呼び出し元の標準が呼び出し元のクリーンアップまたは呼び出し先のクリーンアップを指定しているかどうかに依存します。