2019
08
06

関数呼び出し時のスタックの動きについて

関数呼び出し時のスタックの動きについて。
こちらの記事でも書いた内容を改めてまとめ直しました。
まずは関連用語の覚書

スタック
関数の引数、関数内部のローカル変数や戻りアドレスが格納される。LIFO (Last In, First Out 後入れ先出し)。
スタック領域はメモリの上位アドレスから下位アドレスに向かって確保されていく。

ヒープ
動的に確保されたメモリ領域。例えばmallocによって動的にメモリ領域を確保する場合は、ヒープ領域上に確保される。ヒープ領域はメモリの下位アドレスから上位アドレスに向かって確保されていく。

EIP
次に実行する命令文のアドレスを格納している。命令文が実行されるたび、EIPの値は加算される (どのくらい加算されるかは実行された命令文のサイズによる)

ESP
スタック・ポインタ。スタック領域のトップに積まれたデータのメモリー・アドレスを格納する。スタックはメモリの上位アドレスから下位アドレスに向かって積み上がっていくので、ESPは最下位のアドレスに格納されたデータを指す。

EBP
ベース・ポインタ。データの格納領域の基点のメモリー・アドレスを格納する。通常、関数の最初において、EBPにはESPの値が設定される。これは関数の引数とローカル変数を追跡するためである。ローカル変数へのアクセスはEBPからオフセットを引くことによって行われる。関数の引数へのアクセスはEBPにオフセットを加算することによって行われる。



main関数: sum関数を引数付きで呼び出す。(引数は5と10)

.text:08048433 55 push ebp
.text:08048434 89 E5 mov ebp, esp
.text:08048436 83 E4 F0 and esp, 0FFFFFFF0h
.text:08048439 83 EC 20 sub esp, 20h
.text:0804843C C7 44 24 04 0A 00 00 00 mov dword ptr [esp+4], 0Ah
.text:08048444 C7 04 24 05 00 00 00 mov dword ptr [esp], 5
.text:0804844B E8 CD FF FF FF call sum
.text:08048450 89 44 24 1C mov [esp+1Ch], eax
.text:08048454 8B 44 24 1C mov eax, [esp+1Ch]
.text:08048458 89 44 24 04 mov [esp+4], eax
.text:0804845C C7 04 24 00 85 04 08 mov dword ptr [esp], offset unk_8048500
.text:08048463 E8 88 FE FF FF call _printf
.text:08048468 B8 00 00 00 00 mov eax, 0
.text:0804846D C9 leave
.text:0804846E C3 retn
.text:0804846E main endp


sum関数: 2つの整数の合計を求める関数

.text:0804841D 55 push ebp
.text:0804841E 89 E5 mov ebp, esp
.text:08048420 83 EC 10 sub esp, 10h
.text:08048423 8B 45 0C mov eax, [ebp+arg_4]
.text:08048426 8B 55 08 mov edx, [ebp+arg_0]
.text:08048429 01 D0 add eax, edx
.text:0804842B 89 45 FC mov [ebp+var_4], eax
.text:0804842E 8B 45 FC mov eax, [ebp+var_4]
.text:08048431 C9 leave
.text:08048432 C3 retn
.text:08048432 sum endp


上記のsum関数を例にスタックの動きを追います。


sum関数のcall直後
stack1.png
引数が2つスタックに積まれ、さらにsum関数が実行されたあとの次の命令のアドレスがリターンアドレスとしてスタックに積まれます。(この操作はcallが実行されると自動的に行われます)。

EBPレジスタの保存
stack2.png
push ebp命令によってmain関数のEBPレジスタの値(0x111)がスタックに積まれます。これにより、sum関数の実行が完了したあとにmain関数に戻れるようになります。
そして、mov ebp, esp命令によりespの値がebpにコピーされます。

ローカル変数の領域の確保
stack3.png
sub esp, 10h命令によってESPレジスタの指す位置を下位のアドレスに移動させます。EBPレジスタの指す位置とESPレジスタの指す位置の間にできた領域はローカル変数の格納に利用されます。この場合は0x10、つまり10進数で16バイトの領域がローカル変数の領域として割り当てられます。

leave
stack4.png

stack5.png
leave命令によってESPがEBPと同じ位置に戻され、保存していたmain関数のEBPレジスタの値(0x111)が復元されます。leave命令は mov esp, ebp; pop ebpと等しい動作をします。leave命令完了後は、ESPはリターンアドレスを指しています。

retn
stack6.png
retn命令はスタックのトップから値をpopし、そこへjmpします。今回の場合スタック上位に積まれているのはsum関数実行後のリターンアドレスなので、retnによってリターンアドレスがpopされ、ジャンプします。
Comment



Only the blog author may view the comment.


Trackback
Trackback URL

«  | HOME |  »

奇妙な風景 Unique Scene
<< >>

プロフィール


最新記事


最新コメント


最新トラックバック


月別アーカイブ


カテゴリ


スポンサード リンク


FC2カウンター


検索フォーム


RSSリンクの表示


リンク


ブロとも申請フォーム


QRコード