为什么这个共享库没有预期的依赖关系?

问题描述 投票:0回答:1

我正在尝试创建一个共享库

libfunc.so
,它依赖于另一个共享库(特别是
libuv.so
,但我认为特定库与问题无关)。 IE。当我运行
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 的评论回复:进一步优化。再次强调,我的理解可能是初级和不完整的,但我认为如果我使用

-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)

探索@EmployedRussian的建议,

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
$
c linker shared-libraries
1个回答
0
投票

我注意到的另一件事:我需要 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 默认配置为通过 
  2. -Wl,--as-needed
  3. 
    
  4. 如果这两个都是 true,那么,当您链接
func.o

时,

引用 uv_close,链接器找到
/lib/x86_64-linux-gnu/libuv.so.1
,但发现它不满足任何符号,因此不记录它作为
DT_NEEDED
代表
libfoo.so
当您将 

func.o

更改为还需要

uv_close
时,链接器会观察到
/lib/x86_64-linux-gnu/libuv.so.1
是满足该符号所必需的,并将其记录在
DT_NEEDED
libfoo.so
标记中。

要确认这些猜测,请将
libfoo.so

-Wl,-y,uv_clock_gettime,-y,uv_close
标志链接起来。这应该显示哪些二进制文件引用并定义了这两个符号。
您也可以与 

-Wl,--no-as-needed

链接——这样的话,无论是否满足任何符号,

libuv.so.1
都会出现。
    

© www.soinside.com 2019 - 2024. All rights reserved.