2010-11-24 13 views
1

どのようにして、アセンブリ内で関数の引数を別の関数に転送するだけで、余分な数を追加することができますか?完璧な転送 - 組み立て

これまでのところ、私は2つの余分な引数を押して、もう1つの関数にjmpしました。それは有効ですか?私はそれを裸の関数にすると仮定すると、プロローグ/エピローグはありません。私はx86です。

+0

他の機能のリターンアドレスはどうですか? –

答えて

4

これを行うには、リターンアドレスをポップし、2つの引数を押して、スタックにリターンアドレスを戻してからジャンプさせる必要があります。

以下の説明では、私がティンカーのレジスタを予約していない環境で、純粋なスタックベースの呼び出し規約を使用していることを前提としています。予約されたレジスタがある場合(たとえば、Cプログラムによって呼び出されるASM関数を記述している場合など)、または呼び出し規約がレジスタベースである場合、状況は多少異なるはずです。

また、最後に必ず免責事項をお読みください。

方法のうちそれと

...

あなたは、スタック上の2つのパラメータで呼ばれています機能を持っている想像してみてください。スタックフレームは、あなたの関数へのエントリで、次のようになります。

arg1 
arg2 
return addr 

はの引数の順序(stdcall対すなわちcdecl)について屁理屈ないようにしましょう。

ここで、2つの引数と2つの引数を必要とする別の関数にコントロールを渡したいとします。

arg1 
arg2 
arg3 
arg4 
return addr 

だからあなたの最初の関数は、戻りアドレスをポップ二つの新しいパラメータを追加し、リターンアドレスをプッシュして、ジャンプを行う必要があります:

その関数へのエントリでは、スタックフレームは次のようになります。
passthrough: 
    ; save the return address 
    pop ax 
    ; Do stuff here to load values in BX and CX 
    ; now push BX and CX (other parameters) 
    push bx 
    push cx 
    ; restore the return address 
    push ax 
    ; Branch to the new function. 
    ; The new function's RETurn will return to the caller of this function 
    jmp new_function 

(はい、私は16ビット命令であることやっただけなど、eaxaxを変更します。)

また、これは非常に重要です:呼び出し先の場合のみ動作はスタックをクリーンアップする予定です。呼び出し側がスタックをクリーンアップすると予想される場合(通常はpopまたはスタックポインタを追加することによって)、呼び出し側は実際に4があるときに呼び出し元がスタックから2つのパラメータを削除することを期待しているため、この手法は失敗します。破損したスタックフレームになり、呼び出し元がret命令を実行しようとすると、それは雑草に迷い込んでしまいます。

+0

x86では、呼び出し元がクリーンアップする必要があります(呼び出し直後に 'add%esp'が表示されますが、巧妙なコンパイラではそれらをバッチすることもあります)。テールコールは、同じ数以下の引数でのみ行うことができます。 –

+3

@Ben:x86にはどちらも必要ありません。言語および/またはオペレーティングシステム関数によって指定された呼び出し規約によって、どのメソッドが使用されるかが決まります。たとえば、Windowsの 'stdcall'は、Delphiと同様に、呼び出し先のクリーンアップを指定します。 'cdecl'呼び出し規約は呼び出し元のクリーンアップを指定します。呼び出し先のクリーンアップでは、 'ret 8'のような指示が表示されます。つまり、戻りアドレスがポップされた後に' esp'が8だけインクリメントされます。 –

関連する問題