符号 etext 、 edata 和 end 是在哪里定义的?
题
这是 Linux 手册页中的代码:
#include <stdio.h>
#include <stdlib.h>
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 <stdio.h>
#include <stdlib.h>
#include <mach-o/getsect.h>
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);
}
这些符号对应于各种节目段的开始。它们是由链接器设置。
海湾合作委员会做什么
扩展 克吉安纳卡基斯 多一点。
这些符号的定义是 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
指向开始的第一个字节 .data
以下部分。
因此,通过控制该部分的第一个字节,我们可以控制退出状态!
不隶属于 StackOverflow