裏CHUNSOFT > ゲーム解析入門 > 3.スタック

3.スタック

スタックとは、針に円盤を通すようにデータの出し入れができる仕組みです。 仕組み自体は基礎知識に書いているので、それを見ながら読んで下さい。

レジスタの値をスタックにプッシュ、或いはスタックからレジスタに値をプルする命令は以下の通りです。 「なし」となっている所は該当の命令がありません。 しかし、少し考えるとそんな命令が仮にあったとしても意味がないということが分かるかと思います。

レジスタレジスタの値をプッシュレジスタに値をプル
"A"PHAPLA
"X"PHXPLX
"Y"PHYPLY
"S"なしなし
"PC"なしなし
"PB"PHKなし
"D"PHDPLD
"DB"PHBPLB
"P"PHPPLP

また、PEA $YYXXという命令もあり、これは任意の値YYXXをスタックにプッシュできる命令です。

スタックが使われるのは、大抵はレジスタの値の待避(ジャンプ命令の前後にあるプッシュ、プル命令がそれです)なのですが、変数代わりに使われたり、分岐に使われたりすることもあり、その場合は話が難しくなります。 以下、__はスタックの現在位置、つまり"S"が示すアドレスを表し、**は今までにプッシュされたデータを表すことにします。 分岐に使われる例を見てみましょう。 道具を使った時に、道具の種類毎に分岐する処理です。

030E42  C2 30        REP #$30        ; …… -- -- -- -- -- -- __ ** ** …… ; この時点で、道具コードは"X"に入っている
030E44  8A           TXA             ; …… -- -- -- -- -- -- __ ** ** …… ; "A" = "X"
030E45  0A           ASL             ; …… -- -- -- -- -- -- __ ** ** …… ; "A" *= 2
030E46  AA           TAX             ; …… -- -- -- -- -- -- __ ** ** …… ; "X" = "A"(ここまでで"X"を2倍にした)
030E47  BF 5B 45 C3  LDA $03455B+"X" ; …… -- -- -- -- -- -- __ ** ** …… ; "A" = {03455B+"X"}(道具を使った時の処理オフセット)
030E4B  F4 4F 0E     PEA $0E4F       ; …… -- -- -- -- __ 4F 0E ** ** …… ; 値0E4Fをスタックにプッシュ
030E4E  48           PHA             ; …… -- -- __ XX YY 4F 0E ** ** …… ; "A"の値をスタックにプッシュ("A"=YYXXとした)
030E4F  60           RTS             ; …… -- -- -- -- __ 4F 0E ** ** …… ; YYXXをプルして、それに1を加えたアドレスにジャンプ

03455B以降は、道具を使った時の処理のオフセットが入っています。 2バイトずつで、030001を加えたものが実際のアドレスとなります。

基礎知識にも書きましたが、サブルーチン命令について復習しておきましょう。 JSRは、正しくは「その命令の末尾のアドレス下位2バイトをプッシュし、引数のアドレスにジャンプする(上位1バイトはそのまま)」という処理を行うということです。 RTSは、正しくは「スタックから2バイトプッシュし、それに1を加えたアドレスにジャンプ(上位1バイトはそのまま)」という処理を行うということです。 だから結果としてRTSは元のルーチンに戻るということになるのです。

しかし、ここではRTSの時点でスタックの現在位置の次にはYYXX(道具を使った時の処理オフセット)が入っています。 従って、RTSは元のルーチンに戻るということではなく、03YYXX+1のアドレスにジャンプするということになります。 例えばめぐすり草(2B)だと、アドレス03455B+2*2B=0345B1の値は155Cだから03155Dにジャンプすることになり、実際ここにめぐすり草を飲んだ時の処理があります。

更に、ここではPEAによって0E4Fという値もプッシュされています。 これは、道具を使った時の処理の最後にRTSでプルされることになります。 よって、道具を使った時の処理が終わると030E50に、つまり030E4Fの次から再開するということになります。 結局この処理は、RTSを使って「道具毎にサブルーチンに分岐する」という処理を実現しているのです。

逆に言えば、サブルーチンにジャンプした直後と戻る直前で"S"が違っていれば、予測不可能なアドレスにジャンプしてしまうことになります。 プログラムを改造する時は気を付けましょう。

2010年8月8日更新

裏CHUNSOFT > ゲーム解析入門 > 3.スタック