2015-09-23 76 views
2

我有一個關於ELF動態符號表的問題。對於類型爲FUNC的符號,我注意到某些二進制文件中的值爲0。但在其他二進制文件中,它有一些非零值。這兩個二進制文件都是由gcc生成的,我想知道爲什麼這個區別?有沒有編譯器選項來控制它?ELF動態符號表

編輯:這是readelf --dyn-SYMS的輸出PROG1的 「printf的」 符號是82f0這恰好是對printf的PLT表項的地址

Symbol table '.dynsym' contains 5 entries: 
Num: Value Size Type Bind Vis  Ndx Name 
0: 00000000  0 NOTYPE LOCAL DEFAULT UND 
1: 00000000  0 NOTYPE WEAK DEFAULT UND __gmon_start__ 
2: 000082f0  0 FUNC GLOBAL DEFAULT UND [email protected]_2.4 (2) 
3: 00008314  0 FUNC GLOBAL DEFAULT UND [email protected]_2.4 (2) 
4: 000082fc  0 FUNC GLOBAL DEFAULT UND [email protected]_2.4 

這裏值。 readelf --dyn-SYMS的

輸出PROG2

Symbol table '.dynsym' contains 6 entries: 
Num: Value Size Type Bind Vis  Ndx Name 
0: 00000000  0 NOTYPE LOCAL DEFAULT UND 
1: 00000000  0 NOTYPE WEAK DEFAULT UND __gmon_start__ 
2: 00000000  0 FUNC GLOBAL DEFAULT UND [email protected]_2.4 (2) 
3: 00000000  0 FUNC GLOBAL DEFAULT UND [email protected]_2.4 (2) 
4: 00000000  0 FUNC GLOBAL DEFAULT UND [email protected]_2.4 (2) 
5: 00000000  0 FUNC GLOBAL DEFAULT UND [email protected]_2.4 

這裏的值,所有符號都爲零。

+0

什麼是創建prog1和prog2的確切命令? – Jens

+0

prog2:gcc -o prog2 prog2.c。但關於prog1,我不知道。我想知道是否有任何選項來創建這樣的二進制文件。 –

回答

1

通過觀察上是不確定的一些二進制

所有功能運行readelf有大小爲零。

這些未定義的函數是通過庫調用的函數。在我小的ELF二進制glibc的所有引用是不確定的有21

它變得清晰,符號表可以有三種符號的頁大小零

http://docs.oracle.com/cd/E19457-01/801-6737/801-6737.pdf。在這三種類型中,兩種類型的未定義符號和暫定符號是那些未指定存儲的符號。在稍後的情況下,你可以看到在readelf輸出,一些功能不是未定義的(有索引),並沒有存儲。

爲清楚起見,未定義的符號是那些被引用但未分配存儲空間(尚未創建),而暫定符號是創建但未分配存儲空間的符號。 e.g未初始化的符號

編輯

如果你正在談論.PLT,共享庫綁定符號是懶惰。

如何控制綁定看到http://www.linuxjournal.com/article/1060

此功能被稱爲延遲符號結合。這個想法是,如果你有很多的共享庫,它可能需要動態裝載器大量的時間來查找所有的函數來初始化所有的.plt插槽,所以最好將綁定地址延遲到函數直到我們實際上需要他們。如果你最終只使用共享庫中的一小部分函數,​​這將是一個巨大的勝利。在將控制權轉交給應用程序之前,可以指示動態加載程序將地址綁定到所有.plt插槽,這是通過在運行程序之前設置環境變量LD_BIND_NOW = 1來完成的。例如,在調試程序時,這在某些情況下非常有用。另外,我應該指出.plt是在只讀內存中。因此,用於跳轉目標的地址實際上存儲在.got節中。 .got還包含一組指針,用於來自共享庫的程序中使用的所有全局變量。

+0

這裏我沒有提到函數的大小,通過與GLIBC函數對應的動態符號的值,我指的是.PLT中的條目的地址,從該位置跳轉到實際的glibc函數(通過libc。所以)。我注意到這個入口在一些二進制文件中是非零的。 –

+0

,因爲共享庫在運行時綁定地址而不是編譯時。 – shami

+0

是的,但Dynamic FUNC符號的地址不是加載庫例程的地址,而是相應libc例程的二進制文件中plt條目的地址。我將編輯我的問題以添加readelf --dyn-syms的屏幕截圖,以使您相信。 –

2

x86_64 SV ABI強制要求(重點煤礦):

爲了允許比較的功能地址以預期方式工作, 如果可執行文件引用 的在共享對象中所定義的函數,鏈接編輯器會將該函數的過程鏈接表 條目的地址放置在其關聯的符號表項中。 這將導致符號表條目的段索引爲 SHN_UNDEF,但一種類型的STT_FUNC和爲非零st_value。 在共享的 庫中對函數地址的引用將通過可執行文件中的這種定義來滿足 。

用我GCC,此程序:

#include <stdio.h> 

int main() 
{ 
    printf("hello %i\n", 42); 
    return 0; 
} 

時,直接編譯成可執行產生一個空值:

1: 0000000000000000  0 FUNC GLOBAL DEFAULT UND [email protected]_2.2.5 (2) 

但此方案與printf功能的比較:

#include <stdio.h> 

int main() 
{ 
    printf("hello %i\n", 42); 
    if (printf == puts) 
    return 1; 
    return 0; 
} 

產生非空值:

3: 0000000000400410  0 FUNC GLOBAL DEFAULT UND [email protected]_2.2.5 (2) 

在的.o文件,所述第一程序產生:

000000000014 000a00000002 R_X86_64_PC32  0000000000000000 printf - 4 

和第二:

000000000014 000a00000002 R_X86_64_PC32  0000000000000000 printf - 4 
000000000019 000a0000000a R_X86_64_32  0000000000000000 printf + 0 

的差由引起額外的R_X86_64_32重定位獲取函數的地址。

相關問題