home ホーム search 検索 -  login ログイン  | reload edit datainfo version cmd icon diff delete  | help ヘルプ

日記/2009/11/28/gccでstaticリンクさせようと手動でldコマンド動かしたメモ (v1)

日記/2009/11/28/gccでstaticリンクさせようと手動でldコマンド動かしたメモ (v1)

日記 / 2009 / 11 / 28 / gccでstaticリンクさせようと手動でldコマンド動かしたメモ (v1)
id: 503 所有者: msakamoto-sf    作成日: 2009-11-28 16:36:46
カテゴリ: C言語 Linux UNIX 

西田亙氏の「GNU DEVELOPMENT TOOLS」を読み返していて、第6章の静的リンクのところで躓いた。GCCやbinutilsのバージョンが大分変わっているのもあったと思う。

自分の環境:CentOS 5.2

$ rpm -q --qf "%{NAME},%{VERSION}\n" gcc binutils
gcc,4.1.2
binutils,2.17.50.0.6

具体的には、hello.cをstaticリンクさせようとして手動でldコマンド実行したが、crt1.o, crti.o, hello.o, libc.a, libgcc.a, crtn.o だけだと未解決シンボルが出てリンクに失敗する。
結論を先に書くと、libgcc.aの後ろに libgcc_eh.a を置き、さらにその後ろに libc.a をもう一度指定することでリンクは成功する。


下準備:

$ cat hello.c
#include <stdio.h>

#define MESSAGE "Hello, World"

int main() {
    printf("%s\n", MESSAGE);
    return 123;
}

$ gcc -c -o hello.o hello.c ; echo $?
0
$ file hello.o
hello.o: ELF 32-bit LSB relocatable, Intel 80386, version 1 (SYSV), not stripped

リンク失敗:

$ ld \
> /usr/lib/crt1.o \
> /usr/lib/crti.o \
> hello.o \
> /usr/lib/libc.a \
> `gcc -print-libgcc-file-name` \
> /usr/lib/crtn.o
/usr/lib/libc.a(ioputs.o): In function `puts':
(.text+0x146): undefined reference to `_Unwind_Resume'
/usr/lib/libc.a(ioputs.o):(.eh_frame+0xde): undefined reference to `__gcc_personality_v0'
/usr/lib/libc.a(syslog.o): In function `openlog':
(.text+0x332): undefined reference to `_Unwind_Resume'
...
/usr/lib/libc.a(iogetdelim.o): In function `getdelim':
(.text+0x26c): undefined reference to `_Unwind_Resume'
/usr/lib/libc.a(iogetdelim.o):(.eh_frame+0xde): undefined reference to `__gcc_personality_v0'
$ echo $?
1

"_Unwind_Resume"というのと"__gcc_personality_v0"の2つのシンボルが見つからない。

試しに、普通にgccから"-static"オプションをつけて実行してみる。"-v"付で途中経過を表示させてみたところ:

/usr/libexec/gcc/i386-redhat-linux/4.1.2/collect2 -m elf_i386 
--hash-style=gnu 
-static 
-o hello_static 
/usr/lib/gcc/i386-redhat-linux/4.1.2/../../../crt1.o 
/usr/lib/gcc/i386-redhat-linux/4.1.2/../../../crti.o 
/usr/lib/gcc/i386-redhat-linux/4.1.2/crtbeginT.o 
-L/usr/lib/gcc/i386-redhat-linux/4.1.2 
-L/usr/lib/gcc/i386-redhat-linux/4.1.2 
-L/usr/lib/gcc/i386-redhat-linux/4.1.2/../../.. /tmp/ccxsa3ji.o 
--start-group 
-lgcc 
-lgcc_eh 
-lc 
--end-group 
/usr/lib/gcc/i386-redhat-linux/4.1.2/crtend.o 
/usr/lib/gcc/i386-redhat-linux/4.1.2/../../../crtn.o

なんとなく

--start-group 
-lgcc 
-lgcc_eh 
-lc 
--end-group 

というのが怪しそうな感じがする。とくに"-lgcc_eh"というのは何だろう。
というわけで、libgcc.aのあるディレクトリに潜ってみる。

$ gcc -print-libgcc-file-name
/usr/lib/gcc/i386-redhat-linux/4.1.2/libgcc.a
$ cd /usr/lib/gcc/i386-redhat-linux/4.1.2/
$ ls *.a
libgcc.a  libgcc_eh.a  ...

"libgcc_eh.a"のシンボルをgrepしてみる。

