試験運用中なLinux備忘録・旧記事

はてなダイアリーで公開していた2007年5月-2015年3月の記事を保存しています。

hashstyleについての覚え書き

  1. binutils 2.18に上げるだけ
  2. システム全体に有効にするためには、全てのELFを再ビルドする必要がある
    1. 再ビルドが必要なものと、そうでないもの
    2. 再ビルドの実際
  3. hashstyleがまだ有効になっていないものを探すには

binutilsのバージョン2.18がリリースされ、高速な動的リンクを実現する「.gnu.hash」が使えるようになっている。少し様子を見ていたのだが、問題はなさそうな感じだったので導入してみた。
http://www.sourceware.org/ml/binutils/2006-06/msg00418.html
には「〜50% dynamic linking improvement」とあるように、その効果は大きく、体感的にも、アプリケーションの起動時間が短縮されていることが分かる。ただし、動的リンクが高速化したのであって、初期化処理などに元々時間のかかるアプリケーションの起動時間が劇的に改善されるというわけではない*1

binutils 2.18に上げるだけ

(2007/10/17)2.18-r1は、x86x86_64ともに安定版扱いとなり、/etc/portage/package.keywordsの設定は不要になった.

安定版のbinutilsを使用している場合、/etc/portage/package.keywordsbinutilsの項目を追加し、

$ sudo emerge -avu binutils

でバージョンを上げるだけで、LDFLAGSの値を手動でいじったりすることなく、以降ビルドされるパッケージは、

$ readelf -a [新しくビルドしたパッケージに含まれる実行ファイルの場所] | grep GNU_HASH
  [ 4] .gnu.hash         GNU_HASH         0000000000400390  00000390
 0x000000006ffffef5 (GNU_HASH)           0x400390

のように「.gnu.hash」が使われるようになる。確認に使用したreadelfコマンドは、binutilsに含まれている。

システム全体に有効にするためには、全てのELFを再ビルドする必要がある

システム全体に対してhashstyleを有効にしたいのであれば、片っ端から再ビルドすることになるのだが、Gentoo Linuxでは、各パッケージのバージョンが上がるときにビルドすることになるので、無理に再ビルドをすることもない。一部、滅多にバージョンの上がらないもの(例: GTK+ 1系とそれに関連したパッケージ)に関しては行ったほうがよいかもしれない。

再ビルドが必要なものと、そうでないもの
ELF形式の実行ファイルやライブラリで構成されているパッケージ、インタプリタ(例: Python Perl PHP Rubyなどに加え、Monoも含む)、言語バインディング(例: gtk2-perl gnome-python gnome-sharpなど)の類は再ビルドが必要。
フォント、ドキュメント、テーマファイル(gtk-enginesのように、共有オブジェクト(*.so)のテーマエンジンを含むものは再ビルドが必要)、ゲームの付属データ、ELF以外の実行形式(各種スクリプト言語や、Java、.NETなど)のみのパッケージ、などは入れ直す意味がない。

再ビルドの実際
emerge -e worldは、全てのパッケージを入れ直すので、安易に実行すると、時間や電気が無駄になる。

$ sudo emerge -pqe world | sed -e 's/\[[0-9].*\]//g' -e 's/\[.*\] /=/g' > list.txt
(list.txtを編集)
$ sudo emerge -av $(cat list.txt)

のように、インストールされるパッケージのリストをファイルに出してから、再インストールする必要のないものを除いて、再ビルドを実行させるとよいのだが、再ビルドの必要があるのかが不明なものが出たら、まずはリストから除外して、確実に再ビルドすると分かっているものを先に入れ直した後、以下に紹介する方法で、「.gnu.hash」セクションの無いものを検出して、残りを処理していくような形がよいのかもしれない(もっとうまい方法がある可能性もあるが...)。

hashstyleがまだ有効になっていないものを探すには

「.gnu.hash」セクションの無い実行ファイルやライブラリを調べるには下のようにする。検索する場所はfindコマンドの引数の部分に指定する。実行ファイルもライブラリも含まないディレクトリは含めないように指定するとよい。ディレクトリ構成は、x86_64のものなので、検索ディレクトリは環境によって変える必要があるかもしれない。

