Fedora 28 / GLIBC 2.27 libm.so.6 logf() 和 powf() c++
Fedora 28 / GLIBC 2.27 libm.so.6 logf() and powf() c++
我相信其他 Fedora 28 用户会知道,OS 的 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
因此,根据 GLIBC-2.0 中也实现了 powf() 和 logf() 的信息,我将以下内容添加到我的项目中(在 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 做不同的事情吗?
很明显,我在这里遗漏了一些东西,所以如果能提供任何帮助,我将不胜感激。
非常感谢
阿曼达
我认为问题在于您使用 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
所以我认为问题在于您试图 link 根本不在 64 位库中的符号(因为 glibc 没有这些符号的 64 位版本,直到 version 2.2.5,因此 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
我相信其他 Fedora 28 用户会知道,OS 的 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
因此,根据 GLIBC-2.0 中也实现了 powf() 和 logf() 的信息,我将以下内容添加到我的项目中(在 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 做不同的事情吗?
很明显,我在这里遗漏了一些东西,所以如果能提供任何帮助,我将不胜感激。
非常感谢
阿曼达
我认为问题在于您使用 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
所以我认为问题在于您试图 link 根本不在 64 位库中的符号(因为 glibc 没有这些符号的 64 位版本,直到 version 2.2.5,因此 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