我试图创建一个共享库libfunc.so
,它依赖于另一个共享库(特别是libuv.so
,但我认为特定的库与问题无关)。即,当我运行ldd libfunc.so
时,我想看到从libfunc.so
到libuv.so
的依赖关系。
下面是我想编译成libfunc.so
的代码:
#include <uv.h>
int func() {
uv_timespec64_t now;
uv_clock_gettime(UV_CLOCK_REALTIME, &now);
return 0;
}
字符串
......我这样编译它:
$ cc --version && cc -fpic -ggdb -Wall -c -o func.o func.c
cc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0
Copyright (C) 2021 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$ cc -shared -o libfunc.so func.o -fpic -ggdb -Wall -luv
$
型
.当我运行ldd libfunc.so
时,我没有看到对libuv.so
的期望依赖:
$ ldd ./libfunc.so
linux-vdso.so.1 (0x00007fff827ae000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f14b291e000)
/lib64/ld-linux-x86-64.so.2 (0x00007f14b2b54000)
$
型
.也就是说,我想看到的东西沿着沿着:
linux-vdso.so.1 (0x00007ffcbbdca000)
libuv.so.1 => /lib/x86_64-linux-gnu/libuv.so.1 (0x00007f781b25c000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f781b034000)
/lib64/ld-linux-x86-64.so.2 (0x00007f781b2a2000)
型
我的问题是:为什么libuv.so
上的依赖项没有显示出来,我需要做什么来创建这个依赖项?
我的理解可能是基本的和不完整的,但我认为创建依赖关系是沿着1)编写代码从(共享)库调用函数,2)编译目标代码,3)从目标代码创建(共享)库,同时与定义缺少符号的库链接。
检查libfunc.so
,我确实看到libuv
符号的预期未定义符号:
$ nm libfunc.so | grep U
0000000000002000 r __GNU_EH_FRAME_HDR
U __stack_chk_fail@GLIBC_2.4
U uv_clock_gettime
$
型
在某些情况下,我试图从更大的项目创建一个MVCE。具体地说,该更大的项目创建了一个依赖于libuv
的共享库。但是,当我在更大的项目的共享库上运行ldd
时,它确实显示了对libuv
的依赖(这就是我获得上面“期望的”ldd输出的输出)。
较大的项目太大,我无法在Stack Overflow上发布,但通过检查其make
输出,我相信我的MCVE正在使用相同的标志进行编译/链接。例如,来自较大项目的一些编译行和链接行是:
cc -fpic -ggdb -Wall -c -o file1.o file1.c
cc -fpic -ggdb -Wall -c -o file2.o file2.c
cc -shared -o libplugin.so file1.o file2.o -fpic -ggdb -Wall -luv
型
(还有更多的文件编译包含libplugin.so
,但上面的子集传达了它的要点-编译标志对于所有编译的文件都是统一的)
**更新:**如果我在共享库的代码中添加对uv_close()
的调用,就会显示所需的依赖关系!即:
#include <uv.h>
int func() {
uv_timespec64_t now;
uv_clock_gettime(UV_CLOCK_REALTIME, &now);
uv_close(NULL, NULL); // <= Adding this line causes the desired dependency to show up in ldd
return 0;
}
$ cc -fpic -ggdb -Wall -c -o func.o func.c
$ cc -shared -o libfunc.so func.o -fpic -ggdb -Wall -luv
$ ldd ./libfunc.so
linux-vdso.so.1 (0x00007ffc1e323000)
libuv.so.1 => /lib/x86_64-linux-gnu/libuv.so.1 (0x00007f412b761000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f412b539000)
/lib64/ld-linux-x86-64.so.2 (0x00007f412b7a1000)
$
有人能帮助我理解这个观察吗?为什么调用uv_clock_gettime()
与uv_close()
在共享库中创建的依赖关系方面会有这种行为?
更新:我想再多探索一下@WeatherVane的评论RE:optimization。在这里,我的理解可能是初步的和不完整的,但我认为如果我用-O0
编译,它会迫使编译器不优化任何东西,因此即使我的共享库只调用uv_clock_gettime()
也会引起依赖。但现实并不符合这个想法:将func.c
返回到只调用uv_clock_gettime()
并使用-O0
编译所有内容,我仍然看不到对libuv
的依赖。即:
$ cc -fpic -ggdb -O0 -Wall -c -o func.o func.c # Note the -O0
$ cc -shared -O0 -o libfunc.so func.o -fpic -ggdb -luv # Note the -O0
$ ldd ./libfunc.so
linux-vdso.so.1 (0x00007fff8e724000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fee6f03e000)
/lib64/ld-linux-x86-64.so.2 (0x00007fee6f274000)
型
我想探索@Barmar的建议,即通过打印now
的值来排除优化的可能性,但即使是那个版本的代码也会导致没有期望的依赖关系。即:
#include <inttypes.h>
#include <stdio.h>
#include <uv.h>
int func() {
uv_timespec64_t now;
uv_clock_gettime(UV_CLOCK_REALTIME, &now);
printf("%" PRId64 "\n", now.tv_sec);
return 0;
}
$ cc -fpic -ggdb -Wall -c -o func.o func.c
$ cc -shared -o libfunc.so func.o -fpic -ggdb -luv
$ ldd ./libfunc.so
linux-vdso.so.1 (0x00007ffd72bdf000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f0a89964000)
/lib64/ld-linux-x86-64.so.2 (0x00007f0a89b9a000)
探索@ EmployeedRussian的建议,readelf
输出为:
$ readelf -Ws /usr/local/lib/libuv.so.1 | grep uv_close
337: 0000000000013766 427 FUNC GLOBAL DEFAULT 14 uv_close
735: 0000000000013766 427 FUNC GLOBAL DEFAULT 14 uv_close
$ readelf -Ws /usr/local/lib/libuv.so.1 | grep uv_clock_gettime
341: 00000000000136a0 178 FUNC GLOBAL DEFAULT 14 uv_clock_gettime
1120: 00000000000136a0 178 FUNC GLOBAL DEFAULT 14 uv_clock_gettime
$
我根据@ EmployeedRussian的回答更新了这篇文章,因为它们是相关的,但作为评论添加起来很麻烦。
对于只调用uv_clock_gettime
的共享库版本,使用链接器-y
选项可以发现:
$ cc -shared -Wl,-y,uv_clock_gettime,-y,uv_close -o libfunc.so func.o -fpic -ggdb -luv
/usr/bin/ld: func.o: reference to uv_clock_gettime
/usr/bin/ld: /usr/lib/gcc/x86_64-linux-gnu/11/../../../x86_64-linux-gnu/libuv.so: definition of uv_close
$
.并且对于引用uv_clock_gettime
和uv_close
的共享库版本,链接器-y
选项显示:
$ cc -shared -Wl,-y,uv_clock_gettime,-y,uv_close -o libfunc.so func.o -fpic -ggdb -luv
/usr/bin/ld: func.o: reference to uv_close
/usr/bin/ld: func.o: reference to uv_clock_gettime
/usr/bin/ld: /usr/lib/gcc/x86_64-linux-gnu/11/../../../x86_64-linux-gnu/libuv.so: definition of uv_close
.这与@EmployedRussian对引用的符号与发现的符号与DT_NEEDED
的解释一致。
此外,对于只引用uv_clock_gettime
的共享库版本,使用链接器--no-as-needed
标志确实“强制”包含依赖项:
$ cc -shared -Wl,--no-as-needed -o libfunc.so func.o -fpic -ggdb -luv
$ ldd ./libfunc.so
linux-vdso.so.1 (0x00007ffe312cf000)
libuv.so.1 => /lib/x86_64-linux-gnu/libuv.so.1 (0x00007f36fe4f8000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f36fe2d0000)
/lib64/ld-linux-x86-64.so.2 (0x00007f36fe538000)
$
1条答案
按热度按时间bkkx9g8r1#
我注意到的另一件事是:我需要grep
/usr/local/lib/libuv.so.1
而不是/lib/x86_64-linux-gnu/libuv.so.1
,因为后者没有uv_clock_gettime
符号。这可能就是答案,我猜
/lib/x86_64-linux-gnu/libuv.so.1
在链接时被使用,并且1.您的GCC默认配置为传递
-Wl,--as-needed
。如果这两个条件都为真,那么,当你链接
func.o
时,* doesn 't * referenceuv_close
,链接器会找到/lib/x86_64-linux-gnu/libuv.so.1
,但发现它不满足任何符号,因此不会将它记录为libfoo.so
的DT_NEEDED
。当您将
func.o
更改为也需要uv_close
时,链接器会观察到/lib/x86_64-linux-gnu/libuv.so.1
是满足该符号所必需的,并将其记录在libfoo.so
的DT_NEEDED
标记中。要确认这些猜测,请将
libfoo.so
与-Wl,-y,uv_clock_gettime,-y,uv_close
flag链接。这应该会显示哪些二进制文件引用,哪些定义了这两个符号。您还可以链接到
-Wl,--no-as-needed
--在这种情况下,libuv.so.1
将显示出来,而不管它是否满足任何符号。