Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/objective-c/27.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Linker 在Linux中ld到库而不包含版本信息_Linker_Ld - Fatal编程技术网

Linker 在Linux中ld到库而不包含版本信息

Linker 在Linux中ld到库而不包含版本信息,linker,ld,Linker,Ld,在编译C/C++程序时,是否有一种方法可以链接到Linux中的库导出,而不必嵌入版本信息 我正在Firefox中构建一个链接到libxul.so的共享对象(它是Firefox二进制扩展)。我想构建我的共享对象并链接到libxul.so,这样在运行时,加载程序就不会关心libxul.so是什么版本 现在,我的output.so文件具有以下依赖关系: readelf -V myext.so 0x0080: Version: 1 File: libxul.so Cnt: 1 0x0090:

在编译C/C++程序时,是否有一种方法可以链接到Linux中的库导出,而不必嵌入版本信息

我正在Firefox中构建一个链接到libxul.so的共享对象(它是Firefox二进制扩展)。我想构建我的共享对象并链接到libxul.so,这样在运行时,加载程序就不会关心libxul.so是什么版本

现在,我的output.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=文件提供以下错误:

/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将版本信息嵌入到我的库中?

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

一个小例子。考虑一个文件T.C,其中,主函数()从库函数和库源文件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 $清洁;制作 rm-f t.o libtt.so tt.o gcc-o libtt.so-shared-fPIC tt.c gcc-o 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 $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) $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=>未找到(0) libc.so.7=>/lib/libc.so.7(0x80081a000) 请注意,如果看不到libtt.so,链接器将失败,因为它不知道在哪里可以找到未解析的链接

尽管linker显示了一些奇怪的东西,但所有这些都适用于所述样式以外的名称:

$ 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) $gcc-o lybtt.so-共享-fPIC tt.c $gcc-o t t.c lybtt.so-Wl,-rpath=`pwd` 美元/吨 233 $ldd./t /t: lybtt.so(0x80081a000) libc.so.7=>/lib/libc.so.7(0x800a1b000) 如果您是library builder,则可以不使用版本来命名它,所有工具都会识别这一点。但这通常被认为是不好的风格,在推荐中被禁止。公共搜索路径中的所有库都声明有其名称中的版本,对于任何打包的非家用软件,严格建议这样做


对于你的问题,如果你真的需要自杀,你可以复制libxul,在其中更改soname,然后再次进入正确的搜索路径。但我怀疑这正是您想要的。

我能够根据需要构建库,而不需要版本信息

我最后做的是用适当的导出符号创建一个虚拟库——没有版本(或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
而且它可以按需要运行


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

当您链接libxul24,然后尝试运行libxul26时,某些函数的API和/或ABI将发生更改,这就是为什么不允许您这样做的原因。这是一个完整性检查:您希望从一个库中使用的函数在另一个库中不一定相同(xul26本质上是相同的)。@mirabilos即使没有任何更改,构建工具也可能自动分配版本号。这是因为库版本与整个产品版本相同。我也在一些工具(如gettext)中看到了这一点,在这些工具中,库版本和功能更改之间没有关联。但只要不能保证API不会改变,就不能依赖其他库版本的安全加载…@Netch:当然,但生成XUL库的不是他。在这种情况下,我相信它是一个产品内部库,上游甚至不假装关心API/ABI的稳定性(不知道一开始是否应该链接到它)。因此,我认为这是M*zilla人的深思熟虑。Mozilla还实施了其他版本兼容性检查(即扩展包中的minVersion和maxVersion设置),这些检查比链接版本号更细粒度、更灵活。在任何情况下,这都是Linux的破坏者,因为同样的代码在Windows和Mac中都可以正常工作。