3

鉴于程序

$ cat main.cpp 
#ifndef WITH_LOCAL_STATIC
static int y = 0;
#endif

class X {
  public:
    void foo() {
#ifdef WITH_LOCAL_STATIC
        static int y = 0;
#endif
        ++y;
    }
};

int main() {
    X().foo();
    return 0;
}

以两种不同的方式编译:

$ g++ main.cpp -o global
$ g++ main.cpp -DWITH_LOCAL_STATIC -o local

我得到两种不同的二进制格式:

$ file local
local: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=0x8d8e998601e44115b5fa6c0e71f3ed97cb13a0bd, not stripped
$ file global
global: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=0x3481ba7c6969ed9d1bd1c8ce0f052d574023d488, not stripped

有人可以解释为什么我ELFOSABI_LINUX在一种情况下,但ELFOSABI_NONE在另一种情况下?编译器是 gcc 4.7.2

背景是在我的环境中,加载程序拒绝不是ELFOSABI_NONE.

4

1 回答 1

0

GNU/Linux 格式取代了 System V 目标文件格式,并且您的 gcc 认为可以运行您的可执行文件的最小 OS/ABI 是 GNU/Linux。

这通常发生在您的程序具有类型为STT_GNU_IFUNC(表示间接函数的 GNU 扩展)的符号时,并且这些符号通常来自 glibc。当您引入局部静态变量 gcc 时,向翻译单元添加(更多)代码以处理其初始化和销毁​​(沿线_ZZZ__static_initialization_and_destruction_iii),这就是 glibc 的相关部分可能发挥作用的地方。

首先,最好的办法是遵循这个问题中的建议:如何避免二进制文件中的 STT_GNU_IFUNC 符号?

其次,我不得不说,在我的机器上,旧的 gcc 4.4 和新的 clang 3.4 都将全局本地二进制文件生成为SYSV标准 ELF,所以要么你的测试用例缺少更多相关的点点滴滴,要么你是可能使用自定义配置和构建的 gcc、自定义链接器或非标准 glibc。

您可以通过更多途径来调查您是如何在二进制文件中使用这些 GNU 间接函数的:

  • 在您的二进制文件上运行nm并识别间接符号,它们应该具有i类型。(见下文。)
  • 生成链接映射和/或汇编输出,并将这些间接符号跟踪到代码的细节。
  • 另外检查定位 glibc 是否ldd -v $(type -p gcc)指向非标准 libc

i - 对于 PE 格式文件,这表明符号位于特定于 DLL 实现的部分中。对于 ELF 格式文件,这表明该符号是一个间接函数。这是标准 ELF 符号类型集的 GNU 扩展。它表示一个符号 > 如果被重定位引用,它不会计算为它的地址,而是必须在运行时调用。然后运行时执行将返回要在重定位中使用的值。

https://sourceware.org/binutils/docs/binutils/nm.html

于 2014-02-19T08:34:39.693 回答