GNU/Linux >> Linux の 問題 >  >> Linux

.so ファイル内の古いシンボル バージョンへのリンク

次の実用的なソリューションを見つけました。最初にファイル memcpy.c を作成します:

#include <string.h>

/* some systems do not have newest [email protected]@GLIBC_2.14 - stay with old good one */
asm (".symver memcpy, [email protected]_2.2.5");

void *__wrap_memcpy(void *dest, const void *src, size_t n)
{
    return memcpy(dest, src, n);
}

このファイルをコンパイルするために追加の CFLAGS は必要ありません。次に、プログラムを -Wl,--wrap=memcpy でリンクします .


同様の問題がありました。 RHEL 7.1 にいくつかの Oracle コンポーネントをインストールしようとしたところ、次のようになりました:

$ gcc -o /some/oracle/bin/foo .... -L/some/oracle/lib ... 
/some/oracle/lib/libfoo.so: undefined reference to `[email protected]_2.14'

(私の) RHEL の glibc は [email protected]_2.2.5 しか定義していないようです:

$ readelf -Ws /usr/lib/x86_64-redhat-linux6E/lib64/libc_real.so | fgrep [email protected]
   367: 000000000001bfe0    16 FUNC    GLOBAL DEFAULT    8 [email protected]@GLIBC_2.2.5
  1166: 0000000000019250    16 FUNC    WEAK   DEFAULT    8 [email protected]@GLIBC_2.2.5

そこで、次のように、最初にラップせずに memcpy.c ファイルを作成することで、この問題を回避することができました:

#include <string.h>
asm (".symver old_memcpy, [email protected]_2.2.5");       // hook old_memcpy as [email protected]
void *old_memcpy(void *, const void *, size_t );
void *memcpy(void *dest, const void *src, size_t n)   // then export memcpy
{
    return old_memcpy(dest, src, n);
}

そして、memcpy を [email protected]_2.14 としてエクスポートする memcpy.map ファイル:

GLIBC_2.14 {
   memcpy;
};

次に、自分の memcpy.c を次のような共有ライブラリにコンパイルしました:

$ gcc -shared -fPIC -c memcpy.c
$ gcc -shared -fPIC -Wl,--version-script memcpy.map -o libmemcpy-2.14.so memcpy.o -lc

、 libmemcpy-2.14.so を /some/oracle/lib に移動し (私のリンクでは -L 引数が指す)、

で再度リンクしました
$ gcc -o /some/oracle/bin/foo .... -L/some/oracle/lib ... /some/oracle/lib/libmemcpy-2.14.so -lfoo ...

(これはエラーなしでコンパイルされ、次の方法で検証されました:

$ ldd /some/oracle/bin/foo
    linux-vdso.so.1 =>  (0x00007fff9f3fe000)
    /some/oracle/lib/libmemcpy-2.14.so (0x00007f963a63e000)
    libdl.so.2 => /lib64/libdl.so.2 (0x00007f963a428000)
    libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f963a20c000)
    librt.so.1 => /lib64/librt.so.1 (0x00007f963a003000)
    libc.so.6 => /lib64/libc.so.6 (0x00007f9639c42000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f963aa5b000)

これは私にとってはうまくいきました。


同様の問題がありました。私たちが使用するサードパーティのライブラリには、古い [email protected]_2.2.5 が必要です .私の解決策は、@anight が投稿した拡張アプローチです。

memcpyもワープ コマンドですが、@anight が投稿した解決策がうまくいかなかったため、少し異なるアプローチを使用する必要がありました。

memcpy_wrap.c:

#include <stddef.h>
#include <string.h>

asm (".symver wrap_memcpy, [email protected]_2.2.5");
void *wrap_memcpy(void *dest, const void *src, size_t n) {
  return memcpy(dest, src, n);
}

memcpy_wrap.map:

GLIBC_2.2.5 {
   memcpy;
};

ラッパーをビルドします:

gcc -c memcpy_wrap.c -o memcpy_wrap.o

最後に、プログラムをリンクするときに

を追加します
  • -Wl,--version-script memcpy_wrap.map
  • memcpy_wrap.o

最終的には次のようになります:

g++ <some flags> -Wl,--version-script memcpy_wrap.map <some .o files> memcpy_wrap.o <some libs>

memcpy を静的にリンクするだけです - memcpy.o を libc.a ar x /path/to/libc.a memcpy.o から引き出します (どのバージョンでも - memcpy はほぼスタンドアロンの機能です)、最終的なリンクに含めます。プロジェクトがオープンソースではなく一般に配布されている場合、静的リンクはライセンスの問題を複雑にする可能性があることに注意してください。

別の方法として、memcpy を自分で実装することもできますが、glibc で手動で調整されたアセンブリ バージョンの方が効率的である可能性があります。

[email protected]_2.2.5 は memmove にマップされていることに注意してください (古いバージョンの memcpy は一貫して予測可能な方向にコピーされたため、memmove を使用する必要があるときに誤用されることがありました)。これがバージョン バンプの唯一の理由です。 - この特定のケースでは、コード内の memcpy を memmove に単純に置き換えることができます。

または、静的リンクに移動するか、ネットワーク上のすべてのシステムがビルド マシンと同じかそれ以上のバージョンであることを確認できます。


Linux
  1. テキストファイルのすべての行に対してコマンドを実行する

  2. 古いバージョンの libstdc++ とのリンク

  3. cp -L 対 cp -H

  1. 古いバージョンの libc にリンクして、より広いアプリケーション カバレッジを提供する

  2. リンクエラーに対する再配置R_X86_64_32S

  3. 古いバージョンの共有ライブラリにリンクするにはどうすればよいですか

  1. insmod 後のシンボル symbol_name のバージョンに関する不一致

  2. Fedora に古いバージョンの gcc をインストールする方法

  3. 30 日以上経過したファイルを安全に削除する