将构建环境升级到 Ubuntu 14.4 后出现“版本 `GLIBC_2.16' 未找到”目标主机错误
“Version `GLIBC_2.16' not found” target host error after upgrading build environment to Ubuntu 14.4
将构建环境升级到 Ubuntu 14.4 后,主要可执行文件拒绝在具有旧 Linux 版本的主机上启动,并显示以下消息:
/lib/i386-linux-gnu/libc.so.6: version `GLIBC_2.16' not found
(required by ./executable_name)
为了安全地将我的包分发到具有较旧 Glibc 的主机,我应该尝试:
- 针对 libc 进行静态链接?
- 在构建机器上降级 libc?
- 安装较旧的 glibc 以及一个 Ubuntu 分配器行吗?
与?
注意:
- 我不需要使用旧 Ubuntu 版本的任何二进制文件
- 我不需要在旧的 Ubuntu 版本
上构建
经过长时间的调查,我终于找到了解决问题的方法。
首先我查看了可执行文件的依赖关系:
ldd -v <executable_name>
我的构建是用 Cmake 构建的,只有它的 Release 版本有以下依赖:
Version information:
./build/Release/products/<executable_name>:
libc.so.6 (GLIBC_2.16) => /lib/i386-linux-gnu/libc.so.6
用objdump分析这个文件,我检索到它需要__poll_chk符号:
00000000 F *UND* 00000000 __poll_chk@@GLIBC_2.16
尽管 Glibc 使用所谓的 _symbol versioning _,但此特定功能仅在 Glibc 2.16.
中添加
因此,我尝试调查导致调试版本和发布版本之间存在差异的原因。
设置CMAKE_BUILD_TYPE时,Cmake 定义本地变量,这些变量决定编译器标志。对于 GCC 4.8.4,它们是:
- 调试:-g
- 发布:-NDEBUG -O3
Glibc poll.h包含poll2.h,其中包含棘手的_poll_chk 在 GLibc 2.16 中还不可用。这包括在 _USE_FORTIFY_LEVEL 定义下。
并且根据 Linux 手册页(参见下面的引用)在发布版本中我有 -D_FORTIFY_SOURCE=2 由于 - O3级.
man gcc
NOTE: In Ubuntu 8.10 and later versions, -D_FORTIFY_SOURCE=2 is set by
default, and is activated when -O is set to 2 or higher. This
enables additional compile-time and run-time checks for several libc
functions. To disable, specify either -U_FORTIFY_SOURCE or
-D_FORTIFY_SOURCE=0.
man feature_test_macros
_FORTIFY_SOURCE (since glibc 2.3.4) Defining this macro causes some lightweight checks to be performed to detect some buffer overflow
errors when employing various string and memory manipulation
functions. Not all buffer overflows are detected, just some
common cases. In the current implementation, checks are added
for calls to memcpy(3), mempcpy(3), memmove(3), memset(3), stpcpy(3),
strcpy(3), strncpy(3), strcat(3), strncat(3), sprintf(3), snprintf(3),
vsprintf(3), vsnprintf(3), and gets(3). If _FORTIFY_SOURCE is set to
1, with compiler optimization level 1 (gcc -O1) and above, checks that
shouldn't change the behavior of conforming programs are performed.
With _FORTIFY_SOURCE set to 2 some more checking is added, but some
conforming programs might fail. Some of the checks can be performed
at compile time, and result in compiler warnings; other checks take
place at run time, and result in a run-time error if the check fails.
Use of this macro requires compiler support, available with gcc(1)
since version 4.0.
或者只使用
man -K _FORTIFY_SOURCE
我检查了我的可执行文件包含的每个静态库,其代码使用 poll 函数并最终找到了它:
objdump -t lib.a | grep poll
00000000 *UND* 00000000 Curl_poll
00000000 l d .text.Curl_poll 00000000 .text.Curl_poll
00000000 *UND* 00000000 poll
00000000 *UND* 00000000 __poll_chk
00000000 g F .text.Curl_poll 0000025c Curl_poll
可以通过将 -U_FORTIFY_SOURCE 添加到目标 CmakeLists.txt 中的编译器标志来禁用此优化。这消除了任何最近检测到的 GLIBC2.16 依赖项:
Version information:
products/<executable>:
ld-linux.so.2 (GLIBC_2.3) => /lib/ld-linux.so.2
librt.so.1 (GLIBC_2.2) => /lib/i386-linux-gnu/librt.so.1
libdl.so.2 (GLIBC_2.0) => /lib/i386-linux-gnu/libdl.so.2
libdl.so.2 (GLIBC_2.1) => /lib/i386-linux-gnu/libdl.so.2
libpthread.so.0 (GLIBC_2.2) => /lib/i386-linux-gnu/libpthread.so.0
libpthread.so.0 (GLIBC_2.3.2) => /lib/i386-linux-gnu/libpthread.so.0
libpthread.so.0 (GLIBC_2.1) => /lib/i386-linux-gnu/libpthread.so.0
libpthread.so.0 (GLIBC_2.0) => /lib/i386-linux-gnu/libpthread.so.0
libpulse.so.0 (PULSE_0) => /usr/lib/i386-linux-gnu/libpulse.so.0
libsndfile.so.1 (libsndfile.so.1.0) => /usr/lib/i386-linux-gnu/libsndfile.so.1
libc.so.6 (GLIBC_2.15) => /lib/i386-linux-gnu/libc.so.6
libc.so.6 (GLIBC_2.11) => /lib/i386-linux-gnu/libc.so.6
libc.so.6 (GLIBC_2.1.3) => /lib/i386-linux-gnu/libc.so.6
libc.so.6 (GLIBC_2.2.4) => /lib/i386-linux-gnu/libc.so.6
libc.so.6 (GLIBC_2.4) => /lib/i386-linux-gnu/libc.so.6
libc.so.6 (GLIBC_2.1) => /lib/i386-linux-gnu/libc.so.6
libc.so.6 (GLIBC_2.3) => /lib/i386-linux-gnu/libc.so.6
libc.so.6 (GLIBC_2.2) => /lib/i386-linux-gnu/libc.so.6
libc.so.6 (GLIBC_2.7) => /lib/i386-linux-gnu/libc.so.6
libc.so.6 (GLIBC_2.0) => /lib/i386-linux-gnu/libc.so.6
libc.so.6 (GLIBC_2.3.4) => /lib/i386-linux-gnu/libc.so.6
我唯一不明白的是为什么我在其他调用 GLibc poll 的静态库中没有这样的问题?
为了使情况更清楚,我使用了特殊的 GCC 标志来显示预处理器输出:
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -E")
.c.o包括poll.h和poll2.h 其内容如下:
# 1 "/usr/include/i386-linux-gnu/bits/poll2.h" 1 3 4
# 24 "/usr/include/i386-linux-gnu/bits/poll2.h" 3 4
extern int __poll_alias (struct pollfd *__fds, nfds_t __nfds, int __timeout) __asm__ ("" "poll")
;
extern int __poll_chk (struct pollfd *__fds, nfds_t __nfds, int __timeout,
unsigned int __fdslen);
extern int __poll_chk_warn (struct pollfd *__fds, nfds_t __nfds, int __timeout, unsigned int __fdslen) __asm__ ("" "__poll_chk")
__attribute__((__warning__ ("poll called with fds buffer too small file nfds entries")));
extern __inline __attribute__ ((__always_inline__)) __attribute__ ((__gnu_inline__)) __attribute__ ((__artificial__)) int
poll (struct pollfd *__fds, nfds_t __nfds, int __timeout)
{
if (__builtin_object_size (__fds, 2 > 1) != (unsigned int) -1)
{
if (! __builtin_constant_p (__nfds))
return __poll_chk (__fds, __nfds, __timeout, __builtin_object_size (__fds, 2 > 1));
else if (__builtin_object_size (__fds, 2 > 1) / sizeof (*__fds) < __nfds)
return __poll_chk_warn (__fds, __nfds, __timeout, __builtin_object_size (__fds, 2 > 1));
}
return __poll_alias (__fds, __nfds, __timeout);
}
但是库目标文件仍然只有上层 poll 符号:
objdump -t lib.a | grep poll
00000000 UND 00000000 poll
到目前为止,我无法解释为什么棘手的 __poll_chk 符号没有添加到其他库中。但是现在我的二进制文件可以在任何目标 Linux 主机上运行。
将构建环境升级到 Ubuntu 14.4 后,主要可执行文件拒绝在具有旧 Linux 版本的主机上启动,并显示以下消息:
/lib/i386-linux-gnu/libc.so.6: version `GLIBC_2.16' not found (required by ./executable_name)
为了安全地将我的包分发到具有较旧 Glibc 的主机,我应该尝试:
- 针对 libc 进行静态链接?
- 在构建机器上降级 libc?
- 安装较旧的 glibc 以及一个 Ubuntu 分配器行吗? 与?
注意: - 我不需要使用旧 Ubuntu 版本的任何二进制文件 - 我不需要在旧的 Ubuntu 版本
上构建经过长时间的调查,我终于找到了解决问题的方法。
首先我查看了可执行文件的依赖关系:
ldd -v <executable_name>
我的构建是用 Cmake 构建的,只有它的 Release 版本有以下依赖:
Version information:
./build/Release/products/<executable_name>:
libc.so.6 (GLIBC_2.16) => /lib/i386-linux-gnu/libc.so.6
用objdump分析这个文件,我检索到它需要__poll_chk符号:
00000000 F *UND* 00000000 __poll_chk@@GLIBC_2.16
尽管 Glibc 使用所谓的 _symbol versioning _,但此特定功能仅在 Glibc 2.16.
中添加因此,我尝试调查导致调试版本和发布版本之间存在差异的原因。
设置CMAKE_BUILD_TYPE时,Cmake 定义本地变量,这些变量决定编译器标志。对于 GCC 4.8.4,它们是:
- 调试:-g
- 发布:-NDEBUG -O3
Glibc poll.h包含poll2.h,其中包含棘手的_poll_chk 在 GLibc 2.16 中还不可用。这包括在 _USE_FORTIFY_LEVEL 定义下。
并且根据 Linux 手册页(参见下面的引用)在发布版本中我有 -D_FORTIFY_SOURCE=2 由于 - O3级.
man gcc
NOTE: In Ubuntu 8.10 and later versions, -D_FORTIFY_SOURCE=2 is set by default, and is activated when -O is set to 2 or higher. This enables additional compile-time and run-time checks for several libc functions. To disable, specify either -U_FORTIFY_SOURCE or -D_FORTIFY_SOURCE=0.
man feature_test_macros
_FORTIFY_SOURCE (since glibc 2.3.4) Defining this macro causes some lightweight checks to be performed to detect some buffer overflow errors when employing various string and memory manipulation functions. Not all buffer overflows are detected, just some common cases. In the current implementation, checks are added for calls to memcpy(3), mempcpy(3), memmove(3), memset(3), stpcpy(3), strcpy(3), strncpy(3), strcat(3), strncat(3), sprintf(3), snprintf(3), vsprintf(3), vsnprintf(3), and gets(3). If _FORTIFY_SOURCE is set to 1, with compiler optimization level 1 (gcc -O1) and above, checks that shouldn't change the behavior of conforming programs are performed. With _FORTIFY_SOURCE set to 2 some more checking is added, but some conforming programs might fail. Some of the checks can be performed at compile time, and result in compiler warnings; other checks take place at run time, and result in a run-time error if the check fails. Use of this macro requires compiler support, available with gcc(1) since version 4.0.
或者只使用
man -K _FORTIFY_SOURCE
我检查了我的可执行文件包含的每个静态库,其代码使用 poll 函数并最终找到了它:
objdump -t lib.a | grep poll
00000000 *UND* 00000000 Curl_poll
00000000 l d .text.Curl_poll 00000000 .text.Curl_poll
00000000 *UND* 00000000 poll
00000000 *UND* 00000000 __poll_chk
00000000 g F .text.Curl_poll 0000025c Curl_poll
可以通过将 -U_FORTIFY_SOURCE 添加到目标 CmakeLists.txt 中的编译器标志来禁用此优化。这消除了任何最近检测到的 GLIBC2.16 依赖项:
Version information:
products/<executable>:
ld-linux.so.2 (GLIBC_2.3) => /lib/ld-linux.so.2
librt.so.1 (GLIBC_2.2) => /lib/i386-linux-gnu/librt.so.1
libdl.so.2 (GLIBC_2.0) => /lib/i386-linux-gnu/libdl.so.2
libdl.so.2 (GLIBC_2.1) => /lib/i386-linux-gnu/libdl.so.2
libpthread.so.0 (GLIBC_2.2) => /lib/i386-linux-gnu/libpthread.so.0
libpthread.so.0 (GLIBC_2.3.2) => /lib/i386-linux-gnu/libpthread.so.0
libpthread.so.0 (GLIBC_2.1) => /lib/i386-linux-gnu/libpthread.so.0
libpthread.so.0 (GLIBC_2.0) => /lib/i386-linux-gnu/libpthread.so.0
libpulse.so.0 (PULSE_0) => /usr/lib/i386-linux-gnu/libpulse.so.0
libsndfile.so.1 (libsndfile.so.1.0) => /usr/lib/i386-linux-gnu/libsndfile.so.1
libc.so.6 (GLIBC_2.15) => /lib/i386-linux-gnu/libc.so.6
libc.so.6 (GLIBC_2.11) => /lib/i386-linux-gnu/libc.so.6
libc.so.6 (GLIBC_2.1.3) => /lib/i386-linux-gnu/libc.so.6
libc.so.6 (GLIBC_2.2.4) => /lib/i386-linux-gnu/libc.so.6
libc.so.6 (GLIBC_2.4) => /lib/i386-linux-gnu/libc.so.6
libc.so.6 (GLIBC_2.1) => /lib/i386-linux-gnu/libc.so.6
libc.so.6 (GLIBC_2.3) => /lib/i386-linux-gnu/libc.so.6
libc.so.6 (GLIBC_2.2) => /lib/i386-linux-gnu/libc.so.6
libc.so.6 (GLIBC_2.7) => /lib/i386-linux-gnu/libc.so.6
libc.so.6 (GLIBC_2.0) => /lib/i386-linux-gnu/libc.so.6
libc.so.6 (GLIBC_2.3.4) => /lib/i386-linux-gnu/libc.so.6
我唯一不明白的是为什么我在其他调用 GLibc poll 的静态库中没有这样的问题?
为了使情况更清楚,我使用了特殊的 GCC 标志来显示预处理器输出:
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -E")
.c.o包括poll.h和poll2.h 其内容如下:
# 1 "/usr/include/i386-linux-gnu/bits/poll2.h" 1 3 4
# 24 "/usr/include/i386-linux-gnu/bits/poll2.h" 3 4
extern int __poll_alias (struct pollfd *__fds, nfds_t __nfds, int __timeout) __asm__ ("" "poll")
;
extern int __poll_chk (struct pollfd *__fds, nfds_t __nfds, int __timeout,
unsigned int __fdslen);
extern int __poll_chk_warn (struct pollfd *__fds, nfds_t __nfds, int __timeout, unsigned int __fdslen) __asm__ ("" "__poll_chk")
__attribute__((__warning__ ("poll called with fds buffer too small file nfds entries")));
extern __inline __attribute__ ((__always_inline__)) __attribute__ ((__gnu_inline__)) __attribute__ ((__artificial__)) int
poll (struct pollfd *__fds, nfds_t __nfds, int __timeout)
{
if (__builtin_object_size (__fds, 2 > 1) != (unsigned int) -1)
{
if (! __builtin_constant_p (__nfds))
return __poll_chk (__fds, __nfds, __timeout, __builtin_object_size (__fds, 2 > 1));
else if (__builtin_object_size (__fds, 2 > 1) / sizeof (*__fds) < __nfds)
return __poll_chk_warn (__fds, __nfds, __timeout, __builtin_object_size (__fds, 2 > 1));
}
return __poll_alias (__fds, __nfds, __timeout);
}
但是库目标文件仍然只有上层 poll 符号:
objdump -t lib.a | grep poll
00000000 UND 00000000 poll
到目前为止,我无法解释为什么棘手的 __poll_chk 符号没有添加到其他库中。但是现在我的二进制文件可以在任何目标 Linux 主机上运行。