もともとの意図を思い出すと、 「main という手続きの中から、hello という別の手続きを呼び出す」 必要がある。
想像がつくように、hello という手続きを定義しておき、 main の内部で jal hello を実行すれば目的は達成される。
しかし、jal hello を実行すると $ra が新たなアドレス (図 3 では 0x0040002c) で上書きされ、 main 終了後の戻りアドレス 0x00400018 が消されてしまい、 プログラムが正しく終了できない、という問題が起こる。
そこで「手続き hello を呼び出す前に $ra の値を保存しておく」 必要が生じる。 このように、レジスタの値等を一時的に保存するための記憶領域として スタックというメモリ領域が用意されている。
スタックはメモリ上にあるので、今まで同様 lw や sw を用いて値を読み書きできる。 ただし、読み出しや書き出しを行なう位置はスタックポインタ $sp という特別なレジスタに保持しておく規約になっている。
ここで、スタックポインタ $sp を用いて戻りアドレス $ra を退避する方法を図 4 に示す。 (なお、メモリのロード/ストアに対応するものを、 スタックではポップ/プッシュと呼ぶ)
図で網かけの領域はシミュレータで使われる領域であるのでそこには アクセスせず、それよりlow address の領域を用いるようにする。 (なお、教科書などではスタックの説明をするのに上下逆の絵を描く 慣習だが、ここでは混乱を避けるため 今まで通りの描き方で統一する。)
図にあるように、スタックに退避 (プッシュ) するときは $sp の値を 4 引いてから従来通り sw で値を書き込む。
逆に、スタックから値を戻す時は lw で値を読み込んでから $sp の値に 4 を足し、 初期状態に戻しておく。
以上で HelloFunc.asm のプログラムの内容を理解する準備が整った。 プログラムの中身を見て、何が行なわれているのか理解してみよう。
また、プログラムを少し修正して以下の設問に答えよ。