あまつぶ

9.28 【レジスタの保存】

 恒例となりつつある、ダウンロード数の話から。前回は、9.1だったみたい。
 気になる(?)ごたく+……のダウンロード数は、17838に。さすがにだいぶペースは落ちてきたみたいだけど、まだ500以上というのはすごい。少なくともそれ以上のペースでMacユーザが増えているということかな(笑)。
 Geneva2Osakaが2位になってた話をちょっと前に書いたけど、現時点(じゃなくてメールが送られてきた時までの時点か)で4250だったんだそうな。ランキングにも載るわけだ。ま、もうおそらく、これをこえる記録は生まれないだろうな(汗)。
 QT-QとPhutは、それぞれ262と674。これが多いのか少ないのかわからないけど、どちらも前に書いてある数からすると減っている(^^;; ま、新しいバージョンは必要でなかった人もいるだろうし(要するに、使ってみたけど「いまいちだな」と思った場合か(笑))、そんなもんかな。そう考えると、最初に公開するバージョンというのは重要なものなのかも知れないな。うちのソフトは最初のバージョンからちゃんと使えるってのはほとんどないけど。
 そうだ。いつも書き忘れているけど、ダウンロードしてくださった方、どうもありがとうございます。

 コントロールパネルの続きは、たいして進んでいないのでレジスタの保存のことを書こうかな。上と同じ9.1に書いた、WordPerfectで下線が出なくなるという問題に関して。まだダウンロードはできていないのだけど、おそらく原因もわかって対処もできたつもり。現在某MLでテストしていただいている某ソフトを使ってもちゃんと下線が表示されるようになったそうだし。それを踏まえて、Geneva2Osaka 1.31b1を公開開始。
 まず不思議だったのは、某ソフトではカレントアプリケーションのクリエータコードをチェックしているから関係ないアプリケーションの場合では素通りしてなにもしないはず。その場合、まずグローバル変数にアクセスするためにSetCurrentA4()を呼び、その後クリエータコードをチェックするルーチンを通ってパッチを当てる前のトラップルーチンに飛び、最後にSetA4()でA4を元に戻して戻るだけ。
 クリエータコードをチェックするルーチンが問題だとは考えにくいので、そうすると気になるのはSetCurrentA4()か。A4を介してグローバル変数にアクセスしているわけだが、それがまずいのかも知れない。ということは、A4を介さずに(SetCurrentA4()を使わずに)グローバル変数にアクセスすることができれば問題は解決するのではないか。
 と、考えたまではよかったが、A4を介さずにグローバル変数にアクセスする方法が思いつかない。やはりどうしようもないのか……と思いつつMacintoshプロフェッショナルプログラミングをぱらぱらとめくってみると、気になる記述を発見。「SetCurrentA4()は、A0とD0を破壊する」 ということは、ひょっとすると、WordPerfectはこのトラップを呼んだ時にA0(D0かも知れないけど)が保存されることを前提にしているということか? 確かどこかで、A0に値を返すわけではないトラップを呼んだあとのA0をあてにしてはいけないというようなことを読んだことがある気がするが、それがまさに目の前で起こっているのだろうか。

 そこでものは試し、SetCurrentA4()を呼ぶ前にA0とD0を保存(movem.l d0/a0,-(a7))して、SetA4()のあとで元に戻す(movem.l (a7)+,d0/a0)ようにしてみた。CodeWarriorでは関数中にアセンブラのブロックを置くことができないので別のところに書いてアセンブルしたあとのコードを直接埋め込むことにした。できたコードを逆アセンブルしてみると、movem.lが最初と最後に2つずつ並んでいてなんだか妙だ。
 片方のmovem.lはCodeWarriorがルーチン内で破壊している他のレジスタ(A2とか)を保存するために自動的につけられるもの。これをいじって「ついでにA0とD0も保存してよ」ってことにできればもっとシンプルになるだが、CodeWarriorだけでは実現不可能かな。コードができたあとにパッチを当てるとか……、あー、すべてアセンブラで書くっていう方法ならできるけど(笑)。
 この変更をしても、うちでの動作はまったく問題なし。まあ、アドレスを保存するように修正したんだから問題ないに決まっているが。問題があるとすればコードを追加したことによる速度の低下だが、おそらく気にするほどのことではないはず。Cで書いた部分のコーディングだってまだまだ甘いわけだし。
 ところで、コードを直接埋め込む方法。他にもいろいろ方法はあるのではないかと思うけど、

void	SaveA0D0(void) TWOWORDINLINE(0x48E7,0x8080);
void	RestoreA0D0(void)	TWOWORDINLINE(0x4CDF,0x0101);


うちではこんなことをしてみた。ヘッダファイルにあるような形のもので、「SaveA0D0();」などと書けば、指定した4バイトがそこに書き込まれるというわけ。コードは、それぞれ上に書いた「movem.l d0/a0,-(a7)」と「movem.l (a7)+,d0/a0」に対応。
 当然ながらこのコードは68k環境でしか有効ではない。PowerPC環境では、こんなややこしいことをする必要はなく、なにもしなくてもグローバル変数にアクセスできる。レジスタの保存も、勝手にやってくれる。だから、上の定義は「#if !powerc」と「#endif」とかでかこっておけばより安全かな。ソースを共有するなら、PowerPC環境ではそれぞれを空白と解釈するようにしておけば完璧。ま、そんなところ。

to September 27, 1999 ↑ to September index → to October 1, 1999