这取决于您的链接器脚本。例如,在某些平台上,您在 BSS 的开头有符号 __bss_start。它是一个没有任何数据关联的符号,您可以通过extern 声明一个具有该名称的变量来获得指向它的指针(仅用于获取该变量的地址)。例如:
#include <stdio.h>
extern char __bss_start;
int main()
{
printf("%p\n", &__bss_start);
return 0;
}
您可以通过查看链接描述文件找到它,例如在/usr/lib/ldscripts/elf_x64_64.x:
.data :
{
*(.data .data.* .gnu.linkonce.d.*)
SORT(CONSTRUCTORS)
}
.data1 : { *(.data1) }
_edata = .; PROVIDE (edata = .);
__bss_start = .; /* <<<<< this is what you're looking for /*
.bss :
{
*(.dynbss)
*(.bss .bss.* .gnu.linkonce.b.*)
*(COMMON)
/* Align here to ensure that the .bss section occupies space up to
_end. Align after .bss to ensure correct alignment even if the
.bss section disappears because there are no input sections.
FIXME: Why do we need it? When there is no .bss section, we don't
pad the .data section. */
. = ALIGN(. != 0 ? 64 / 8 : 1);
}
您还可以看到您提到的edata,但由于edata 不是为实现保留的(PROVIDE 表示仅在未使用时创建此符号)您可能应该使用@987654329 @ 代替。
如果您希望地址位于data 部分的开头,您可以修改链接描述文件:
__data_start = . ;
.data :
{
*(.data .data.* .gnu.linkonce.d.*)
SORT(CONSTRUCTORS)
}
.data1 : { *(.data1) }
_edata = .; PROVIDE (edata = .);
__bss_start = .; /* <<<<< this is what you're looking for /*
.bss :
{
*(.dynbss)
*(.bss .bss.* .gnu.linkonce.b.*)
*(COMMON)
/* Align here to ensure that the .bss section occupies space up to
_end. Align after .bss to ensure correct alignment even if the
.bss section disappears because there are no input sections.
FIXME: Why do we need it? When there is no .bss section, we don't
pad the .data section. */
. = ALIGN(. != 0 ? 64 / 8 : 1);
}
您可能想要制作链接描述文件的副本(在/usr/lib/ldscripts 中查找正确的链接描述文件,它们会根据您所针对的输出类型而有所不同)并在编译时提供:
gcc -o execfile source.c -Wl,-T ldscript
如果您不想修改链接描述文件,另一种选择是使用 __executable_start 并解析 ELF 标头(希望可执行文件充分线性映射)
至于_etext,它是text 部分的结尾(您也可以在链接描述文件中阅读,但我没有在摘录中包含它),但text 部分是后跟rodata,尝试在那里写可能会出现段错误。