2015-11-03 162 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