スタックと割り込み ―― プログラムが動く仕組みを知ろう

大山将城

tag: 組み込み

技術解説 2008年7月23日

● 関数呼び出し

 リスト1中の処理AをFuncA()として関数化してみましょう(図3).main関数を実行すると,(1)の破線で関数FuncAを呼び出し,(2)の破線で関数から戻ってくることになります.関数FuncAの呼び出しを実行すると,関数FuncAに実行が移ります.そして関数FuncA内で処理Aを実行し,return文で再びmain関数に戻ります.

zu03_01.gif
図3 処理Aを関数化したプログラム
main関数中で行っていた処理AをFuncAという関数に記述して,main関数からFuncAを呼び出す形に変更した.

 プログラム・カウンタの値でいうと,関数FuncA呼び出しでプログラム・カウンタの値は処理A(正確には,関数FuncAの先頭の命令)を指すように更新されます.また,return文の実行で,プログラム・カウンタの値はmain関数の処理B(正確には,FuncA();の直後の命令)を指すように更新されます.

● 関数呼び出しと順次実行・分岐の違い

 関数呼び出しにおいても,プログラム・カウンタの値を制御することでプログラムの実行の流れが進んでいくという点は同じです.一方で,関数呼び出しの動作には,順次実行や分岐とは根本的に違うところがあります.それは,図3の(2)の「関数FuncA()が終わったら,どうやって呼び出し元であるmain関数に戻るのか」という点です.

 呼び出し元に戻ってくるためには,関数を呼び出したときに戻り先のアドレスをあらかじめどこかに記録しておく必要があります.関数から戻るときはその記録を参照して,プログラム・カウンタの値をその値に戻すことで「呼び出し元に戻る」動作を実現しています.その記録する場所が,「スタック」というメモリ領域なのです.

2.スタックとは何か

 スタック領域は,メモリ上の領域の一つであり注3,プログラム実行時の作業領域として使用します.スタック領域は,コード領域やデータ領域,ヒープ領域と同じように,メモリ上に領域を排他的に(ほかの領域とは重なり合わないように)確保しています.そして,コード領域ではプログラム・カウンタで位置を特定してアクセスするように,スタック領域はスタック・ポインタというCPU内の特別なレジスタでアクセスします.

注3;メモリ上の領域については,第2章の表2を参照.

 図4にスタック・ポインタとメモリの関係の例を示します.スタック・ポインタの値が0xff10だったとします.この場合,0xff10がスタックの先頭です.CPUはプログラム実行時にデータの一時的な退避が必要になると,0xff10にデータを書き込み,スタック・ポインタの値を減らします.

zu04_01.gif
図4 スタック・ポインタとメモリの関係
スタック・ポインタは,スタックの先頭を指している.スタックにデータを退避するときは,スタック・ポインタに基づいてデータを書き込み(プッシュ),スタック・ポインタの値を減らす.

● プッシュ&ポップのデータ構造

 スタックは,データ構造に特徴があります.もともとスタックという名前は,干し草の山を意味する英語stackに由来します.スタック上にデータを書き込むことをプッシュ(英語のpush.山の一番上に置く),読み出すことをポップ(英語のpop.山の一番上からひょいと取り出す)と言います.スタックにデータをプッシュするとスタック・ポインタの値は減少し,スタックからデータをポップするとスタック・ポインタの値は増加します.スタック・ポインタは常に山の一番上を指します.

 データの出し入れの順番で考えると,最後にプッシュしたデータが最初にポップされます.この性質をLIFO(Last- in First-out)と言います(図5).このLIFOをうまく使うことで,CPUは関数呼び出しと関数リターンを実現しています.

zu05_01.gif
図5 LIFOのデータ構造
干し草の山にひょいひょいとデータを積んでいくイメージ.後から積んだものを,先に取り出す仕組みになっている.

 関数呼び出しと関数リターンの時の,戻り先アドレスのプッシュとポップの例を図6に示します.関数FuncAの実行開始時,スタック・ポインタの値は0xff10とします(1).この状態で関数FuncB呼び出しを実行すると,戻り先アドレスをスタックの先頭にプッシュし,スタック・ポインタの値を0xff0eに減らします(2).さらに,プログラム・カウンタの値を更新して関数FuncBの実行に移ります.

zu06_01.gif
図6 戻り先アドレスのプッシュとポップ
関数FuncBを呼び出すとき,戻り先アドレスをスタックにプッシュしてスタックの先頭位置(スタック・ポインタ)を変更する.関数リターン時にはスタックの先頭位置を元に戻し,戻り先アドレスをスタックから取り出して呼び出し元に戻る.

 関数FuncBの関数リターンを実行すると,スタック・ポインタの値を0xff10に増やし,アドレス0xff10から戻り先アドレスをポップします(3).さらに,プログラム・カウンタの値を戻り先アドレスに更新して,呼び出し元に戻ります.

 このように,戻り先アドレスの読み書きが,LIFOの性質によってプッシュとポップだけで実現できます.

組み込みキャッチアップ

お知らせ 一覧を見る

電子書籍の最新刊! FPGAマガジン No.12『ARMコアFPGA×Linux初体験』好評発売中

FPGAマガジン No.11『性能UP! アルゴリズム×手仕上げHDL』好評発売中! PDF版もあります

PICK UP用語

EV(電気自動車)

関連記事

EnOcean

関連記事

Android

関連記事

ニュース 一覧を見る
Tech Villageブログ

渡辺のぼるのロボコン・プロモータ日記

2年ぶりのブログ更新w

2016年10月 9日

Hamana Project

Hamana-8最終打ち上げ報告(その2)

2012年6月26日