【问题标题】:Fedora 28 / GLIBC 2.27 libm.so.6 logf() and powf() c++Fedora 28 / GLIBC 2.27 libm.so.6 logf() 和 powf() c++
【发布时间】:2019-01-13 22:11:17
【问题描述】:

我相信其他 Fedora 28 用户会知道,操作系统的 glibc 最近更新为 glibc 2.27。除了许多其他功能之外,2.27 还添加了 logf() 和 powf() 的新实现。这导致我的应用程序无法在具有较旧 glibc(例如 Debian)的发行版上运行。在 Debian 上调用应用程序时,会产生以下错误:

  • ... libm.so.6 版本 GLIBC-2.27 未找到(./app_name 要求)

我使用以下过程将符号跟踪到 logf 和 powf:

objdump -T ./app_name | grep GLIBC_2.27

它给出了以下输出:

0000000000000000      DF *UND*  0000000000000000  GLIBC_2.27  powf
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.27  logf

然后……

objdump -T /lib/libm.so.6 | grep -w logf
objdump -T /lib/libm.so.6 | grep -w powf

它给出了以下输出:

000397a0 g    DF .text  00000135  GLIBC_2.27  logf
00010430 g    DF .text  0000009e (GLIBC_2.0)  logf

还有……

000397a0 g    DF .text  00000135  GLIBC_2.27  powf
00010430 g    DF .text  0000009e (GLIBC_2.0)  powf

因此,有了 powf() 和 logf() 也在 GLIBC-2.0 中实现的信息,我将以下内容添加到我的项目中(在 main() 之上)并重新编译。

__asm__(".symver logf,logf@GLIBC_2.0");
__asm__(".symver powf,powf@GLIBC_2.0"); 

不幸的是,我的项目仍在使用 GLIBC-2.27 中的 powf 和 logf。实际上,我为 Debian 分发二进制文件非常重要,如果可以避免的话,我宁愿不必在该发行版上编译。

从历史上看,我已经成功地将这个过程用于 libc.so.6 中的符号,但不适用于 libm.so.6。我应该为 libm.so.6 做不同的事情吗?

很明显,我在这里遗漏了一些东西,因此我将感谢您提供的任何帮助。

非常感谢

阿曼达

【问题讨论】:

  • 一般来说,在较新的操作系统上构建并尝试在较旧的操作系统上运行是行不通的。您应该使用旧的工具链和库设置构建机器(可能作为容器或 VM),并在那里构建。

标签: linux c++11 debian fedora glibc


【解决方案1】:

我认为问题在于您使用objdump 来查找 32 位 libm 的符号版本,并且我假设您实际上正在构建一个 64 位应用程序。在 Fedora 28 容器中,如果我查看 64 位库,则会看到这些版本:

objdump -T /lib64/libm.so.6 | egrep -w 'logf|powf'
0000000000011ea0 g    DF .text  0000000000000138 (GLIBC_2.2.5) powf
000000000004cad0 g   iD  .text  000000000000002a  GLIBC_2.27  powf
000000000004c610 g   iD  .text  000000000000002a  GLIBC_2.27  logf
0000000000011e40 g    DF .text  0000000000000051 (GLIBC_2.2.5) logf

这按预期工作:

#include <math.h>

__asm__(".symver logf,logf@GLIBC_2.2.5");
__asm__(".symver powf,powf@GLIBC_2.2.5");

int main(int argc, char**)
{
  return powf(argc, 2.0f) * logf(argc);
}

它使用 64 位库中的版本:

$ g++ m.cc 
$ nm  --undefined-only a.out
                 w __gmon_start__
                 U __libc_start_main@@GLIBC_2.2.5
                 U logf@GLIBC_2.2.5
                 U powf@GLIBC_2.2.5

所以我认为问题在于您试图链接到根本不在 64 位库中的符号(因为 glibc 在 2.2.5 版之前没有这些符号的 64 位版本,所以它们GLIBC_2.0 版本不存在)。

要使其适用于 32 位或 64 位,您可以这样做:

#include <math.h>

#if __LP64__
# define SYMVER "GLIBC_2.2.5"
#else
# define SYMVER "GLIBC_2.0"
#endif
#define USE_OLD_SYM(F,V) __asm__(".symver " #F "," #F "@" V)
USE_OLD_SYM(logf,SYMVER);
USE_OLD_SYM(powf,SYMVER);

int main(int argc, char**)
{
  return powf(argc, 2.0f) * logf(argc);
}

这使用了正确的字号版本:

$ g++ m.cc  
$ nm  --undefined-only a.out
                 w __gmon_start__
                 U __libc_start_main@@GLIBC_2.2.5
                 U logf@GLIBC_2.2.5
                 U powf@GLIBC_2.2.5
$ g++ m.cc  -m32
$ nm  --undefined-only a.out
         w __gmon_start__
         U __libc_start_main@@GLIBC_2.0
         U logf@GLIBC_2.0
         U powf@GLIBC_2.0

【讨论】:

  • 我必须承认我现在觉得自己很傻。我完全错过了我使用的是 32 位版本的 libm.so.6 的事实。我按照你的建议做了,我的项目现在在 Fedora 上编译时在 Debian 上运行。再次感谢您的帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-30
  • 2020-03-07
  • 2018-12-19
  • 1970-01-01
  • 2022-09-27
  • 2023-03-29
相关资源
最近更新 更多