2015-11-03 164 views
2

我的程序正在使用gcc的linux上工作。通過手冊頁,我發現edata,它代表初始化數據段的第一個地址過去結束
但我想知道初始化數據段的首地址
我該如何得到它?如何獲得初始化數據段的首地址

我試過把etext作爲初始化數據段的第一個地址。然後,當我增加地址並訪問存儲在其中的變量時,我遇到了段錯誤。我認爲etext和edata之間的一些地址空間沒有映射到虛擬內存中。是對的嗎?

+3

你如何找到'edata'?你不能使用相同的技術來查找數據嗎?爲什麼不簡單地閱讀二進制文件並找到'data'段?我最感興趣的是*爲什麼*你需要它?你試圖解決什麼是原始問題?(相關閱讀:[「什麼是XY問題」](http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem)) –

+0

@JoachimPileborg。我搜索這個問題,只找到edata,etext,結束。這就是爲什麼我在這裏尋求幫助。 – fanux

+1

@JoachimPileborg不是我的問題清楚嗎?我已閱讀相關文件並進行搜索。如果你不能回答,就走開。或者,我會感謝你。不要評價我或者問我爲什麼想知道它。那是愚蠢的 – fanux

回答

3

這取決於你的鏈接腳本。例如,在某些平臺上,您在BSS的開始處有符號__bss_start。這是一個沒有任何數據關聯的符號,你可以通過extern得到一個指向它的指針,聲明一個具有該名稱的變量(僅用於獲取該變量的地址)。例如:

#include <stdio.h> 

extern char __bss_start; 

int main() 
{ 
    printf("%p\n", &__bss_start); 

    return 0; 
} 

您在/usr/lib/ldscripts/elf_x64_64.x看在鏈接腳本,例如發現這一點:

.data   : 
{ 
    *(.data .data.* .gnu.linkonce.d.*) 
    SORT(CONSTRUCTORS) 
} 
.data1   : { *(.data1) } 
_edata = .; PROVIDE (edata = .); 
__bss_start = .; /* <<<<< this is what you're looking for /* 
.bss   : 
{ 
*(.dynbss) 
*(.bss .bss.* .gnu.linkonce.b.*) 
*(COMMON) 
/* Align here to ensure that the .bss section occupies space up to 
    _end. Align after .bss to ensure correct alignment even if the 
    .bss section disappears because there are no input sections. 
    FIXME: Why do we need it? When there is no .bss section, we don't 
    pad the .data section. */ 
. = ALIGN(. != 0 ? 64/8 : 1); 
} 

你也可以看到你所提到的edata,但edata不預留用於實施(PROVIDE的意思是隻有創建這個符號,否則不使用),你應該使用_edata來代替。

如果你想將地址data部分,您可以修改鏈接腳本的開始:

__data_start = . ; 
.data   : 
{ 
    *(.data .data.* .gnu.linkonce.d.*) 
    SORT(CONSTRUCTORS) 
} 
.data1   : { *(.data1) } 
_edata = .; PROVIDE (edata = .); 
__bss_start = .; /* <<<<< this is what you're looking for /* 
.bss   : 
{ 
*(.dynbss) 
*(.bss .bss.* .gnu.linkonce.b.*) 
*(COMMON) 
/* Align here to ensure that the .bss section occupies space up to 
    _end. Align after .bss to ensure correct alignment even if the 
    .bss section disappears because there are no input sections. 
    FIXME: Why do we need it? When there is no .bss section, we don't 
    pad the .data section. */ 
. = ALIGN(. != 0 ? 64/8 : 1); 
} 

你可能想使鏈接腳本的副本(在/usr/lib/ldscripts尋找合適的一個,它們是不同,這取決於什麼樣的你的目標輸出),並提供它,當你編譯:

gcc -o execfile source.c -Wl,-T ldscript 

,如果你不想修改鏈接腳本可以使用__executable_start的另一種選擇d解析ELF頭文件(希望可執行文件被線性映射)

至於_etext,它是text部分的結尾(您也可以在鏈接描述文件中閱讀它,但我沒有包含它在摘錄中),但text部分後面跟着rodata,試圖寫入可能會出現段錯誤。

+0

這真的有用! – fanux

+0

但我期望的是一個函數或變量或宏...謝謝 – fanux

+0

變量** __ data_start **和** data_start **可以直接**在程序中使用,而不用在ldscript中定義。它們都是初始化數據段的第一個地址,它們的值相同。他們的用法就像etext和edata。這可能只適用於使用gcc的Linux,因爲我沒有在其他編譯器和平臺上進行測試。 – fanux

0

您可以使用linux工具size(Debian/Ubuntu中的binutils軟件包)。

size -A /usr/bin/gcc 

結果

/usr/bin/gcc : 
section    size  addr 
.interp     28 4194928 
.note.ABI-tag   32 4194956 
.note.gnu.build-id  36 4194988 
.gnu.hash    240 4195024 
.dynsym    4008 4195264 
.dynstr    2093 4199272 
.gnu.version   334 4201366 
.gnu.version_r   160 4201704 
.rela.dyn    720 4201864 
.rela.plt    3240 4202584 
.init     14 4205824 
.plt     2176 4205840 
.text    384124 4208016 
.fini      9 4592140 
.rodata    303556 4592160 
.eh_frame_hdr   8540 4895716 
.eh_frame    50388 4904256 
.gcc_except_table  264 4954644 
.tbss     16 7052632 
.init_array    16 7052632 
.fini_array    8 7052648 
.jcr      8 7052656 
.data.rel.ro   3992 7052672 
.dynamic    480 7056664 
.got     216 7057144 
.got.plt    1104 7057384 
.data     2520 7058496 
.bss     80976 7061024 
.gnu_debuglink   12   0 
Total    849310