glibc 2.2.5


nfsd とか top とか、細々としたのを make しているうちにキレた。 emacs クラスの大物なら自前で build する気にもなるが、ちまちまといちいち make してまわるのはかなわん。 まとめて全部一括で Debian woody に面倒みてもらうことにする。 しかし、いまの Debeian woody バイナリの多くは libc に glibc 2.2.3 or higher を要求するため、 SL-A300 のデフォルトの 2.2.2 では足りない。

Woody の 2.2.5 をそのまんまつっこんでもいいのだろうが、 それこそ最適化ついでもあって自前で build という話。 実は build そのものは時間食うわりに手間は大したことない。 どっちかってーと、問題はそのあとだ。

カーネルヘッダの準備

シャープが配付している glibc に付属するカーネルヘッダは kernel 2.4.6 のものだ。 つまり SL-5000 系のものだ。glibc みたいなシビアなやつ作る前に SL-A300 のものに入れ換えておく。 2.4.6 以降で glibc が触る部分に変更はないみたいなんで、気分の問題だけど。
# pushd /opt/Embedix/tools/arm-linux/include
# mv asm asm.old
# mv linux linux.old
# pushd
# bzip2 -d < linux-sla300-20020905.tar.bz2 | tar -xv
# cd linux
# cp arch/arm/def-configs/discovery-MV .config
# make menuconfig
# make depend
# cd include
# tar -cvp asm-arm asm-generic linux | tar -xpC /opt/Embedix/tools/arm-linux/include
# cd /opt/Embedix/tools/arm-linux/include
# ln -sf asm-arm asm
asm-generic もコピーしたが、asm-arm の一部が参照してたので。 glibc じゃないけど、実際なんだかのアプリを make したときにひっかかったから、たぶん必要なんだろう。

Normal version

glibc は基本的に cross compile に対応している。 Debian の rules ファイルも対応していた。
... ので、-a<arch> オプション使って cross build できる。 うーむ、このオプション初めて使った。
% apt-get source libc6
% cd glibc-2.2.5
% export PATH=/opt/Embedix/tools/bin/:${PATH}
% export LINUX_SOURCE=/opt/Embedix/tools/arm-linux
% fakeroot dpkg-buildpackage -aarm
% cd ..
% fakeroot alien --to-tgz libc6_2.2.5-6_arm.deb
これで build から binary package 作成までまとめて面倒みてくれた。楽になったなぁ。 時間のほうはあいかわらずかかるけど(セレロン 300MHz で約 100 分) ...

いかにも linux のソースを指定するようにみえる "LINUX_SOURCE" には本物の kernel source tree を指定してもいいが、 include ファイルの一部を libc6-dev 作るときに一緒にまとめてパッケージングするのに要るだけなんで、 指定しないでおいて libc6-dev 作るトコでわざとエラー起こさせて build を止めさせてもいい。 この時点で libc6 のほうは全部出来上がってるので困ることはない。

Locale
自前で make したのを置き換えるのにあたって気になったのが locale の扱いである。 Vine のアプリを Debian に持ち込んでも同じ挙動にならず、 locale ごと持ってこなければならないとか、 どーも Redhat 系と Debian 系で (元ネタ同じくせに) locale の扱いに微妙に差がある。 SL-A300 のは雰囲気 RedHat 系なので Debian のをコピーして大丈夫かって ディレクトリ見るまでは思ってたんだが、/usr/share/locale/ に何にも入ってなかった ... 誰も lib/locale 参照してないでやんの。つまらん (をい)。

ということで、 何の気兼ねもなく出来上がった libc 2.2.5 とかをまとめて SL-A300 に持ち込んだらちゃんと動いた。 もしかすると locale も見てる konsole あたりの挙動がアヤしいかもしれないが、 どーせその場合は konsole のほうを書き換えるから、これでいい。 つーか、もともと /usr/lib/locale が空なんだから、 2.2.5 でヘンだったら 2.2.2 でもヘンな動作のはずだろう。

なお、ここで不精して RAM に置くとハングするので注意。
正しい ld-linux.so.2 が /lib (ROM 上にあるはずだ) になければならず、 そして glibc 2.2.2 に付属する ld-linux.so.2 (ld-2.2.2.so) は glibc 2.2.5 に対応していない。 逆に ld-2.2.5.so のほうは glibc 2.2.2 と組んで使えるけど。 ← つまりハングさせたわけね。