(実行ファイル)
$ sudo bash -c 'for x in $(for y in $(find /bin/ /sbin/ /usr/bin /usr/games/bin /usr/libexec -type f -print); do file $y | grep dynamically > /dev/null 2>&1 && echo $y; done); do readelf -a $x | grep GNU_HASH > /dev/null 2>&1 || echo $x; done' | less
(共有オブジェクトファイル)
$ sudo bash -c 'for x in $(for y in $(find /lib32 /lib64 /usr/lib32 /usr/lib64 /usr/games/lib32 /usr/games/lib64 -name "*.so*" -type f -print); do file $y | grep ELF > /dev/null 2>&1 && echo $y; done); do readelf -a $x | grep GNU_HASH > /dev/null 2>&1 || echo $x; done' | less

一通り再ビルドしたにも関わらず、よく分からないまま残ってしまった、というものがあったら

  1. portage-utilsのqfileで、そのファイルがどのパッケージに含まれているのかを特定し、無ければ消す(手動で入れた覚えのあるものは除く)
  2. gentoolkitのequery depends [パッケージ名]で、そのパッケージを要求するパッケージを表示し、1つでもあれば再ビルド、何も表示されなければアンインストール

などのように対処する。emerge --depcleanという手もあるが、十分注意して使う。また、Gentoo Linuxをインストールしたときの古いbinutilsGCC関連の不要なファイルが出てくることもあるが、これらは消しても問題ない。
x86_64環境での32bit互換パッケージ(emul-linux-x86-*)や、バイナリ提供のパッケージに含まれているものは、残ることがある。他にも、一部ライブラリは「.gnu.hash」が使われない?ものもある。

$ sudo bash -c 'for x in $(for y in $(find /bin/ /sbin/ /usr/bin /usr/games/bin /usr/libexec -type f -print); do file $y | grep dynamically > /dev/null 2>&1 && echo $y; done); do readelf -a $x | grep GNU_HASH > /dev/null 2>&1 || echo $x; done'
/usr/bin/nvidia-xconfig
/usr/bin/cgc
/usr/bin/pango-querymodules32
/usr/bin/gtk-query-immodules-2.0-32
/usr/bin/gdk-pixbuf-query-loaders32
$ sudo bash -c 'for x in $(for y in $(find /lib32 /lib64 /usr/lib32 /usr/lib64 /usr/games/lib32 /usr/games/lib64 -name "*.so*" -type f -print); do file $y | grep ELF > /dev/null 2>&1 && echo $y; done); do readelf -a $x | grep GNU_HASH > /dev/null 2>&1 || echo $x; done'
/lib32/libncursesw.so.5.5
/lib32/libblkid.so.1.0
(中略)
/usr/lib32/libpango-1.0.so.0.1600.4
/usr/lib64/libssl.so.0.9.7
/usr/lib64/libcrypto.so.0.9.7
/usr/lib64/xorg/modules/drivers/nvidia_drv.so
/usr/lib64/opengl/nvidia/extensions/libglx.so
/usr/lib64/opengl/nvidia/extensions/libwfb.so
/usr/lib64/opengl/nvidia/tls/libnvidia-tls.so.100.14.19
/usr/lib64/opengl/nvidia/no-tls/libnvidia-tls.so.100.14.19
/usr/lib64/opengl/nvidia/lib/libnvidia-cfg.so.100.14.19
/usr/lib64/opengl/nvidia/lib/libGLcore.so.100.14.19
/usr/lib64/opengl/nvidia/lib/libGL.so.100.14.19
/usr/lib64/libCg.so
/usr/lib64/libCgGL.so
/usr/lib64/codecs/sipr.so
/usr/lib64/codecs/drvc.so
/usr/lib64/codecs/cook.so
/usr/lib64/codecs/atrc.so
/usr/lib64/klibc/lib/libc.so
/usr/lib64/klibc/lib/klibc-Zfr15yna-Brj5oGkXdCarh0_pfE.so
/usr/lib64/libapr-0.so.0.9.12
/usr/lib64/libXvMCNVIDIA.so.100.14.19

関連URL:

*1:とは言え、確実に短縮はされるし、大規模なものはリンクするライブラリも多いため、効果もその分あるとも言えるかも