【问题标题】:MIPSEL GLIBC sem_init() not sharedMIPSEL GLIBC sem_init() 未共享
【发布时间】:2021-06-09 06:10:06
【问题描述】:

我目前正在开发一个旨在在 Linux for MIPSEL 平台上运行的应用程序。 该应用程序在其 DSO 之一内使用 POSIX 信号量,在我的例子中,注意的是在应用程序所依赖的一个 DSO 内使用的 sem_init() 函数。

该应用程序当前使用的是 GLIBC_2.31,但我在使用 GLIBC_2_26 时也观察到了同样的现象。

现在我将解释异常和故障排除的当前状态。

当我注意到当信号量增加其值时等待信号量的进程不会唤醒时,这一切都发生了。

为了记录,我知道对于多处理,信号量必须位于使用信号量的进程之间共享的内存区域中。

现在,使用 strace 进一步调查,我还注意到我使用 sem_init(&semaphore, 1, 0) 初始化的信号量导致了 private,尽管我将它初始化为共享。

futex(0x774ce0bc, FUTEX_WAIT_BITSET_PRIVATE|FUTEX_CLOCK_REALTIME, 1, {tv_sec=1615204364, tv_nsec=515578961}, FUTEX_BITSET_MATCH_ANY) = -1 ETIMEDOUT (Connection timed out)

我在这个问题上执行的下一步是使用 gdb 调试信号量初始化过程。在那里我发现在这个特殊的组合中,MIPSEL - LINUX - GLIBCsem_init() 存在两个版本:

$ mipsel-linux-objdump -T libpthread.so.0  | grep sem_init
00012e30 g    DF .text  00000040 (GLIBC_2.0)  sem_init
00012dd0 g    DF .text  00000060  GLIBC_2.2   sem_init

由于某种原因,链接器决定将我的代码链接到 older(不支持共享信号量)而不是 newer

查看 GLIBC 代码,特别是在实现 sem_init() 的地方 (/nptl/sem_init.c),我意识到 sem_init() 是一个别名,两个符号明确地标识了函数的实现。

我的下一步是直接调用我需要的函数__new_sem_init(),以确保任何我不知道的链接器炼金术会干扰我的意图。

很遗憾,符号没有导出,无法使用。

查看我的库liba.so,它使用了sem_wait()sem_init()sem_post(),我注意到这些符号都是由libpthread.so.0 导出的。

$ mipsel-linux-nm -D libpthread.so.0 | grep sem_
00014a10 T sem_clockwait
00013784 T sem_close
00012e70 T sem_destroy
00012e70 T sem_destroy
00013b14 T sem_getvalue
00013b00 T sem_getvalue
00012e30 T sem_init
00012dd0 T sem_init
000131b8 T sem_open
00014ab0 T sem_post
00014b90 T sem_post
00014508 T sem_timedwait
00013f40 T sem_trywait
00013fac T sem_trywait
00013920 T sem_unlink
00013eb0 T sem_wait
00014020 T sem_wait

但是查看liba.so 依赖项,我很惊讶该库仅依赖于主libc 库(libc.so.6)并且不依赖于libpthread.so.0,其中实际的@987654336实现了@符号。

$ /lib/ld-2.31.so --list /usr/lib/liba.so 
        linux-vdso.so.1 (0x7ffaa000)
        libc.so.6 => /lib/libc.so.6 (0x77ddc000)
        /lib/ld-2.31.so (0x77f8a000)

我想这可能与我的问题密切相关,但我不知道如何将这两个事实联系起来。 如何使用其依赖项不提供的符号编译和链接liba.so

$ mipsel-linux-objdump -T libc.so.6  | grep sem
000fab80 g    DF .text  00000070  GLIBC_2.0   semget
000fabf0 g    DF .text  000000b0  GLIBC_2.2   semctl
000faca0  w   DF .text  00000074  GLIBC_2.3.3 semtimedop
000359d0 g    DF .text  00000074  GLIBC_2.0   sigisemptyset
00149854 g    DF .text  000000b0 (GLIBC_2.0)  semctl
000fab60 g    DF .text  00000018  GLIBC_2.0   semop
$

如何强制 GNU 链接器链接到 sem_init@@GLIBC_2.2 而不是 sem_init@GLIBC_2.0

【问题讨论】:

    标签: linux mips semaphore ld glibc


    【解决方案1】:

    看来我的问题确实是下链接问题

    经过对文献的适当研究和大量测试,我终于能够解决我最初的问题。让我的应用程序使用正确版本的sem_init()

    我的假设是因为我的库没有携带 libpthread 依赖项,所以我的假设是正确的。

    检查我的 Makefile,我发现语句中缺少 -libpthread 开关,创建共享库。

    这是问题的根源,一旦我添加了开关,一切都开始按预期工作。

    导致解决方案延迟的原因之一是在不同的目标上使用相同的 Makefile 构建相同的库; libpthread 依赖项已包含在库中。

    但我没有任何解释为什么动态链接器选择了最旧的符号sem_init@GLIBC_2_0 来代替sem_init@GLIBC_2_2

    我知道链接器已经能够链接我的sem_init(),因为原始可执行文件app 具有libpthread 作为依赖项,所以在链接时,库就在那里,它可以找到符号.

    我无法解释的是为什么它选择了sem_init@GLIBC_2_0

    根据这些来源

    http://peeterjoot.com/2019/09/20/an-example-of-linux-glibc-symbol-versioning/@@ 表示它适用于新代码,而@MYSTUFF_1.1 是一个仅加载函数,新代码不能使用该符号。

    https://developers.redhat.com/blog/2019/08/01/how-the-gnu-c-library-handles-backward-compatibility/@@ 告诉动态链接器这个版本是默认版本。

    https://web.archive.org/web/20100430151127/http://www.trevorpounds.com/blog/?33 双@@ 只能为给定符号定义一次,因为它表示要使用的默认版本。

    如果符号未版本化,则带有双 @@ 的符号应由动态链接器选择。

    仅当符号未版本化并且需要符号的对象正确包含对包含该符号的 DSO 的依赖项时,此语句是否正确?

    【讨论】:

      猜你喜欢
      • 2012-07-24
      • 2014-02-09
      • 2015-07-28
      • 2022-01-11
      • 2017-08-03
      • 2014-03-04
      • 1970-01-01
      • 2021-05-16
      • 2019-08-26
      相关资源
      最近更新 更多