この質問は古く、他の回答は古いです。 「雇用されたロシア人」の回答は非常に有益で有益ですが、ソースコードがある場合にのみ機能します.そうしないと、当時の代替手段は非常にトリッキーでした。幸いなことに、今日では、patchelf を使用して、この問題に対する簡単な解決策があります (彼の返信の 1 つでコメントされているように)。あなたがしなければならないことは:
$ ./patchelf --set-interpreter /path/to/newglibc/ld-linux.so.2 --set-rpath /path/to/newglibc/ myapp
その後、ファイルを実行するだけです:
$ ./myapp
chroot
する必要はありません ありがたいことに、バイナリを手動で編集することもできます。ただし、バイナリ ファイルが変更されるため、パッチを適用する前にバイナリをバックアップすることを忘れないでください。パッチを適用した後、古いパスをインタープリター/rpath に復元することはできません。機能しない場合は、実際に機能するパスが見つかるまでパッチを適用し続ける必要があります...まあ、試行錯誤のプロセスである必要はありません。たとえば、OP の例では、GLIBC_2.3
が必要でした 、そのため、 strings
を使用して、そのバージョンを提供するライブラリを簡単に見つけることができます :
$ strings /lib/i686/libc.so.6 | grep GLIBC_2.3
$ strings /path/to/newglib/libc.so.6 | grep GLIBC_2.3
理論的には、システム libc には必要なバージョンがないため、最初の grep は空になり、2 番目の grep はバージョンが myapp
であるため GLIBC_2.3 を出力するはずです。 を使用しているので、patchelf
できることがわかります そのパスを使用してバイナリを作成します。セグメンテーション違反が発生した場合は、最後にある注をお読みください。
Linuxでバイナリを実行しようとすると、バイナリはリンカー、次にライブラリをロードしようとします。それらはすべてパスおよび/または正しい場所にあるはずです。問題がリンカにあり、バイナリが探しているパスを知りたい場合は、次のコマンドで見つけることができます:
$ readelf -l myapp | grep interpreter
[Requesting program interpreter: /lib/ld-linux.so.2]
問題がライブラリにある場合、使用されているライブラリを提供するコマンドは次のとおりです:
$ readelf -d myapp | grep Shared
$ ldd myapp
これにより、バイナリに必要なライブラリが一覧表示されますが、OP の場合と同様に、既にエラーが発生しているため、問題のあるライブラリについては既にご存じでしょう。
「patchelf」は、これら 2 つの問題に関連して、プログラムを実行しようとしているときに遭遇する可能性のあるさまざまな問題に対して機能します。たとえば、次の場合:ELF file OS ABI invalid
、新しいローダー (--set-interpreter
コマンドの一部) ここで説明します。もう 1 つの例は、No such file or directory
を取得する問題です。 ここに例示されているように、そこにあり実行可能なファイルを実行すると。その特定のケースでは、OP にローダーへのリンクがありませんでしたが、あなたのケースではルート アクセス権がなく、リンクを作成できない可能性があります。新しいインタープリターを設定すると、問題が解決します。
洞察と解決策を提供してくれたEmployed RussianとMichael Pankovに感謝します!
注意 セグメンテーション違反の場合:myapp
の場合に該当する可能性があります いくつかのライブラリを使用しており、それらのほとんどは問題ありませんが、そうでないものもあります。それならあなたは patchelf
それを新しいディレクトリに移動すると、セグメンテーション違反が発生します。 patchelf
したとき バイナリの場合、いくつかのライブラリが元々別のパスにあったとしても、いくつかのライブラリのパスを変更します。以下の私の例を見てください:
$ ldd myapp
./myapp: /usr/lib/x86_64-linux-gnu/libstdc++.so.6: version `GLIBCXX_3.4.20' not found (required by ./myapp)
./myapp: /usr/lib/x86_64-linux-gnu/libstdc++.so.6: version `GLIBCXX_3.4.21' not found (required by ./myapp)
linux-vdso.so.1 => (0x00007fffb167c000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f9a9aad2000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f9a9a8ce000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f9a9a6af000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f9a9a3ab000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f9a99fe6000)
/lib64/ld-linux-x86-64.so.2 (0x00007f9a9adeb000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f9a99dcf000)
ほとんどのライブラリは /lib/x86_64-linux-gnu/
にあることに注意してください しかし、問題のあるもの (libstdc++.so.6
) は /usr/lib/x86_64-linux-gnu
にあります . myapp
をパッチした後 /path/to/mylibs
を指す 、セグメンテーション違反が発生しました。何らかの理由で、ライブラリはバイナリと完全に互換性がありません。 myapp
以降 /lib/x86_64-linux-gnu/
からコピーしました。 /path/to/mylibs2
へ 、そして libstdc++.so.6
もコピーしました /path/to/mylibs
から そこの。それから /path/to/mylibs2
にパッチルフしました 、および myapp
今すぐ動作します。バイナリが異なるライブラリを使用していて、バージョンも異なる場合、状況を修正できないことがあります。 :(しかし、可能であれば、ライブラリを混在させることが方法かもしれません。理想的ではありませんが、たぶん それが動作します。頑張ってください!
LD_PRELOAD を使用します。ライブラリを man lib ディレクトリの外に置き、次を実行します。
LD_PRELOAD='mylibc.so anotherlib.so' program
参照:ウィキペディアの記事
まず、動的にリンクされる各プログラムの最も重要な依存関係はリンカーです。そのため、すべてのライブラリはリンカーのバージョンと一致する必要があります。
簡単な例を見てみましょう:私はいくつかのプログラムを実行するニュースセット ubuntu システムを持っています (私の場合は D コンパイラ - ldc2)。古いCentOSで動かしたいのですが、glibcライブラリが古いので無理です。私は手に入れました
ldc2-1.5.0-linux-x86_64/bin/ldc2: /lib64/libc.so.6: version `GLIBC_2.15' not found (required by ldc2-1.5.0-linux-x86_64/bin/ldc2)
ldc2-1.5.0-linux-x86_64/bin/ldc2: /lib64/libc.so.6: version `GLIBC_2.14' not found (required by ldc2-1.5.0-linux-x86_64/bin/ldc2)
すべての依存関係を ubuntu から centos にコピーする必要があります。適切な方法は次のとおりです:
まず、すべての依存関係を確認しましょう:
ldd ldc2-1.5.0-linux-x86_64/bin/ldc2
linux-vdso.so.1 => (0x00007ffebad3f000)
librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007f965f597000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f965f378000)
libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007f965f15b000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f965ef57000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f965ec01000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f965e9ea000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f965e60a000)
/lib64/ld-linux-x86-64.so.2 (0x00007f965f79f000)
linux-vdso.so.1 は実際のライブラリではないため、気にする必要はありません。
/lib64/ld-linux-x86-64.so.2 はリンカーであり、Linux によって使用され、実行可能ファイルをすべての動的ライブラリとリンクします。
残りのファイルは実際のライブラリであり、リンカーと一緒にそれらすべてを centos のどこかにコピーする必要があります。
すべてのライブラリとリンカーが "/mylibs" ディレクトリにあると仮定しましょう。
ld-linux-x86-64.so.2 - すでに述べたように - はリンカです。動的ライブラリではなく、静的実行可能ファイルです。これを実行して、いくつかのパラメーター (--library-path など) があることも確認できます (後で説明します)。
Linux では、動的にリンクされたプログラムはその名前だけで起動される場合があります。例:
/bin/ldc2
Linux はそのようなプログラムを RAM にロードし、どのリンカが設定されているかをチェックします。通常、64 ビット システムでは、/lib64/ld-linux-x86-64.so.2 です (ファイル システムでは、実際の実行可能ファイルへのシンボリック リンクです)。その後、Linux はリンカーを実行し、動的ライブラリをロードします。 /P>
これを少し変更して、次のようなトリックを行うこともできます:
/mylibs/ld-linux-x86-64.so.2 /bin/ldc2
Linux に特定のリンカを強制的に使用させる方法です。
これで、前述のパラメーター --library-path に戻ることができます
/mylibs/ld-linux-x86-64.so.2 --library-path /mylibs /bin/ldc2
ldc2 を実行し、/mylibs から動的ライブラリをロードします。
これは、選択された (システムのデフォルトではない) ライブラリで実行可能ファイルを呼び出す方法です。
同じシステムに複数のバージョンの glibc が存在する可能性は十分にあります (私たちは毎日そうしています)。
ただし、glibc は多くの部分 (200 以上の共有ライブラリ) で構成されており、すべてが一致する必要があることを知っておく必要があります。そのうちの 1 つは ld-linux.so.2 で、しなければならない libc.so.6 と一致しない場合、表示されているエラーが表示されます。
ld-linux.so.2 への絶対パスは、リンク時に実行可能ファイルにハードコードされており、リンク後に簡単に変更することはできません (更新:patchelf で実行できます。以下のこの回答を参照してください)。
新しい glibc で動作する実行可能ファイルをビルドするには、次のようにします。
g++ main.o -o myapp ... \
-Wl,--rpath=/path/to/newglibc \
-Wl,--dynamic-linker=/path/to/newglibc/ld-linux.so.2
-rpath
リンカー オプションは、ランタイム ローダーが /path/to/newglibc
のライブラリを検索するようにします。 (そのため、LD_LIBRARY_PATH
を設定する必要はありません 実行前)、および -dynamic-linker
オプションは、正しい ld-linux.so.2
へのパスを「ベイク」します
myapp
を再リンクできない場合 アプリケーション (たとえば、サードパーティのバイナリであるため) のすべてが失われるわけではありませんが、よりトリッキーになります。 1 つの解決策は、適切な chroot
を設定することです。 そのための環境。もう 1 つの可能性は、rtldi とバイナリ エディターを使用することです。更新:または、patchelf を使用できます。