z80 golf(4)
文字列をfall throughさせる技法についていくつか補足しておく。
昨日の日記でも書いたが、このとき1バイトで出来る変換を施すのが良い。
+1 / -1のオフセットを加算するのが典型的だが、他には、Z80だと、2の補数(NEG)、1の補数(CPL)、ローテイト、算術シフトなども1バイトで出来る。あと、ループ変数的に変動するレジスタがあれば、そいつとのADDやSUBも出来る。
たとえば、このとき、
LD A,(HL)
INC L ; Lは1ずつ増える
ADD A,L
のようにしてdecodeすることが出来る。INC Lの位置は、ADD A,Lの後ろにすることもでき、こうすることで、1だけずらしてdecodeすることも出来る。もちろん、ADD A,LをSUB Lに置き換えることもできる。
このようにして文字列に自分が望むコードになるようにencodeするのだが、なかなかうまくいかない。この手の変換で一番有望なのは、右シフトである。
今回の文字列の場合、文字コードはすべて 80h 以下なので、MSBが1bit余っている。このMSBの余裕を使って、 AND 7fhでマスクをとりながら文字を出力する。こうすれば、 +80h のコードを自由に選択することが出来るようになる。この選択の自由度が大きな可能性を切り開くことになる。
「AND 7fは1バイトじゃないやん」と言われそうだが、そこで右シフトである。(Z80には右シフトは1バイトではなく、実際はCYをからめたローテイトを使うことになるのだが、CYは0だと仮定できる状況で有効である)
そうするとLSBの1bitに選択の自由度が出来るので、こいつで命令を調整するのが有効で、よくプロテクトのチェックルーチンを書くときに解析されにくくするためにこの手の技法を多用したものだが、今回の場合、これもうまくいかない。'Hello, world!'の' 'や'!'が大変憎らしい。いままでの人生でこんなに'Hello, world!'の文字列が憎らしく思えたことはないし、きっと、これからもないだろう。