ぐいぐい01に関するメモ-14
- (by K, 2008.12.20)
- メモのうち重要な部分をそのうちまとめてまともなページを作る
(29) 2008.12.20近況
- ここ1週間ほどの開発がここ数年で最高に充実していてかつ面白かったので記念でメモ。
- 少し前からOSASK-IRCにneriさんが常駐してくれていて、それでCOM64-GREの改良の話をしました。いろいろと改良してアーカイブ風になったあと、もっとコンパクトの役に立つ仕様にしたいということで、二人でどうしたらいいかを話し合いました。長すぎるシグネチャを短くするべきか、みたいなところが出発点だったと思います。こうしてCOM64plusの開発が始まりました。シグネチャを4バイトにするべきか2バイトにするべきか、そこも悩ましいところでした。
- それでneriさんは「ぐいぐい01」に採用されているテクニックを貪欲に吸収し、起動時に小アプリ一般にとって有利になるようなレジスタ初期値を採用して、なんとhello+.comのサイズが「ぐいぐい01」のhello(このときは27バイト)を下回る25バイトで書けるまでになりました。僕は「負けたあ」とその日はあきらめて寝ました。たしかcharsも負けました。
- しかし寝ているうちにアイデアを大量に思いついたので、それを翌日全部neriさんに聞いてもらって、どう思うか感想をききながら検討しました。それやるくらいならむしろこうしたほうがいいとか、それはいかにもhello専用の仕様過ぎて好ましくないとか、そんな感じの話をしました。そしてneriさんもいろいろとアイデアを出して結局hellok2.g01は22バイトまで行きました。neriさんのhello+.comは21バイトになりました。これは相当に「おかしい」サイズで、DOSの22バイトよりも小さいのです(註:この文脈での「おかしい」は最高の褒め言葉)。これに勝てるのはバッチファイルで"@echo hello, world"の18バイトくらいなものでしょう。文句なくx86世界最小だと思います。
- またchars+.comはついに15バイトにまでなり、でも「ぐいぐい01」もがんばって16バイトまではきました。もとが33バイトだったのに16バイトだなんてもはや半減です。DOS版が17バイトなので、やはりこれもneriさんは世界記録保持者だと思います。
- その後さらにもう一段僕が改良し(これはneriさんには応用しにくい改良)、helloは何とかneriさんに追いつきました。これで世界記録タイです。charsは追いつけませんでした。またechoも作りました。neriさんは作ってないので比べられません。
- (12.21追記)neriさんは起動時のECX初期値をコンパクトに設定できる形式を導入して1バイトの削減に成功。これでほぼ全てのアプリが1バイト以上小さくなることに。僕も負けじと考えて出現頻度の非常に高いパラメータを省略できるように改良。これで多くのアプリが1バイト以上小さくなることに。
- (12.22追記)昨日neriさんがオプションでCALL(EBP);をコードに追加する機能を付けるべきなんじゃないかと提案しました。この機能を付けるべきかいろいろ試行錯誤した結果、確かに付けたほうがいいと僕は判断しました(.g01の場合は先頭に付ける、COM64plusの場合は末尾に付ける)。またコマンドライン取得APIの仕様が勘違いで間違っていたことに気付いて修正したところ、このAPIが更に使いやすくなりました。これでまたサイズがかなり減っています。なおneriさん自身はまだCALL(EBP);の自動付加オプションをやるという決断にはいたっていないようです(でもきっとあとでやるとは思う)。helloが18バイトで書けるということは、ついにバッチファイルともタイだということです。ちなみにechoの13バイトはバッチファイルで"@echo %1 %2 %3"って書くだけで14バイトなので、すでにバッチファイルにも十分に勝っていると思います。
- (12.24追記)CALL(EBP);をやめてCALL([ESI]);にすることにしました。これだとEBPがあくので好きなことができます。アセンブラ版のバイト数は変わりません。でもC言語版のバイト数は1バイトくらい減らせそうです。・・・さらにCOM64plusのマネをしてレジスタの初期値ロード機能をオプションでつけました。これでcharsが16から14になりました。COM64plusに追いついた!
- 以下にここまでの成果(多分これが限界でもあると思う)を書いておきます。[2009.01.02更新]
| hello | hello-c | chars | echo | echo-c | cpy | cpy-c | makefont-c | sjisconv-c |
abcdw006用 | 27 | 86 | 33 | ? | 156 | ? | 612 | 691 | 912 |
abcdw007用 | 18 | 69 | 14 | 13 | 71 | ? | 342 | 347 | 507 |
abcdw008用 | 18 | 69 | 14 | 6 | 51 | 45 | 138 | 207 | 395 |
abcdw009用 | 17 | 68 | 13 | 6 | 50 | 45 | 134 | 203 | 389 |
COM64plus用 | 18? | 検討中? | 14 | ? | ? | ? | ? | ? | ? |
DOS用 | 22 | ? | 17 | 19 | ? | ? | ? | ? | ? |
- (註)echoはargv[0]が見えても見えなくてもよい。
- echoはもちろんジャンクAPIで実現しているが、ジャンクAPIはジャンクであるというマークがついている分だけ実行ファイルが長くなる傾向がある。もし他の部分は一切変えずに本仕様に昇格させれば、それだけでechoもecho-cも2バイトは縮むだろう。・・・というのはabcdw007までの仕様でのことで、abcdw008以降については本仕様級の仕様なので、ここから減ることはない。
- abcdw006→abcdw007の仕様変更はかなり大きなもので、基本的にバイナリ互換はありません。ソース互換すらほどほどしかありません。大規模改造なので僕も非常に苦労しています(アプリの移植はそれほどでもないけど、efg01の改造が大変)。
- これはまさに「乾いた雑巾を絞る」レベルの改良で、その中にあってcharsが半減したり、echo-cが半減したりと、ちょっとありえない劇的な進歩になっています。それもこれもみんなneriさんの協力のおかげです。・・・neriさんなしで一人でやっていたらこの設計に到達するまでに1年間はかかったと思います(その後の改良のペースもすごいのでトータルで2年分くらいは進んでいる気がする)。あとやっぱりabcdw006までで小さいアプリをたくさん作ってきて、ボトルネックというか、「こんな仕様だったらいいのに」を実感していたのもあると思います。
- それにhello-cも static char s[18] = "\x35\x01\x24\x8d" "hello, world\n" "\x23"; なんていういかにも「うさんくさい」「こんなの普通書くわけない」といった方法での86バイトだったのが、 g01_putstr0("hello, world"); という普通の書き方で69バイトになるようになっています(12.24:バイト数更新)。汚く書いたらもう少し小さくなるかもしれませんがまああまり変わらないでしょう。
- という劇的な大進歩なので、互換性がちょっと不足気味だったりリリースにてこずったりしても、どうか大目にみてください。
- 「こんな互換性に問題の出るバージョンアップが繰り返されたら安心してアプリを作れないじゃないか!」というのはもっともです。「いったいいつになったら落ち着くんだ?」といいたくなるでしょう。しかしこれは永遠に続くわけではないのです。というのはたとえばhelloは文字列だけで13バイトあって、しかも.g01のシグネチャだけで2バイトあるのですから、これだけでも最低15バイトは必要です。これより小さくなることはありえません(一般的なAPIとして不適切な設計にしない限り)。もちろんテキストファイルじゃないので他にも書かなければいけない何らかの情報やプログラムがあるわけですから、本当の限界はもっと大きい値でしょう。どのアプリもAPIを改良すればどこまでも小さくなるわけではないのです。限界があるのです。その限界に達してしまえば、それ以上どんなにいじってもより小さくなることはないので、仕様のバージョンアップが起きることはないはずです。
- 現状を見てください。なんかもうひどく限界に近い気がしませんか?まあ僕だってabcdw006の段階で既に限界だと思っていました。だからそういう「感じ」が必ずしもあてになるわけではないのですが、しかし大いに参考になる目安だとは思います。・・・早く限界に近づかせる方法は、サイズを追求する人がさらに増えて、この分野の研究が進むことしかないでしょう。
- 以下にabcdw006との比較を書いておきます(全部C言語のみ)。[2008.12.24更新]
| pi | calc | cpy | makefont | bim2hrb | sjisconv | gas2nask | nask |
abcdw006用 | 241 | 1583 | 612 | 691 | 987 | 912 | (5114) | 23314 |
abcdw007用 | 205 | 1521 | 386 | 439 | 766 | 644 | 5001 | 23040 |
- (註)piは.hrb版の229バイトに対して逆転に成功。参考までに書いておくとcalc.hrbは1668バイト。
- calcはこのサイズより小さくCで書く方法がないということではない。オリジナルのhrb版のソースにできるだけ近いソースを使わなければいけないという制約を自ら科しているためにこのサイズに留まっている(コマンドラインバッファをより長くすることだけは許される)。
| obj2bim | bim2g01 | bin2obj | naskcnv0 | aksa | golib00 |
abcdw006用 | 7211 | (1956) | 983 | 2050 | 5311 | 2749 |
abcdw007用 | 6903 | 1792 | 729 | 1778 | 5079 | 2476 |
- (12.25追記)昨日とりあえずabcdw007をアップロードしたのですが、一日たってぼんやり眺めていると、なんかcpyが386バイトやmakefontが439バイトと、どちらも512バイト未満に収まっているのに対して、sjisconvが644バイトに留まっているのがなんか気にいりません。そんなに複雑な処理をしているわけでもないのに・・・。で、数十分ほどいじっていたらなんとか減量に成功して507バイトになりました。うんうん、こうでなくっちゃ。で、sjisconvの減量に成功してみると、今度はcpyやmakefontも小さくしてやろうかなという気になりました。どちらも10分くらいでそれなりに小さくなりました。ということで、その成果を。・・・いやあやっぱり、APIが使いやすいと減量も簡単です(というかabcdw007版がとにかく新efg01で動けばいいやで手抜き過ぎた?)。たぶん他のアプリも手入れすればそれぞれ100バイトくらい減量できそうですが、時間もないしめんどくさいのでいつか気が向いたときにします。
| sjisconv | cpy | makefont |
abcdw007版 | 644 | 386 | 439 |
改良版 | 507 | 342 | 347 |
- (12.26追記)しばらく開発しないといっておきながら、突発的にcpyをnaskで書いたら何バイトになるのかが気になって(たぶん禁断症状)、それで作ってみました(実際はASKAで書きました)。abcdw008で実装予定の(つまりまだ未実装の)APIを勝手に使って書いたところ、cpyは51バイトで書けることが分かりました。うおおおぉー。これはすごい。やっぱりアセンブラは偉大だー。あとはこの51バイトを使いたくてしょうがなくなったらabcdw008を作ることにします(笑)。ちなみにこのAPIを使うとechoは11バイトになります。他のアプリもみんな100バイトくらいは減るんじゃないかなあ。もちろん上記で減量に成功したsjisconvやmakefontも。
- (12.27追記)コマンドライン周りの設計中(本仕様級)。以前は数ヶ月かけてもできなかったのに、今だと数日でこんなにはかどる。でも時間がないので比較的ゆっくり。ちなみに昨日のcpyのASKA版は更に見直しで45バイトになり、echoも9バイトになりました。
- (12.28追記)abcdw008向けのmakefont-c(現在207バイト)をASKAで書いたら72バイトになった。やっぱりアセンブラは偉大だー。
- (01.02追記)アイデアを思いついた!ので現在効果を見積もり中(abcdw009)。とりあえずバイナリ互換はなくなります。・・・アプリを丁寧に作るとそれだけ小さくなってくれるので、すごく気持ちがいいです。やりがい一杯、手ごたえ一杯。やっぱりこうでないと!
こめんと欄
- 現在abcdw007の今週中のリリースを目指してがんばり中。 -- K
- とりあえずリリースしました。MLへは後日投稿します。 -- K
- abcdw008ができましたー。 http://osask.jp/files/ 6バイトのechoや45バイトのcpyなど、こんなので本当にちゃんと動くの?といいたくなるサイズのアプリが一杯です。MLへは後日投稿します。 -- K
- abcdw009ができましたー。 http://osask.jp/files/ abcdw009があればabcdw008はいらないようになっています(というか以前のバージョンは全部なくても大丈夫)。MLへは後日投稿します。 -- K
Last-modified: 2009-11-21 (土) 00:00:00 (JST) (319d) by lina