2017-07-28 113 views
3

在以前的GCC版本中,objdump報告的符號偏移量與實際執行代碼時使用的符號偏移量相匹配。例如:objdump報告的符號偏移量不再匹配運行時偏移量

$ cat example.c 
#include <stdio.h> 

int g_someGlobal = 0; 

int main() 
{ 
    printf("%d\n", g_someGlobal); 
    return 0; 
} 

$ gcc-6 -v 
... 
gcc version 6.1.1 20160802 (Debian 6.1.1-11) 


$ gcc-6 -O0 -g -o example example.c 

$ objdump -x example | grep Global 
... 
080496f4 g  O .bss  00000004    g_someGlobal 
... 

的確,運行二進制時,在執行期間所使用的符號的實際地址是相同的一個作爲通過objdump的報道:

$ gdb ./example 
... 
(gdb) start 
Temporary breakpoint 1, main() at example.c:10 
10   printf("%d\n", g_someGlobal); 

(gdb) p/x &g_someGlobal 
$1 = 0x80496f4 

不幸的是,重複相同的序列在最近發佈的Debian拉伸命令,出現這種情況,而不是:

$ gcc-6 -v 
... 
gcc version 6.3.0 20170415 (Debian 6.3.0-14) 


$ gcc-6 -O0 -g -o example example.c 

$ objdump -x example | grep Global 
00002020 g  O .bss 00000004    g_someGlobal 

符號現在偏移似乎是一個更小的值 - 這...

$ gdb ./example 
... 
(gdb) start 
... 
Temporary breakpoint 1, main() at example.c:7 
7    printf("%d\n", g_someGlobal); 
(gdb) p/x &g_someGlobal 
$1 = 0x80002020 

...不再在運行時使用的一個相匹配。

我在這裏犯了一個錯誤嗎?在此期間工具的使用是否改變了?如果不是,這個改變背後的推理是什麼?

無論如何 - 理論上必須有一種方法來獲得承載變量的.bss段的「預期運行時偏移量」(objdump確實報告將放置哪個段,因此最終運行時位置可以通過加上.bss偏移量來計算)。在我的初步嘗試這樣做,我還沒有找到一種方式來獲得這一點,雖然:

$ readelf --sections example | grep bss 
[26] .bss   NOBITS  0000201c 00101c 000008 00 WA 0 0 4 

這似乎並沒有上報,似乎發生在.bss -hosted變量中的0x80000000的「轉移」這個例子。 ?

(即使這是一個「神奇常數」這個新的執行環境,是否適用於.data變量,也和說實話,我討厭魔法值 - 此前,無論出來的objdump -x準確,無論符號在哪裏...)

任何信息來解決這個最受歡迎。理想情況下,我想重現objdump -x的舊行爲 - 即靜態地(不是在運行時)從承載它的ELF中獲取符號的運行時地址的值。

UPDATE:我做了GCC7.1.0的自定義編譯(來源),這不再可重現。也許這是在GCC 6.3(打包在Debian的拉伸版)迴歸...

+1

現在不在KB中輸入答案,但原因是Debian的gcc軟件包是用'--enable-default-pie'構建的。添加'-no-pie'來連接命令行以獲得鏈接時間確定的地址。 –

+0

@R ..的確,經過驗證!如果您將評論添加爲答案,我會接受它。你有沒有關於爲什麼Debian選擇這樣做的背景? – ttsiodras

+0

沒關係,我讀了關於PIE並理解 - 安全相關的事情。再次感謝! – ttsiodras

回答

3

的原因是Debian的GCC軟件包是建立與--enable-default-pie。在一個PIE可執行文件中,ELF段可以被加載到一個任意的(只要它是正確對齊的)基址,通常由加載程序隨機選擇。您在ELF文件中看到的符號地址相對於它所加載的基地址而言是偏移量,而不是絕對虛擬地址。

如果你不想/需要PIE,你可以添加-no-pie鏈接命令行來獲得像你習慣的鏈接時間確定的地址。