#navi_header|技術| [[949]] でも注記していますが、x86(32bit)PC環境でBuildrootを使わずに構築した uClibc を静的リンクしたバイナリの場合、Segmentation Fault で異常終了してしまう現象が確認されています。 自分の環境では、 DODEBUG オプションを有効化してuClibcおよびリンク先のアプリケーションをリビルドするとこの問題を回避できました。 原因までは特定できていませんが、gdbでデバッグして気になった箇所をメモしておきます。 環境は [[949]] と同一です。 #more|| * Segmentation Fault するバイナリのデバッグ #pre||> $ gdb ./ret1_static GNU gdb (GDB) Red Hat Enterprise Linux (7.0.1-23.el5_5.2) Copyright (C) 2009 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "i386-redhat-linux-gnu". For bug reporting instructions, please see: ... Reading symbols from /home/msakamoto/reduced.linux/uclibc_test2/ret1_static...(no debugging symbols found)...done. (gdb) run Starting program: /home/msakamoto/reduced.linux/uclibc_test2/ret1_static Program received signal SIGSEGV, Segmentation fault. 0x00000000 in ?? () (gdb) bt #0 0x00000000 in ?? () #1 0x0804819e in __uClibc_init () #2 0x0804817f in __uClibc_init () #3 0x0804823f in __uClibc_main () #4 0x00000000 in ?? () ||< __uClibc_init() というかなり初期段階の関数中で、EIPが0番地をさしてSIGSEGVしたことが分かります。 __uClibc_init()の逆アセンブラ結果、スタック、関連箇所の逆アセンブラ結果を添えておきます: #pre||> (gdb) disas 0x0804819e Dump of assembler code for function __uClibc_init: 0x08048179 <__uClibc_init+0>: push %ebx 0x0804817a <__uClibc_init+1>: call 0x8048362 <__i686.get_pc_thunk.bx> 0x0804817f <__uClibc_init+6>: add $0x1729,%ebx 0x08048185 <__uClibc_init+12>: sub $0x8,%esp 0x08048188 <__uClibc_init+15>: mov -0x8(%ebx),%eax 0x0804818e <__uClibc_init+21>: cmpl $0x0,(%eax) 0x08048191 <__uClibc_init+24>: jne 0x804819e <__uClibc_init+37> 0x08048193 <__uClibc_init+26>: movl $0x1000,(%eax) 0x08048199 <__uClibc_init+32>: call 0x0 ## <<<<< ここで落ちてるっぽい。 0x0804819e <__uClibc_init+37>: pop %eax 0x0804819f <__uClibc_init+38>: pop %edx 0x080481a0 <__uClibc_init+39>: pop %ebx 0x080481a1 <__uClibc_init+40>: ret End of assembler dump. (gdb) x/16x $esp 0xbfffe9bc: 0x0804819e 0x00000000 0x0804817f 0x080498a8 0xbfffe9cc: 0x0804823f 0x00000000 0x00000000 0x00000000 0xbfffe9dc: 0x00000000 0x00000000 0x00000000 0x00000000 0xbfffe9ec: 0x00000000 0x00000000 0x00000000 0x00000000 (gdb) disas 0x8048362 Dump of assembler code for function __i686.get_pc_thunk.bx: 0x08048362 <__i686.get_pc_thunk.bx+0>: mov (%esp),%ebx 0x08048365 <__i686.get_pc_thunk.bx+3>: ret 0x08048366 <__i686.get_pc_thunk.bx+4>: nop 0x08048367 <__i686.get_pc_thunk.bx+5>: nop End of assembler dump. ||< * DODEBUGを有効化して静的リンクしたバイナリの "__uClibc_init()" こちらは正常に動作したバイナリ(=自分の環境ではDODEBUGを有効化してリビルド)の __uClibc_init() です: #pre||> (gdb) disas Dump of assembler code for function __uClibc_init: 0x08048195 <__uClibc_init+0>: push %ebp 0x08048196 <__uClibc_init+1>: mov %esp,%ebp 0x08048198 <__uClibc_init+3>: push %ebx 0x08048199 <__uClibc_init+4>: sub $0x4,%esp 0x0804819c <__uClibc_init+7>: call 0x80489e6 <__i686.get_pc_thunk.bx> 0x080481a1 <__uClibc_init+12>: add $0x26cb,%ebx 0x080481a7 <__uClibc_init+18>: mov -0x8(%ebx),%eax 0x080481ad <__uClibc_init+24>: mov (%eax),%eax 0x080481af <__uClibc_init+26>: test %eax,%eax 0x080481b1 <__uClibc_init+28>: jne 0x80481ce <__uClibc_init+57> 0x080481b3 <__uClibc_init+30>: mov -0x8(%ebx),%eax 0x080481b9 <__uClibc_init+36>: movl $0x1000,(%eax) 0x080481bf <__uClibc_init+42>: lea -0x804a86c(%ebx),%eax 0x080481c5 <__uClibc_init+48>: test %eax,%eax 0x080481c7 <__uClibc_init+50>: je 0x80481ce <__uClibc_init+57> 0x080481c9 <__uClibc_init+52>: call 0x0 0x080481ce <__uClibc_init+57>: add $0x4,%esp 0x080481d1 <__uClibc_init+60>: pop %ebx 0x080481d2 <__uClibc_init+61>: pop %ebp 0x080481d3 <__uClibc_init+62>: ret End of assembler dump. ||< * "__uClibc_init()" のソースコード "defconfig" 時にundefとなるブロックを除去したコードです。 libc/misc/internals/__uClibc_main.c: #pre||> extern void weak_function _stdio_init(void) attribute_hidden; ... extern void __uClibc_init(void); libc_hidden_proto(__uClibc_init) void __uClibc_init(void) { /* Don't recurse */ if (__pagesize) return; /* Setup an initial value. This may not be perfect, but is * better than malloc using __pagesize=0 for atexit, ctors, etc. */ __pagesize = PAGE_SIZE; /* * Initialize stdio here. In the static library case, this will * be bypassed if not needed because of the weak alias above. * Thus we get a nice size savings because the stdio functions * won't be pulled into the final static binary unless used. */ if (likely(_stdio_init != NULL)) _stdio_init(); } libc_hidden_def(__uClibc_init) ||< DODEBUG有効化したバイナリの逆アセンブラ結果と見比べてみると、Cソースとアセンブラがほぼ1対1に対応付けられると思います。 * "DODEBUG"の影響 "DODEBUG"でgrepしてみると、Rules.makファイル内でコンパイルオプションを調整していることが分かります。 Rules.mak : ... ifeq ($(DODEBUG),y) CFLAGS += -O0 -g3 else CFLAGS += $(OPTIMIZATION) endif "DODEBUG"を有効にすると最適化を無効にし(-O0)、最大限のデバッグ情報を埋め込むよう(-g3)指示しています。 逆に "DODEBUG"が無効の場合、可能な限りの最適化オプションを盛り込むようになります(OPTIMIZATIONでgrepしてみて下さい)。 サイズの違いを見てみます。 DODEBUG=y #DOSTRIP is not set → $ wc -c dev/usr/lib/libc.a 43388656 dev/usr/lib/libc.a $ wc -c dev/usr/lib/uclibc_nonshared.a 60030 dev/usr/lib/uclibc_nonshared.a "libc.a"が実に40MBを超えるサイズになってしまっています。これがまるごと静的リンクされるわけではなく、libc.a内から必要に応じてオブジェクトファイルが抽出されてリンクされるわけですが、例えばhelloworldでも $ wc -c helloworld_static 3376190 helloworld_static と3MBを超えてしまいます。 DODEBUGを無効化した場合: # DODEBUG is not set # DOSTRIP is not set → $ wc -c dev/usr/lib/libc.a 1078172 dev/usr/lib/libc.a $ wc -c dev/usr/lib/uclibc_nonshared.a 1330 dev/usr/lib/uclibc_nonshared.a stripしてませんので1MBを超えてしまいますが、大分小さくなりました。 とはいえ、自分の環境ですとこれで静的リンクするとSegmentation Faultしてしまい使い物になりません・・・( ;∀;)。 * 途中経過報告 まだ原因を特定出来ていないので「途中」の経過報告となります。 現段階で考えられる原因は2つあります。 1.最適化オプションの影響。 DODEBUGを無効化した場合、デバッグ情報を埋め込まないだけでなく、可能な限りの最適化オプションを盛りこんでコンパイルされます。この影響で _uClibc_init() の流れがおかしくなっているのかもしれません。 2.リンクするオブジェクトやその順番が間違っている。 DODEBUGを有効にした場合も動作するのは「たまたま」上手く動いただけで、そもそもリンクするcrtX.oやlibc.a、およびその順番が間違っている可能性もあります。たまたまリンクは上手く出来たが、weakシンボル絡みで実は裏側では・・・というケースが考えられます。 今のところ頭に浮かんでいる原因はこの2つです。 ただ現実問題として、コンパクトなLinuxシステムの構築でuClibcを使うとき、静的リンクを使う状況はあまり無いと思います。大抵はファイルシステムの容量がシビアに制限された中での開発となりますので、uClibcを導入するとなれば最終的には動的リンクを使うことになると思います。 したがって、静的リンクでSegmentation Faultしてしまう問題は現実的には無視してしまっても良いのかもしれません。 #navi_footer|技術|