web-dev-qa-db-ja.com

相対パスで共有ライブラリにリンクする方法は?

ld.so(8)のmanページ では、

ライブラリの依存関係を解決するとき、ダイナミックリンカーはまず各依存関係文字列を検査してスラッシュが含まれているかどうかを確認します(これは、スラッシュを含むライブラリパス名がリンク時に指定された場合に発生します)。スラッシュが見つかった場合、依存文字列は(相対または絶対)パス名として解釈され、ライブラリはそのパス名を使用してロードされます。

スラッシュ付きのパスを持つライブラリに対してgccをリンクするにはどうすればよいですか?私は-lを試してみましたが、それはパス引数自体ではなく、さまざまなパスの検索に使用するライブラリ名でのみ機能するようです。

次の質問:この方法で相対パスにリンクする場合、相対パスは何ですか(たとえば、バイナリを含むディレクトリまたは実行時の作業ディレクトリ)?

検索時に見つけたすべてのリンクガイドは、RPATHLD_LIBRARY_PATHRUNPATHを使用して議論しています。 RPATHは非推奨であり、ほとんどの議論ではLD_LIBRARY_PATHの使用を推奨していません。 $Originで始まるパスを含むRUNPATHは、相対パスへのリンクを許可しますが、LD_LIBRARY_PATHによってオーバーライドされる可能性があるため、少し脆弱です。相対パスの方が堅牢であるかどうかを知りたいと思っていました(これについて説明していることが見つからないので、おそらくパスがランタイムディレクトリからの相対パスであるため、そうではないと思います)。

1
ws_e_c421

(今のところ)gccまたは質問のリンク部分を無視し、代わりにLinuxシステムでバイナリを patchelf で変更する場合

$ ldd hello
        linux-vdso.so.1 =>  (0x00007ffd35584000)
        libhello.so.1 => not found
        libc.so.6 => /lib64/libc.so.6 (0x00007f02e4f6f000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f02e533c000)
$ patchelf --remove-needed libhello.so.1 hello
$ patchelf --add-needed ./libhello.so.1 hello
$ ldd hello
        linux-vdso.so.1 =>  (0x00007ffdb74fc000)
        ./libhello.so.1 => not found
        libc.so.6 => /lib64/libc.so.6 (0x00007f2ad5c28000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f2ad5ff5000)

これで、相対パスライブラリを含むバイナリが作成されました。これには、libhello.so.1ファイルが存在します

$ cd english/
$ ../hello
hello, world
$ cd ../lojban/
$ ../hello
coi rodo

パスがプロセスの作業ディレクトリからの相対パスであることがわかります。これにより、あらゆる種類の問題、特に security が開かれます。 問題 。おそらく、ライブラリのさまざまなバージョンをテストするなど、生産的な使用法があるかもしれません。相対作業ディレクトリを複雑にすることなく、2つの異なるバイナリをコンパイルするか、必要なライブラリでpatchelfをコンパイルする方が簡単です。

ステップをコンパイルする

libhelloにはhelloworld呼び出しのみがあります

$ cat libhello.c
#include <stdio.h>
void helloworld(void)
{
    printf("coi rodo\n");
}

経由でコンパイルされました

CFLAGS="-fPIC" make libhello.o
gcc -shared -fPIC -Wl,-soname,libhello.so.1 -o libhello.so.1.0.0 libhello.o -lc
ln -s libhello.so.1.0.0 libhello.so.1
ln -s libhello.so.1.0.0 libhello.so

hello呼び出しを行うhelloworldは、

$ cat hello.c
int main(void)
{
    helloworld();
    return 0;
}
$ CFLAGS="-lhello -L`pwd`/english" make hello

patchelfなし

後から、相対ディレクトリパスを使用するようにgccコマンドを変更します。

$ gcc -shared -fPIC -Wl,-soname,./libhello.so.1 -o libhello.so.1.0.0 libhello.o -lc
$ cd ..
$ rm hello
$ CFLAGS="-lhello -L`pwd`/lojban" make hello
$ ldd hello | grep hello
        ./libhello.so.1 => not found
$ english
$ ../hello
hello, world

通常の方法でライブラリをコンパイルしてから、必要に応じてpatchelfを使用してバイナリをいじるほうが賢明でしょう。

6
thrig

リンカーにオプションを渡すことによってこれを行います。たとえば、ncursesのビルドディレクトリ(インストールされていないライブラリに依存する)からテストプログラムを実行するには、次のようなオプションを使用します(gccコマンドラインで)。

-Wl,-rpath,../lib

これは相対パス名を埋め込みます。同じオプションで絶対パス名を埋め込むことができます。

-Wl,-rpath,../lib:/usr/local/ncurses6/lib

これはローカルテストには役立ちますが、さまざまな理由でシステムにインストールする場合には役立ちません。 Debianにはそれに対するポリシーがあります。1990年代にさかのぼりますが、首尾一貫した議論はまれです(たとえば、一部の情報を収集する RPATHの問題 を参照)。

1
Thomas Dickey