符号etext,edata和end定义在哪里?

这是来自Linux手册页的代码:

#include  #include  extern char etext, edata, end; int main() { printf("First address past:\n"); printf(" program text (etext) %10p\n", &etext); printf(" initialized data (edata) %10p\n", &edata); printf(" uninitialized data (end) %10p\n", &end); exit(EXIT_SUCCESS); } 

运行时,下面的程序产生如下输出:

 $ ./a.out First address past: program text (etext) 0x8048568 initialized data (edata) 0x804a01c uninitialized data (end) 0x804a024 

etextedata end定义在哪里? 如何为这些符号赋值? 是通过链接器还是别的什么?

这些符号在链接描述文件中定义。

请注意,在Mac OS X上,上面的代码可能无效! 相反,你可以:

 #include  #include  #include  int main(int argc, char *argv[]) { printf(" program text (etext) %10p\n", (void*)get_etext()); printf(" initialized data (edata) %10p\n", (void*)get_edata()); printf(" uninitialized data (end) %10p\n", (void*)get_end()); exit(EXIT_SUCCESS); } 

这些符号对应于各种程序段的开头。 它们由链接器设置。

GCC的作用

扩大kgiannakakis更多。

这些符号由链接描述文件的PROVIDE关键字定义,记录在https://sourceware.org/binutils/docs-2.25/ld/PROVIDE.html#PROVIDE

构建Binutils时会生成默认脚本,并嵌入到ld可执行文件中:默认情况下不使用可能安装在您的发行版中的外部文件,如/usr/lib/ldscripts

回显要使用的链接描述文件:

 ld -verbose | less 

在binutils 2.24中,它包含:

 .text : { *(.text.unlikely .text.*_unlikely .text.unlikely.*) *(.text.exit .text.exit.*) *(.text.startup .text.startup.*) *(.text.hot .text.hot.*) *(.text .stub .text.* .gnu.linkonce.t.*) /* .gnu.warning sections are handled specially by elf32.em. */ *(.gnu.warning) } .fini : { KEEP (*(SORT_NONE(.fini))) } PROVIDE (__etext = .); PROVIDE (_etext = .); PROVIDE (etext = .); .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } .rodata1 : { *(.rodata1) } 

所以我们也发现:

  • __etext_etext也可以
  • etext不是.text部分的结尾,而是.fini ,它也包含代码
  • etext不在段的末尾,随后是.rodata ,因为Binutils将所有只读段转储到同一段中

PROVIDE生成弱符号:如果您还在C代码中定义了这些符号,您的定义将获胜并隐藏此符号。

最小的Linux 32位示例

为了真正理解事物的运作方式,我想创建最少的例子!

main.S

 .section .text /* Exit system call. */ mov $1, %eax /* Exit status. */ mov sdata, %ebx int $0x80 .section .data .byte 2 

link.ld

 SECTIONS { . = 0x400000; .text : { *(.text) sdata = .; *(.data) } } 

编译并运行:

 gas --32 -o main.o main.S ld -m elf_i386 -o main -T link.ld main.o ./main echo $? 

输出:

  2 

说明: sdata指向sdata.data节开头的第一个字节。

因此,通过控制该部分的第一个字节,我们控制退出状态!

这个例子在GitHub上 。