2013-07-03 59 views
4

鑑於程序靜態當地人

$ 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的可執行文件。

回答

0

GNU/Linux格式取代了System V目標文件格式,您的gcc認爲您的可執行文件可以運行的最小OS/ABI是GNU/Linux。

這種情況通常發生在你的程序有符號類型爲STT_GNU_IFUNC(表示間接函數的GNU擴展)時,這些符號通常來自glibc。當你引入本地靜態變量gcc向翻譯單元添加(更多)代碼來處理其初始化和破壞(沿着_ZZZ__static_initialization_and_destruction_iii的行),這就是glibc的相關部分可能發揮作用的地方。

首先,最好的辦法是遵循我們在這方面的問題:How to avoid STT_GNU_IFUNC symbols in your binary?

其次,我必須說,在我的盒子,無論是老的gcc 4.4和新鐺3.4生成全球本地二進制文件爲SYSV標準ELF,所以無論您的測試用例是否缺少更多相關的代碼或片段,或者您可能使用了自定義配置和構建的gcc,自定義鏈接器或非標準glibc。

更多的途徑,你可以追求來調查你是怎麼最終在你的二元這些GNU間接功能:在你的二進制

  • 運行nm和識別間接的符號,他們應該有i類型。 (請參閱下面的內容。)
  • 生成鏈接圖和/或程序集輸出,並將這些間接符號跟蹤到代碼的細節。
  • 另外檢查是否有ldd -v $(type -p gcc)點定位的glibc你到一個非標準的libc

我 - 對於PE格式的文件,這表明該符號是一款專門針對dll的實施。對於ELF格式的文件,這表明該符號是一個間接函數。這是一組標準ELF符號類型的GNU擴展。它表示一個符號>如果重定位引用的值不是計算到其地址,而是必須在運行時調用。然後,運行時執行將返回要在重定位中使用的值。

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