符号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
etext
, edata
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上 。