4

x86 命令を考えてみましょうENTER。Intelの命令セットリファレンスから。

プロシージャのスタック フレームを作成します。最初のオペランド (サイズ オペランド) は、スタック フレームのサイズ (つまり、プロシージャのスタックに割り当てられた動的ストレージのバイト数) を指定します。第 2 オペランド (ネスト レベル オペランド) は、プロシージャのレキシカル ネスト レベル (0 から 31) を指定します。ネスティング レベルは、前のフレームから新しいスタック フレームの「表示領域」にコピーされるスタック フレーム ポインタの数を決定します。これらのオペランドはどちらも即値です。

ENTERゼロ以外のネスティング レベルが 2 番目のオペランドとして渡されると、命令がどのように機能するのか疑問に思っていました。この場合、Intel のマニュアルによると、プロセッサは追加のフレーム ポインタをスタックにプッシュする必要があります。簡単に聞こえますが、サンプル プログラムで期待どおりに動作しない理由がわかりません。

次の例を FASM でコンパイルし、OllyDbg でデバッグしました。

format PE

section '.text' code readable executable
entry start
start:
    enter 16, 8
    push 0
    call ExitProcess
...

ENTER命令によって発行されるスタック フレームを以下に示します。

000CFF58   00000000 ; new esp
000CFF5C   00000000
000CFF60   00000000
000CFF64   00000000
000CFF68   000CFF88 ; value of new ebp
000CFF6C   7EFDE000 ; ?
000CFF70   000CFF94 ; value of old ebp
000CFF74   76AD338A ; ?
000CFF78   7EFDE000 ; ?
000CFF7C   000CFF94 ; value of old ebp
000CFF80   76AD338A ; ?
000CFF84   7EFDE000 ; ?
000CFF88   000CFF94 ; value of old ebp
000CFF8C   76AD338A ; old esp

結果は奇妙です。gccでも同じことをしましょう。

> cat enter.s
.globl  _start

.text
_start:
    enter $16, $8
    movl $1, %eax
    movl $0, %ebx
    int $0x80

> gcc -m32 -g -c enter.s && ld -melf_i386 enter.o
> gdb a.out
...
(gdb) r
...  
Program received signal SIGSEGV, Segmentation fault.
_start () at enter.s:5
5           enter $16, $8

エラー、わかりました...

私はおそらくそれがどのように機能するかを誤解しています。ここでの私の唯一の推測は、ENTER命令が何らかの方法で OS によって処理されるということですが、これはほぼ間違いなく間違っています。

4

1 に答える 1