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 によって処理されるということですが、これはほぼ間違いなく間違っています。