next up previous
: [SPIM] 関数 square の : [SPIM] 手続き hello の : jal (jump and link)

スタック、スタックポインタ $sp

さて、ここまでで (手続き) main が呼び出されて処理が終了するまで の流れを概観した。

もともとの意図を思い出すと、 「main という手続きの中から、hello という別の手続きを呼び出す」 必要がある。

想像がつくように、hello という手続きを定義しておき、 main の内部で jal hello を実行すれば目的は達成される。

しかし、jal hello を実行すると $ra が新たなアドレス (図 3 では 0x0040002c) で上書きされ、 main 終了後の戻りアドレス 0x00400018 が消されてしまい、 プログラムが正しく終了できない、という問題が起こる。

そこで「手続き hello を呼び出す前に $ra の値を保存しておく」 必要が生じる。 このように、レジスタの値等を一時的に保存するための記憶領域として スタックというメモリ領域が用意されている。

スタックは、メモリアドレス 0x80000000 より low address のメモリが high から low に向かって (図では下から上へ) 使われる。 なお、配列 (データ領域) の場合は low から high へだったが、 スタックは逆に用いられるので注意。

スタックはメモリ上にあるので、今まで同様 lwsw を用いて値を読み書きできる。 ただし、読み出しや書き出しを行なう位置はスタックポインタ $sp という特別なレジスタに保持しておく規約になっている。

ここで、スタックポインタ $sp を用いて戻りアドレス $ra を退避する方法を図 4 に示す。 (なお、メモリのロード/ストアに対応するものを、 スタックではポップ/プッシュと呼ぶ)

図 4: スタックに対するプッシュとポップ
\begin{figure*}\begin{center}
\epsfbox{poppush.eps}\end{center}\end{figure*}

図で網かけの領域はシミュレータで使われる領域であるのでそこには アクセスせず、それよりlow address の領域を用いるようにする。 (なお、教科書などではスタックの説明をするのに上下逆の絵を描く 慣習だが、ここでは混乱を避けるため 今まで通りの描き方で統一する。)

図にあるように、スタックに退避 (プッシュ) するときは $sp の値を 4 引いてから従来通り sw で値を書き込む。

逆に、スタックから値を戻す時は lw で値を読み込んでから $sp の値に 4 を足し、 初期状態に戻しておく。

以上で HelloFunc.asm のプログラムの内容を理解する準備が整った。 プログラムの中身を見て、何が行なわれているのか理解してみよう。

また、プログラムを少し修正して以下の設問に答えよ。

  1. プログラム中に「この位置における $ra の値は?」とかかれた部分が 2 ヵ所ある。この位置における $ra の値を調べてみよ。$ra の値を 適当なレジスタに代入して、Windows 版 SPIM のウィンドウ上で確認すれば良いだろう。 (ヒント: $t0 = $ra + 0 など)
  2. 上で調べた $ra の値は何を意味しているか考察せよ。


平成16年11月17日