2016-07-07 16 views
3
push EAX 
push 8 
call malloc 
pop EBX 
pop EBX 
mov [EAX], 0 
mov [EAX+4], EBX 

なぜポップEBXを2回行う必要がありますか?毎回EBXにはどのような価値がありますか?なぜこのコードは、関数を呼び出した後に同じレジスタに2回ポップしますか?

+1

プッシュされた2つのものを削除してスタックのバランスをとっています。それは 'ebx'である必要はなく、' pop 'である必要はありません。通常は 'add esp、8'と表示されますが、それは3バイトです。これはちょうど2なので、恐らくサイズを最適化します。 – Jester

答えて

4

枢機卿のルールは、あなたが押しても、をポップする必要があります。それ以外の場合は、スタックのバランスを崩し、コードがクラッシュまたは悪化します。そのルールが意味するのは、あなたがプッシュした値と同じサイズ(バイト単位)の値をポップする必要があるということです。それはcdecl呼び出し規約を使用しているためmallocで必要とされる関数呼び出し(、後にスタックをクリーンアップするには

push EAX ; push a DWORD-sized register (4 bytes) 
push 8  ; push a DWORD immediate  (4 bytes) 

、:

だからこのケースでは、あなたは、malloc関数を呼び出す前に、スタックの上の8つのバイトをプッシュこれはcaller-cleanupです)、8バイトをポップする必要があります。ちょうどので、それを行うための便利な方法は、二度レジスタサイズの値をポップすることであることを起こる:

pop EBX ; pop 4 bytes 
pop EBX ; pop 4 bytes 

スタックがLIFOです。 最初のポップは8EBXに入れます(これはあなたがプッシュした最後のものでした)。これは気にしません。次のポップはEAXの元の値をEBX(最初に押したもの)に戻し、後で使用するようにします。

あなたは単にスタックポインタに8バイトを追加し、ADD命令を使用することができ、スタックからポップされている値のいずれかを維持を気にしなかった場合:

add esp, 8 

これは少し、おそらくです2つのポップよりも速いですが、実際はわずかに大きくなります(2バイトの代わりに3バイト、as Jester points out)コードサイズを最適化することは、コードの速度を最適化する場合と同じくらい重要です。キャッシュ。しかし、このケースでは、押し付けられた最初の価値を得ることが、より重要な懸念事項であると考えられます。 mallocは1つのパラメータしか取らないので、最初のプッシュの唯一の理由は、関数呼び出しによって(関数がEAXで結果を返す)clobberedされているので、EAXの元の値を保持することでした。したがって、コードを書く別の方法は、次のようになります。

; Save EAX by moving it into a caller-save register 
; (that will not get clobbered by the malloc function). 
mov EBX, EAX 

; Call the malloc function by pushing a 4-byte parameter and then rebalancing the stack. 
push 8 
call malloc 
add esp, 4 

; EAX contains malloc's return value, and EBX contains the original value of EAX 
; that we saved before calling malloc. 
mov [EAX], 0 
mov [EAX+4], EBX 
+0

コードブロック内のコメントの中には、プッシュ/ポップごとに8バイトと書かれているものがあります。 –

+0

@peterああ、彼らは実際にすべてです。私はちょうど8を入力するのが好きだったと思う。 –

+1

余分なプッシュ/ポップは、スタックの配置を変更します。 ABIによっては、 'esp'は' call'(例えばi386 SysV)の前に16バイト整列する必要があります。スタックエンジン(Pentium M以降)を搭載したIntel CPUでは、espを直接使用するためには、余分なuopを挿入してアウトオブオーダーコアの値とそのオフセットを同期させる必要があります。したがって、ロード/ストアポートのスループットが問題にならない場合、プッシュ/ポップは実際にはスタックを整列させるための安価な方法になります。 clangは '-O3'だけでなく-O3でもこれを行いますが、ダミーレジスタにポップします。プッシュ/ポップで実際にセーブ/リストアするこのスタイルは、EBXにレイテンシを追加します。 –

関連する問題