28

The Art of Assembly Language (Randall Hyde、Amazon へのリンク) を読んでいて、その本のコンソール アプリケーションを試してみました。それは、Win32 API 関数を使用して、自分自身の新しいコンソールを作成するプログラムでした。LENSTRこのプログラムには、文字列の長さをEBPレジスタに格納するというプロシージャが含まれています。この関数のコードは次のとおりです。

LENSTR PROC
ENTER 0, 0
PUSH  EAX
;----------------------
CLD
MOV   EDI, DWORD PTR [EBP+08H]
MOV   EBX, EDI
MOV   ECX, 100 ; Limit the string length
XOR   AL, AL
REPNE SCASB ; Find the 0 character
SUB   EDI, EBX ; String length including 0
MOV   EBX, EDI

DEC   EBX
;----------------------
POP   EAX
LEAVE
RET   4
LENSTR ENDP

enterここでおよびleaveコマンドの使用法を説明していただけますか?

4

3 に答える 3

51

Enterスタック フレームを作成し、スタック フレームをleave破棄します。の0,0パラメータを使用するとenter、基本的に次のようになります。

; enter
push ebp
mov ebp, esp

; leave
mov esp, ebp
pop ebp

投稿したコードでは使用されていませんが、enter上記の単純なプッシュ/移動の組み合わせよりも少し多くのことをサポートしています。の最初のパラメーターはenter、ローカル変数に割り当てるスペースの量を指定します。たとえば、enter 5, 0次とほぼ同等です。

push ebp
mov ebp, esp
sub esp, 5

Enterネストされた関数/プロシージャを使用できる Pascal などの言語もサポートしています。

procedure X;
    procedure Y;
    begin
        { ... }
    end
begin
   { ... }
end

このような場合、Yは自身のローカル変数だけでなく、 にローカルなすべての変数にもアクセスできますX。これらは任意の深さまでネストできるため、独自のローカル変数、および の変数と の変数にアクセスできるのZ内部を持つことができます。入れ子の深さを指定する 2 番目のパラメーターは、 を使用し、を使用し、を使用します(ここで、およびはそれぞれおよびにローカルな変数のサイズを示します)。YYXenterXenter Sx, 0Yenter Sy, 1Zenter Sz, 2SxSySzXYZ

これにより、スタック フレームのチェーンが作成され、およびなどZのローカル変数にアクセスできるようになります。関数が再帰的である場合、これはかなり重要です。そのため、 の呼び出しは、スタックを最新の 2 つのスタック フレームまでたどることができません。以前の呼び出しからスタック フレームをスキップして、直接戻る必要があります。レキシカル親関数/プロシージャのフレームをスタックします。これは、再帰の場合は呼び出し元とは異なります。YXZ

この複雑さは、C および C++ がネストされた関数を禁止する理由でもあります。エンター/リーブの存在を考えると、Intel プロセッサでサポートするのはかなり簡単ですが、そのような直接的なサポートがない他の多くのプロセッサではかなり難しい場合があります。

これはまた、少なくとも他の 1 つの機能を説明するのにも役立ちます...enterここで使用されている単純なケース (つまり、 ) の -- の機能は、 /enter 0, 0を使用した同等のものよりもかなり遅いです。pushmov

于 2011-05-02T15:30:10.700 に答える
16

これは、関数のスタック フレーム (アクティベーション レコード) のセットアップです。内部的には、通常、次のようになります。

    push( ebp );         // Save a copy of the old EBP value
     
    mov( esp, ebp );     // Get ptr to base of activation record into EBP
     
    sub( NumVars, esp ); // Allocate storage for local variables.

// ENTER with a non-zero immediate does all 3 of the above things, slowly.

次に、スタック フレームが再び破棄されるときは、次の行に沿って何かを行う必要があります。

   mov( ebp, esp );    // Deallocate locals and clean up stack.
 
   pop( ebp );         // Restore pointer to caller's activation record.
// LEAVE does the above steps; a RET instruction is separate

   ret();              // Return to the caller.

これは、 HLAを使用したより良い説明です。私もその本を持っているので、あなたが読んでいる本でよく説明されていますが、それを説明するセクションを読みました.

于 2011-05-02T15:34:50.907 に答える
1

スタックフレームをセットアップするだけで出入りできます。通常、コンパイラはスタック フレーム ポインタを直接操作するコードを生成します。これは、入力と出力が mov/sub に比べて正確に高速ではないためです (ただし、286 日前まではそうでした :-) )。

于 2011-05-02T15:29:11.220 に答える