Assemblyコードの最小化(?)

どうも、チョコです。Assemblyちょっとやってたら調子に乗って記事書きました。誤りがあったら訂正お願いします。

この間、BootLoaderを書いていたが、ファイルサイズが1Sectorの512バイト(-署名2バイト)に入らなければいけなかったため、最適化を行った。(もちろん、ほかのSectorを呼び出して実行はできるが、それでは面白くないから。)

BootLoader#とは?

パソコンが起動したとき、BIOSが初めて実行する512バイトのプログラムをMBRと呼び、このコードがWindowsなどのOSの起動(Boot)をすればBootLoaderと呼ばれる。

最小化#とは?

ここでは、RAMとかStackの最適化とかせずに、実際にコードが保存されているバイト数の節約をする。512バイトしか使ってはいけないので、油断するとすぐ使えないプログラムになってしまう。なんでC++で書かないかのも、このためである。(gcc使えないからとかは黙っておこう)

(ただし、MBRはRealModeで実行するので、Registerは最大32ビットである。)

512バイトで何ができる?

例えば、テトリスのゲームを作ろう。こんな感じの。(最適化の話なので、実際のプログラムはどうでもいいかと)

DA0a29XVoAAfyv6

(作り方を詳しく聞きたい人は、これが完成したら記事を書くので、お楽しみに。)

ここで、移動の処理だけのコードを書くと、なんと100バイトくらい使った。ブロックを積み重ねる判定付けたら180バイト使った。残りのバイトでクレアとか回転とかを実装できそうにないなぁと。

では、プログラムのバイト数を削ってみよう(実際の処理内容は変わらない)。

1.一回しか使わない関数はinlineで書く。逆に、2回以上使う長い処理は関数にまとめる(こっちは常識だな)。call[address] … retは6バイト消化してしまうため、重複処理が6バイト以上であるときだけ関数を使うべき。またRegisterはGlobal変数なので、関数内で宣言もできる。

2.xorを使う(Assemblyでは常識かな)。Registerを0にしたいときにmov EAX,0を書くと4バイト使ってしまうが、xor EAX,EAXを書けば2バイトになる。

3.sub-registerを用いる。EAXの後半がAXで、AXがAHとALの合成など、必要な所を読み、変更できる。例えば、AXは最初が0であれば、mov AX,1とmov AL,1は両方1になるが、AXの場合は2バイトなので結局mov AX,0x0001となり、1バイト無駄になる。

いまは大体こんな感じ。使っている定数に対するregisterのバイト数を気にすると結構バイト数減らせた。以上のことをやるとなんと20バイト以上減らせた。わーい。

(まだ現在進行形ですが、)ソース

では。

Posted on