Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/57.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 符号etext、edata和end在哪里定义?_C_Gcc_Linker_Ld - Fatal编程技术网

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

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

这是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);
}

在哪里定义了
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
    不在段的末尾,后面跟着
    .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
部分开头的第一个字节

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


.

链接404s:/
 2