C 符号etext、edata和end在哪里定义?
这是Linux手册页中的代码:C 符号etext、edata和end在哪里定义?,c,gcc,linker,ld,C,Gcc,Linker,Ld,这是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 (ed
#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);
}
在哪里定义了
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);
}
#包括
#包括
#包括
int main(int argc,char*argv[])
{
printf(“程序文本(etext)%10p\n”,(void*)get_etext();
printf(“初始化数据(edata)%10p\n”,(void*)get_edata());
printf(“未初始化数据(结束)%10p\n”,(void*)get_end();
退出(退出成功);
}
GCC做什么
再扩大一点
这些符号由链接器脚本的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) }
因此,我们还发现:
和\uuuETEXT
也可以工作\uETEXT
不是etext
部分的结尾,而是.text
,其中也包含代码.fini
不在段的末尾,后面跟着etext
,因为Binutils将所有只读段转储到同一段中.rodata
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
部分开头的第一个字节
因此,通过控制该部分的第一个字节,我们可以控制退出状态
.链接404s:/
2