$ nm libgcc_eh.a | grep "_Unwind_Resume"
nm: unwind-sjlj.o: no symbols
00002160 T _Unwind_Resume
00002060 T _Unwind_Resume_or_Rethrow
$ nm libgcc_eh.a | grep "__gcc_personality_v0"
nm: unwind-sjlj.o: no symbols
00000220 T __gcc_personality_v0

このように、libgcc_eh.aの中に格納されていた。
というわけで、libgcc_eh.aを追加してみる。

$ ld \
> /usr/lib/crt1.o \
> /usr/lib/crti.o \
> hello.o \
> /usr/lib/libc.a \
> `gcc -print-libgcc-file-name` \
> `gcc -print-file-name=libgcc_eh.a` \
> /usr/lib/crtn.o
/usr/lib/gcc/i386-redhat-linux/4.1.2/libgcc_eh.a(unwind-dw2.o): In function `.L125':
(.text+0x958): undefined reference to `__stack_chk_fail_local'
/usr/lib/gcc/i386-redhat-linux/4.1.2/libgcc_eh.a(unwind-dw2.o): In function `__frame_state_for':
(.text+0xf26): undefined reference to `__stack_chk_fail_local'
/usr/lib/gcc/i386-redhat-linux/4.1.2/libgcc_eh.a(unwind-dw2.o): In function `.L413':
(.text+0x1896): undefined reference to `__stack_chk_fail_local'
/usr/lib/gcc/i386-redhat-linux/4.1.2/libgcc_eh.a(unwind-dw2.o): In function `_Unwind_Backtrace':
(.text+0x1ce1): undefined reference to `__stack_chk_fail_local'
/usr/lib/gcc/i386-redhat-linux/4.1.2/libgcc_eh.a(unwind-dw2.o): In function `_Unwind_RaiseException':
(.text+0x1f43): undefined reference to `__stack_chk_fail_local'
/usr/lib/gcc/i386-redhat-linux/4.1.2/libgcc_eh.a(unwind-dw2.o):(.text+0x2155): more undefined references to `__stack_chk_fail_local' follow
/usr/lib/gcc/i386-redhat-linux/4.1.2/libgcc_eh.a(unwind-dw2-fde-glibc.o): In function `_Unwind_Find_FDE':
(.text+0x1508): undefined reference to `dl_iterate_phdr'
$ echo $?
1

まだ終了ステータスが1、失敗である。先ほどまでのシンボル未定義は解消されたようだが、新たに次の2つが未定義となってしまった。

__stack_chk_fail_local
dl_iterate_phdr

ところが、いろいろnmで漁っていると "libc.a" の方のTextセクションに定義されている。

$ nm /usr/lib/libc.a 2>/dev/null | grep __stack_chk_fail_local
00000000 T __stack_chk_fail_local
$ nm /usr/lib/libc.a 2>/dev/null | grep dl_iterate_phdr
00000000 T __dl_iterate_phdr
000000f0 T dl_iterate_phdr

ldは引数で指定された順番でオブジェクトファイルを結合していく・・・筈だったような気がする・・・ので、試しにlibgcc_eh.aの後ろにもう一度libc.aを置いてみる。

$ ld \
> /usr/lib/crt1.o \
> /usr/lib/crti.o \
> hello.o \
> /usr/lib/libc.a \
> `gcc -print-libgcc-file-name` \
> `gcc -print-file-name=libgcc_eh.a` \
> /usr/lib/libc.a \
> /usr/lib/crtn.o
$ echo $?
0

今度は上手く行ったようである。

$ ./a.out
Hello, World
$ file a.out
a.out: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), \
for GNU/Linux 2.6.9, statically linked, for GNU/Linux 2.6.9, not stripped
$ ldd ./a.out
      not a dynamic executable

今回は練習なので「リンク成功、動いてオッケー」で済ませたが、それにしてもlibgcc_eh.aファイルが何物か?など疑問が尽きない。
他にも今回の試行錯誤の過程で、実は "/usr/lib/libc_nonshared.a" というのをリンクさせようとして、いったんはそれで上手く行きそうに見えたのだけれど結局 "libc.a" を後ろにもう一度置くだけでOKになった。で、この"libc_nonshared.a"というのも分からない。

ここら辺を突っ込もうと思ったらinfoやgcc/binutilsのソースコードまで踏み込まないと駄目なんだろうなーと思うけど、それは後の楽しみに取っておく事にする・・・というか調べるだけの気力がまだ無いのでスルーしただけです。根性無し。


プレーンテキスト形式でダウンロード
現在のバージョン : 1
更新者: msakamoto-sf
更新日: 2009-11-28 16:39:08
md5:c043bb0121f186f727407c770a7f33f4
sha1:a6c6e741b4b6680a86d8072f69f2b29524a8017e
コメント
コメントを投稿するにはログインして下さい。