ld到Linux没有版本信息的库

时间:2013-12-21 17:57:10

标签: linker ld

在编译C / C ++程序时,有没有办法在Linux中链接到库导出而没有嵌入版本信息?

我正在构建一个链接到Firefox中的libxul.so的共享对象(它是一个Firefox二进制扩展)。我想构建我的共享对象并链接到libxul.so,以便在运行时,加载器不关心libxul.so的版本。

现在,我的输出.so文件具有以下依赖项:

readelf -V myext.so
  0x0080: Version: 1  File: libxul.so  Cnt: 1
  0x0090:   Name: xul24.0  Flags: none  Version: 9

(请注意,它取决于版本'xul24.0')

导出的功能在Firefox版本之间不会更改。所以,我想删除这个版本说明。

尝试加载到Firefox 26时,LD_DEBUG = file提供以下错误:

/usr/lib/firefox/libxul.so: error: version lookup error:
version `xul24.0' not found (required by /.../myext.so) (fatal)

对于Firefox 26版本的libxul.so,版本为'xul26'

那么,我怎样才能阻止ld将版本信息嵌入到我的库中?

2 个答案:

答案 0 :(得分:1)

我能够根据需要构建库,没有版本信息。

我最终做的是创建一个带有相应导出符号的虚拟库 - 没有版本(或soname)信息 - 并在编译和链接我的库时链接到该虚拟库。在运行时,加载程序根据版本控制问题加载真实库(libxul.so)而不会失败,因为我的库不包含真实库的版本信息。为了找出我需要的导出符号,我首先链接到真正的libxul.so,然后使用readelf --dyn-syms来确定实际需要的符号。

当ARCH为32或64(对于32位或64位编译)时: gcc -o $ARCH/libxul.so -fPIC -shared -DM$ARCH -m$ARCH xulstubs.c

xulstubs.c:

/*
 2: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND NS_Realloc@xul26 (2)
 3: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND NS_UTF16ToCString@xul26 (2)
 7: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND NS_CStringCloneData@xul26 (2)
13: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND NS_GetMemoryManager@xul26 (2)
...
 */
void NS_Realloc() {}
void NS_UTF16ToCString() {}
void NS_CStringCloneData() {}
void NS_GetMemoryManager() {}
/* ... etc. ... */

现在,我库中导入的符号没有版本附件:

23: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND NS_Realloc
29: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND NS_UTF16ToCString
33: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND NS_CStringCloneData
37: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND NS_GetMemoryManager

并按需运行。

我仍然想要一个更“优雅”的解决方案,一个不需要创建虚拟库的解决方案。但是,如果这是使用标准工具链的唯一解决方法,我可以忍受它。

答案 1 :(得分:0)

如果考虑使用最广泛的GNU工具链,您可以加载任何没有“lib”前缀和版本后缀的共享库,但只能直接使用代码中的dlopen()。在二进制文件启动或其他库加载期间自动加载将不起作用,因为链接器将找到库文件,从库头读取其“soname”和“rpath”属性并应用它们以在构建的目标加载期间查找库。 Soname对于链接器比库文件名更重要。更重要的是,在某些系统中,ldconfig可以重命名公共搜索路径中的库以匹配内部记录的soname(我在Linux上看到过这种情况)。

一个小例子。考虑一个文件t.c,其中main()打印一个来自库函数的值和一个库源文件tt.c,其中函数返回一个常量。制作它们:

$ make clean; make
rm -f t t.o libtt.so tt.o
gcc -o libtt.so -shared -fPIC tt.c
gcc -o t t.c -L. -ltt

使用这些命令,。/ t将失败,因为libtt.so不在公共搜索路径中,因此需要LD_LIBRARY_PATH来启动它。但我们可以解决这个问题:

$ gcc -o libtt.so -shared -fPIC tt.c
$ gcc -o t t.c -L. -ltt -Wl,-rpath=`pwd`
$ ldd ./t
./t:
        libtt.so => /var2/homes/netch/prog/tests/soname/libtt.so (0x80081a000)
        libc.so.7 => /lib/libc.so.7 (0x800a1b000)

但是,如果我在构建期间请求另一个库名称,搜索将失败:

$ gcc -o libtt.so -shared -fPIC tt.c -Wl,-soname=libtt2.so
$ gcc -o t t.c -L. -ltt -Wl,-rpath=`pwd`
$ ldd ./t
./t:
        libtt2.so => not found (0)
        libc.so.7 => /lib/libc.so.7 (0x80081a000)

请注意,如果没有看到libtt.so,链接器将会失败,因为它不知道在哪里可以找到未解析的链接。

所有这些都适用于其他风格的名称,尽管链接器显示了一些奇怪的东西:

$ gcc -o lybtt.so -shared -fPIC tt.c
$ gcc -o t t.c lybtt.so -Wl,-rpath=`pwd`
$ ./t
233
$ ldd ./t
./t:
        lybtt.so (0x80081a000)
        libc.so.7 => /lib/libc.so.7 (0x800a1b000)

如果您是库构建器,则可以在没有版本的情况下命名它,所有工具都会识别它。但这通常被认为是不好的风格,并在建议中被禁止。公共搜索路径中的所有库都声明其名称中包含版本,严格建议用于任何非家用软件包装。

对于你的问题,如果你真的需要徒步射击,你可以复制libxul,更改其中的soname并再次进入正确的搜索路径。但我怀疑这就是你想要的。