5分でわかる!共有ライブラリまとめ

どうも、知識があいまいなので、若干まとめておく。間違ってたら、適当に指摘していただけると助かります。


Windowsの場合。
Windowsでややこしいのは、リンクに使うオブジェクト(COFFとか)と、.exe、.dll(PE)のオブジェクトの形式が違う点。(ヘッダが違うだけ?中身一緒?)
共有ライブラリを直接リンクできない。(ような気がする)
なので、.dll→.def→.lib てな感じで、一旦DLLがエクスポートしてるシンボルを取得したあと、それをもとにオブジェクトファイル作って、そのオブジェクトをリンクする。
.libの形式が謎。コンパイラ依存かも。
tccは直接.defを読んでるような気がするんだけど、どこで処理してるかわかんない。あとで調べる(←未来)
実行時のリンクは誰がやってるかわからないという。あとで調べない。
実行時の関数呼び出しにDS:とかが見えたので、セグメントを使ったマジックとか使ってるかも。
追記:まったくマジックとかじゃないDSってふつーにデータセグメントじゃないか。

参考になるかも→http://wiki.osdev.info/?PE



Linuxの場合。
ELFは色々資料あるので略。(Windowsのそこらへんの知識は、アングラっぽい扱いになってるのかも)
.soのコピー方法とかについて考える。

昨日までの僕は、libxx.soをコピーすれば終わりだと思ってた。しかし、そうじゃなかった。

libxx.soは、libxx.so.2とかのバージョン番号が付いた実体へのシンボリックリンクになってることが多い。

~/test/so $ cp /usr/lib/libSDL.so .
~/test/so $ ls
a.out  hello.c  hello.c~  libSDL.so  sdl.c  so.c  so.so
~/test/so $ gcc sdl.c libSDL.so
~/test/so $ ls
a.out  hello.c  hello.c~  libSDL.so  sdl.c  so.c  so.so
~/test/so $ LD_LIBRARY_PATH=. ldd a.out 
	linux-gate.so.1 =>  (0x003a9000)
	libSDL-1.2.so.0 => /usr/lib/libSDL-1.2.so.0 (0x0045c000) ## 意図してないよ!
	libc.so.6 => /lib/libc.so.6 (0x0087e000)
	libm.so.6 => /lib/libm.so.6 (0x00d28000)
	libdl.so.2 => /lib/libdl.so.2 (0x00bab000)
	libpthread.so.0 => /lib/libpthread.so.0 (0x00be0000)
	/lib/ld-linux.so.2 (0x003aa000)

なんで、シンボリックリンク辿っていかないといけない…ように見えて、それでも無理。

~/test/so $ ls -l /usr/lib/libSDL*.so*
lrwxrwxrwx   1 root     root       15  6月 11 12:16 /usr/lib/libSDL-1.1.so.0 -> libSDL-1.2.so.0
lrwxrwxrwx   1 root     root       19  6月 11 12:16 /usr/lib/libSDL-1.2.so.0 -> libSDL-1.2.so.0.7.3
-rwxr-xr-x   1 root     root     445560  5月 17 15:17 /usr/lib/libSDL-1.2.so.0.7.3
lrwxrwxrwx   1 root     root       19  6月 11 12:17 /usr/lib/libSDL.so -> libSDL-1.2.so.0.7.3

リンクを辿っていくと、libSDL-1.2.so.0.7.3がコピーされる…けど、

~/test/so $ readelf -d /usr/lib/libSDL.so 

Dynamic section at offset 0x6b460 contains 25 entries:
 タグ        タイプ                       名前/値
 0x00000001 (NEEDED)                     共有ライブラリ: [libm.so.6]
 0x00000001 (NEEDED)                     共有ライブラリ: [libdl.so.2]
 0x00000001 (NEEDED)                     共有ライブラリ: [libpthread.so.0]
 0x00000001 (NEEDED)                     共有ライブラリ: [libc.so.6]
 0x0000000e (SONAME)                     ライブラリの soname: [libSDL-1.2.so.0]

名前が、libSDL-1.2.so.0になってるので、libSDL-1.2.so.0.7.3という名前になってもらっては困る…


となると、objdumpとか使ってsoname見ないといけないような気がするんだけど…

とりあえず美しそうな解決案として、*.laを参照する方法を考える。
autoconf、automakeとかの作法にのっとってるやつは、libxx.laというファイルができてるので、それを参照する。というのがアリかもしれない。

# libSDL.la - a libtool library file
# Generated by ltmain.sh - GNU libtool 1.5.22 (1.1220.2.365 2005/12/18 22:14:06)
#
# Please DO NOT delete this file!
# It is necessary for linking the library.

# The name that we can dlopen(3).
dlname='libSDL-1.2.so.0'
#!/bin/sh
function get_soname() {
	obj=$1
	la=`echo $obj | sed -e 's|.so|.la|g'`

	if ! test -r $la; then return 1; fi

	soname=`grep '^dlname=' $la | sed "s|^dlname='\\(.*\\)'$|\\\\1|g"`

	return 0
}

get_soname /usr/lib/libSDL.so
if test $? -eq 0; then
    echo $soname 
fi


しかし、autoconf対応してないやつは、どうやってやればいいんだ。
そういうのはカンとかに頼るしかないのかも。

  1. *.la調べる
  2. .soがシンボリックリンクじゃなかったらそれコピー
  3. .soがシンボリックリンクだったら…しかたないので、シンボリックリンク辿ってコピー
  4. それで対応できないものは、objdumpしてSONAME拾ってくる

かなぁ…

続く。


続かない。