首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >将构建环境升级到Ubuntu14.4后,“Version `GLIBC_2.16‘not”目标主机错误

将构建环境升级到Ubuntu14.4后,“Version `GLIBC_2.16‘not”目标主机错误
EN

Stack Overflow用户
提问于 2016-02-12 12:36:56
回答 1查看 2.7K关注 0票数 3

在将构建环境升级到Ubuntu14.4之后,main可执行程序拒绝在使用旧Linux版本的主机上启动,其消息如下:

/lib/i 386-linux-gnu/libc.so.6:未找到版本`GLIBC_2.16‘(由./executable_name要求)

为了安全地将我的包分发给拥有较早的Glibc的主机,我是否应该尝试:

  • 静态链接与libc?
  • 在构建机器上降低libc的级别?
  • 安装较老的glibc以及一个Ubuntu发行版吗?用什么?

注意:-我不需要使用来自旧Ubuntu版本的任何二进制文件--我不需要构建旧的Ubuntu版本

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-02-15 08:23:59

经过长时间的调查,我终于找到了解决这个问题的办法。

首先,我查看了可执行文件依赖项:

代码语言:javascript
运行
复制
ldd -v <executable_name>

我的构建是用Cmake构建的,只有它的发布版本具有以下依赖性:

代码语言:javascript
运行
复制
Version information: 
    ./build/Release/products/<executable_name>: 
    libc.so.6 (GLIBC_2.16) => /lib/i386-linux-gnu/libc.so.6

在使用objdump分析该文件时,我检索到它需要__poll_chk符号:

代码语言:javascript
运行
复制
00000000       F *UND*  00000000              __poll_chk@@GLIBC_2.16

尽管Glibc使用所谓的__symbol版本控制__,但这个特定的函数仅在Glibc 2.16中添加。

因此,我试图研究是什么导致了Debug和版本构建之间的差异。

设置类型时,Cmake定义内部变量,这些变量确定编译器标志。对于GCC来说,他们是:

  • 调试:-g
  • 发布:-NDEBUG -O3

Glibcpoll.h包括poll2.h,它包含棘手的_poll_chk,但在Glibc 2.16中不可用。这包括在_USE_FORTIFY_LEVEL定义下。

而且,根据Linux页面(见下面的引号),在版本构建中,由于-D_FORTIFY_SOURCE=2级别的原因,我使用了-O3。

代码语言:javascript
运行
复制
man gcc

注意:在Ubuntu8.10及更高版本中,-D_FORTIFY_SOURCE=2默认设置,并在-O设置为2或更高时激活。这允许对几个libc函数进行额外的编译时和运行时检查。若要禁用,请指定-U_FORTIFY_SOURCE或-D_FORTIFY_SOURCE=0。

代码语言:javascript
运行
复制
man feature_test_macros

_FORTIFY_SOURCE (因为glibc2.3.4)定义了这个宏,在使用各种字符串和内存操作函数时,将执行一些轻量级检查来检测缓冲区溢出错误。并不是所有的缓冲区溢出都被检测到,只是一些常见的情况。在当前实现中,将检查对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)和get(3)的调用。如果_FORTIFY_SOURCE设置为1,编译器优化级别1 (gcc -O1)及以上,则执行不应更改符合程序行为的检查。当_FORTIFY_SOURCE设置为2时,会增加一些检查,但一些符合标准的程序可能会失败。有些检查可以在编译时执行,并导致编译器警告;另一些检查在运行时进行,如果检查失败,则会导致运行时错误。使用这个宏需要编译器的支持,gcc(1)可以从4.0版开始使用。

或者直接用

代码语言:javascript
运行
复制
man -K _FORTIFY_SOURCE

我检查了我的可执行文件包含的每个静态库,其代码使用轮询函数,并最终找到了它:

代码语言:javascript
运行
复制
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依赖关系:

代码语言:javascript
运行
复制
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轮询的其他静态库中没有这样的问题?

为了说明情况,我用特殊的GCC旗子来显示预处理器输出:

代码语言:javascript
运行
复制
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -E")

.c.o包括poll.h和poll2.h,其内容如下:

代码语言:javascript
运行
复制
# 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); 
}

但是库对象文件仍然只有较高的轮询符号:

代码语言:javascript
运行
复制
objdump -t  lib.a | grep poll 
00000000 UND    00000000 poll

到目前为止,我无法解释为什么不将棘手的__poll_chk符号添加到其他库中。但是现在我的二进制文件运行在任何目标Linux主机上。

票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/35362844

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档