CentOS5.5, x86(32bit), VMware上でここ数日、ず~っとはまってるのが uClibc で動的リンクに失敗する問題。 ret1.c: int main(void) { return 1; } たったこれだけ。つまり、uClibcのローダとスタートアップルーチンしか使わない最小のプログラム。 が、どうにも動かない。デバッグ有効でLD_DEBUGもONにしたところ、こんな出力が: #pre||> $ LD_DEBUG=y ./ret1_dyn argc=1 argv=0xbfb37034 envp=0xbfb3703c ELF header=0x363000 First Dynamic section entry=0x36aeec Scanning DYNAMIC section Done scanning DYNAMIC section About to do library loader relocations Done relocating ldso; we can now use globals and make function calls! _dl_get_ready_to_run:317: Cool, ldso survived making function calls _dl_malloc:194: mmapping more memory _dl_get_ready_to_run:501: Lib Loader: (0x363000) /home/msakamoto/reduced.linux/uclibc_test/runtime/lib/ld-uClibc.so.0 _dl_get_ready_to_run:440: calling mprotect on the application program _dl_get_ready_to_run:786: file='libc.so.0'; needed by './ret1_dyn' _dl_load_shared_library:212: find library='libc.so.0'; searching _dl_load_shared_library:289: searching ldso dir='/home/msakamoto/reduced.linux/uclibc_test/runtime/lib' _dl_load_elf_shared_library:803: file='/home/msakamoto/reduced.linux/uclibc_test/runtime/lib/libc.so.0'; generating link map _dl_load_elf_shared_library:804: dynamic: 0xb7f26ed8 base: 0xb7ede000 _dl_load_elf_shared_library:806: entry: 0xb7ee5490 phdr: 0xb7ede034 phnum: 0x8 _dl_get_ready_to_run:808: Loading: (0xb7ede000) /home/msakamoto/reduced.linux/uclibc_test/runtime/lib/libc.so.0 INIT/FINI order and dependencies: lib: /home/msakamoto/reduced.linux/uclibc_test/runtime/lib/libc.so.0 has deps: _dl_get_ready_to_run:948: Beginning relocation fixups _dl_fixup:828: relocation processing: /home/msakamoto/reduced.linux/uclibc_test/runtime/lib/libc.so.0 ./ret1_dyn: symbol 'stdout': can't resolve symbol in lib '/home/msakamoto/reduced.linux/uclibc_test/runtime/lib/libc.so.0'. ||< どうしても "symbol 'stdout': can't resolve symbol in lib ..." になってしまう。 ローダの ld-uClibc-0.9.31.so は動いているらしい。でないと上記メッセージの出力まで到達しない。 で、 /uClibc-0.9.31/ldso/elfinterp.c の static int _dl_parse(...) の中の res = reloc_fnc(tpnt, scope, rpnt, symtab, strtab); これが 0 より 大きい場合に上記メッセージが出力される。0だと正常ルート、マイナス値だと "can't handle reloc type..."みたいなメッセージになる(筈)。 でreloc_fnc()とゆーのは _dl_parse() にコールバックとして渡された関数ポインタ。この中がおかしい・・・というか、まぁ自分のコンパイルオプションだのインストール先がおかしいだのでエラーになっちゃったのかも。 素直にBuildroot使えって? Buildroot使ってみたけれど、なんでtoolchainビルドするのにLinuxKernel落としてくるんだよ、ソレくらい自前で用意したの使えるようにしとけよ、というか全般的にあそこまでお仕着せになってしまうと、気持ち悪くて使いたくない。全部中身を理解した上でのショートカットとしてなら使えるけど、今回試しているのはまさに、中身を全部分解した上で、必要な部分だけ手動でつなぎあわせていく作業なのだから、せっかくの楽しみを奪うなよコンチキショーってところ。 ってか、Buildroot使わずに全部手動でuClibc, BusyBox使ってユーザーランド構築する記事もWeb上ではちらほらあるんだけど、Kernel-2.4.x時代の内容ばかりで、2011年4月時点の最新stableバージョンのuclibc, busyboxでは適用できない。 さらに言うと、色々原因を追い詰めていくにも、「今のmsakamoto-sfだからこそ」なんとか追い詰められないでもない程度で、というのはつまるところ、ELFのローダーであるとかELFファイルのフォーマットであるとかgccって結局binutilsのドライバだよね、でもどのcrtX.oをリンクするのかを知ってるのはgccになっちゃうから、だから面倒でもBuildrootはtoolchainでgccをビルドしなくちゃイカンよなぁ、いや単にCrossCompilerで必要だからというだけじゃなくてね、とか、gccのインクルードパスとかオプションとか調べるにも"-v"とか"--verbose"とか"--save-temps"とか知ってないと中身を分解できないし、そもそもMakefile.inとかそこら辺の周辺技術もひと通り頭に入れていないとそもそもビルドするときなにやってるのかが分からないよな、とかとか。 よーするにソースがオープンだということと、じゃぁそのソースの内容を理解して、Makefileによるビルドが何をどうコピーしてコンパイルしてリンクして移動したりinstallしてるのか、とか、さらにじゃぁビルドしたバイナリはどういうもので、Kernelによりどうやってメモリ上にロードされるのか、とか、トラブったときにobjdumpとかreadelfでELFファイルの中身を解析したり、gdbでマシン語レベルでデバッグしてCのソースと人力で対応付けられるのかとか、その辺のもろもろの胡乱な下準備なしに、トラブったときにその原因を調べられるわけねーだろ、的な感じなのですよ奥様!! ってゆーかld-uClibcのローダ、どうやってデバッグしてるんだ?ld-linux.soの場合は単体で実行できるからそこからgdbでデバッグできそうだが、ld-uClibcはstandaloneでの起動が出来ないからそのテクニックもおそらく使えない・・・。 やべ、詰まった・・・? glibcの動的リンクローダー: $ LD_DEBUG=all /lib/ld-linux.so.2 /bin/ls -l /lib/ld-linux.so.2 ... 6130: binding file /bin/ls [0] to /lib/libc.so.6 [0]: ... lrwxrwxrwx 1 root root 9 4月 2 18:18 /lib/ld-linux.so.2 -> ld-2.5.so 6130: symbol=exit; lookup in file=/bin/ls [0] ... uClibcの動的リンクローダー: $ LD_DEBUG=all ./ld-uClibc-0.9.31.so ../../ret1_dyn argc=2 argv=0xbfb3bea4 envp=0xbfb3beb0 ELF header=0x6f5000 First Dynamic section entry=0x6fceec Scanning DYNAMIC section Done scanning DYNAMIC section About to do library loader relocations Done relocating ldso; we can now use globals and make function calls! _dl_get_ready_to_run:317: Cool, ldso survived making function calls Standalone execution is not supported yet → Oooops!!!