C 如何获取初始化数据段的第一个地址
我的程序使用gcc在linux上运行。通过手册页面,我找到了edata,它表示初始化数据段的第一个地址过去的结束的。C 如何获取初始化数据段的第一个地址,c,linux,C,Linux,我的程序使用gcc在linux上运行。通过手册页面,我找到了edata,它表示初始化数据段的第一个地址过去的结束的。 但是我想知道初始化数据段的第一个地址 我怎样才能得到它 我尝试将etext作为初始化数据段的第一个地址。然后,当我增加地址并访问其中存储的变量时,我得到了一个段错误。我认为etext和edata之间的一些地址空间没有映射到虚拟内存中。是吗?您可以使用linux工具size(Debian/Ubuntu中的binutils包) 范例 size -A /usr/bin/gcc 导致
但是我想知道初始化数据段的第一个地址 我怎样才能得到它
我尝试将etext作为初始化数据段的第一个地址。然后,当我增加地址并访问其中存储的变量时,我得到了一个段错误。我认为etext和edata之间的一些地址空间没有映射到虚拟内存中。是吗?您可以使用linux工具
size
(Debian/Ubuntu中的binutils包)
范例
size -A /usr/bin/gcc
导致
/usr/bin/gcc :
section size addr
.interp 28 4194928
.note.ABI-tag 32 4194956
.note.gnu.build-id 36 4194988
.gnu.hash 240 4195024
.dynsym 4008 4195264
.dynstr 2093 4199272
.gnu.version 334 4201366
.gnu.version_r 160 4201704
.rela.dyn 720 4201864
.rela.plt 3240 4202584
.init 14 4205824
.plt 2176 4205840
.text 384124 4208016
.fini 9 4592140
.rodata 303556 4592160
.eh_frame_hdr 8540 4895716
.eh_frame 50388 4904256
.gcc_except_table 264 4954644
.tbss 16 7052632
.init_array 16 7052632
.fini_array 8 7052648
.jcr 8 7052656
.data.rel.ro 3992 7052672
.dynamic 480 7056664
.got 216 7057144
.got.plt 1104 7057384
.data 2520 7058496
.bss 80976 7061024
.gnu_debuglink 12 0
Total 849310
这取决于链接器脚本。例如,在某些平台上,在bss的开头有符号
\u\u bss\u start
。它是一个没有任何相关数据的符号,您可以通过extern
声明具有该名称的变量(仅为了获取该变量的地址)来获取指向它的指针。例如:
#include <stdio.h>
extern char __bss_start;
int main()
{
printf("%p\n", &__bss_start);
return 0;
}
您还可以看到您提到的edata
,但由于edata
不是为实现保留的(如果没有使用PROVIDE
则仅表示创建此符号),您可能应该改用\u edata
如果希望地址位于数据
部分的开头,可以修改链接器脚本:
__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);
}
如果您不想修改链接器脚本,另一个选项是使用\uuuu executable\u start
并解析ELF头(希望可执行文件充分线性映射)
至于
\u etext
,它是文本
部分的结尾(你也可以在链接器脚本中阅读,但我没有将其包含在摘录中),但是文本
部分后面紧跟着rodata
,试图在那里写可能会出错。你如何找到edata
?您不能使用相同的技术来查找数据
?为什么不直接读取二进制文件并找到数据
段呢?但我最好奇的是你为什么需要它?您试图解决的原始问题是什么?(相关阅读:)@JoachimPileborg。我搜索这个问题,只找到了edata,etext,end。这就是我在这里寻求帮助的原因。@JoachimPileborg我的问题还不清楚吗?我已经阅读了相关文件并进行了搜索。如果你不能回答,就走开。或者,我会感谢你。不要评判我,也不要问我为什么想知道。这是愚蠢的。我猜数据段从etext
之后的下一页边界开始,至少它是根据链接器脚本开始的。@fanux-我们只是好奇您是否找到了使用该信息的方法。Joachim和我显然没有。但我期望的是一个函数、一个变量或一个宏。。。谢谢,变量uu data_start和data_start可以直接在程序中使用,无需在ldscript中定义。它们都是初始化数据段的第一个地址,并且它们的值相同。它们的用法与etext和edata一样。这可能只适用于使用gcc的Linux,因为我没有在其他编译器和平台上测试它。@fanux看起来这些符号来自链接器脚本以外的其他地方。它实际上取决于节如何组合以形成可执行文件中的数据节,\uu data\u start
是crt0.o
节中的第一个,这使得它位于可执行文件的数据节的第一位。无论如何,任何这样的特性都依赖于正在使用的编译器/链接器-如果要使用另一个编译器/链接器,则必须研究如何执行此操作。
__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);
}
gcc -o execfile source.c -Wl,-T ldscript