「組み込み」ならではの基礎知識 ――スタートアップ・ルーチンからハードウェアまで
また,フレーム・ポインタの値をfact(1)のベース・アドレスからfact(2)のベース・アドレスに切り替えたとたんに,fact(1)のベース・アドレスの情報は存在しなくなります(図1-4).つまり,fact(1)の変数部はアクセス不能になり,実質的にそのメモリ領域は解放されたこと(再利用可能)になります.
ここでは,ランタイム構造の基本的なしくみだけを説明しましたが,実際にはローカル変数も変数部に入れます.また,fact(1)が完了した時点で,fact(2)の計算を引き続き実行するために,関数factのコードのどの部分に戻るかという情報を変数部に入れる場合もあります.具体的な実装はコンパイラに依存します.プログラムの開発に際してはこれらのことを確認したうえでコンパイラを使用することをお勧めします.
組み込み機器で使用する多くのマイコンでは,メモリ保護機能が十分ではありません.そのため,スタック上の変数部がどんどんふくらみ,スタックと指定した領域を超えても,見かけ上は何も起こりません.「実機の動作がおかしいなあ」とつぶやき,デバッグを行って初めて,スタックがふくれあがってほかの領域を壊していることがわかるのです.これからきっと何度も経験することと思います.「またスタック・オーバフローか」と.これは,WindowsやLinux/UNIX上では味わえない楽しみ(?!)の一つです.
なお,ここでは再帰呼び出しを例に説明しましたが,通常,組み込みソフトウェアでは再帰呼び出しを使いません.再帰呼び出しを使うと,何度も再帰的に呼び出されることでスタックをたくさん消費するし,スタック・オーバフローを引き起こすことも多いからです.
●格言:挙動不審なプログラムの裏にスタックあり
プログラムのランタイム構造は,プログラムをデバッグするうえで理解しておくべき基本です.デバッグ時に,どう考えても理解できない動きを示す場合,ランタイム構造が破壊されていたり,あらかじめスタックとして確保した領域を超えてほかの部分のデータを壊していたりすることがよくあります.