/usr/share/zoneinfo
glibc には /usr/share/zoneinfo/* もついてくるが、 これが普通に作ると約 5MB ある。一方 SL-A300 上では 500kB. なんでこんなに違うんだと思ったら、symlink でごまかしたりといろいろ。 めんどかったので同名のファイルだけ cp した。... 疲れてるな ....

libc-opt

"libc6-opt" というものがある、んだそうだ。 rules ファイルを読むと、べらぼーに最適化オプションつけまくった libc のようである。 おおむね: ↑な感じ。デフォルトは↓である。 デフォルトは本当に最低限っすな。

しかし、これがどこをどーいじっても最後までいかずに途中でとまる。 たいがいパッケージをつくるちょい手前の、ファイルを用意する段階でコケる。 諦めてファイルかきあつめて SL-A300 につっこんだら、 /sbin/init が segmentation fault を起こした。 なんとなくそんな気はしたんだ ... -fomit-frame-pointer 付けてるし。 GNU の巨大アプリ/ライブラリで -fomit-frame-pointer 付けてまともに動いたためしねーもん。

というわけで、libc6-opt 経由での最適化はボツ。

debian/sysdeps/sysdeps.mk

libc6 の最適化オプションは debian/rules ファイルではなく、 debian/sysdeps/{linux.mk, sysdeps.mk} のほうに実体がある。debian/sysdeps/linux.mk のほうに
MIN_KERNEL_SUPPORTED := 2.4.5
を置き、debian/sysdeps/sysdeps.mk
HOST_CFLAGS = -pipe -O6 -funroll-loops -fstrict-aliasing
とした:

MIN_KERNEL_SUPPORTED (--enable-kernel) による挙動の違いは sysdeps/unix/sysv/linux/kernel-features.h にある。arm では 2.4.0, 2.4.4 あたりで挙動が変わる。せっかくだから 2.4.5 と指定。これは要するに

2.4.0 以上に存在する system call 実行
もしエラーなら、
2.2.0 に存在する system call 実行
といった構造の後半分がなくなるだけなので system call が成功するケースではビタ一文速くなんないが、 ... 失敗するケースではちったー効果あるんかなぁ(ベンチかけてないので弱気)。 ただ system call というのはかなりの高率で失敗するんよね。だから指定してみたんだけど。 HOST_CFLAGS のほうは xscale のパイプラインストール対策っつうことで -funroll-loops 指定。 これによる libc のファイルサイズ増加は 10% 強。速度寄与分はそれ以上だろうからこれは文句なし。

いずれにせよ最適化についてはベンチかけんと何も言えん。 けどベンチかけるんも ROM 書き戻しとかめんどくさい ...

cramfs へのコピー

どーでもいいが、これが(も?)とてもめんどかった。

名前が違う (libc-2.2.2.so と libc-2.2.5.so etc.) から、cp で上書きできないばかりでなく symlink 先も違う。SL-A300 中では ROM の中だから SL-A300 に移ってから ldconfig で symlink 一気張り替えというわけにもいかず、 ひとつひとつ手で張り換える ... のは多分 unix 的には間違いで、 script 書いて半自動で一気に書き換えるべきなんだろうが、なにしろファイルの取捨選択で人の判断が入る。 libnss_nisplus まで cp する必要はねーだろ、とか。

いったん rm して tar でまるごとコピーして必要なさそうなものを消していくのがはやそうだが ... libe2p, libext2fs など glibc 由来でないライブラリも /lib に入ってるので、 忘れずに戻さないといけない。

というわけで、結局ディレクトリ見比べてのファイルの名前比較っつう作業が省けないのであった。

サイズ

libc のコンパイルオプション サイズ(バイト)
Normal 1190788
libc6-opt 1238360 動かず :-<
unroll-loop したやつ 1349236 現用
SL-A300 付属のやつ 1152468 ROM ver1.1 の glibc 2.2.2

この 200KB のサイズ増加そのほかの理由で cramfs は 14811136 バイトにおさまりきらなくなった。 15073280 バイト以下ではあった (15056896 バイト...) のでそのまま ROM に書き込んで、 いまも普通に使えている。

SL-5000 系のカーネルソース見たらこっちの ROM disk のサイズは 14811136 バイトで、 "14811136 バイト" の上限は合理的だった。 シャープさんてば、SL-A300 に持ちこむ時に何も考えずにドキュメントや script 作ったに違いない。

libncurses

ところで、libc を換えただけでは woody が使えるとは限らない。標準配付の中では libncurses が 4.2 と古く、woody が 5.0 を要求するので ncurses を使うものは動かない。 ちなみに telnetd (/usr/sbin.rom/in.telnetd) が libncurses を使ってる。 てことは実は無くてもいいんか。

... ま、でも libncurses は libc と違って /usr/lib において /lib のを上書きしてもいいからね。 あとまわしってことで。


[日記へ] [目次へ]