.rodata部分的前16个字节是什么?例如,我有以下代码:

#include <cstdio>

void myprintf(const char* ptr) {
        printf("%p\n", ptr);
}

int main() {
        myprintf("hello world");
        myprintf("
$ g++ -Wall test_elf.cpp -o test_elf -O3 -std=c++17
$ readelf -W -p .rodata test_elf 

String dump of section '.rodata':
  [    10]  %p^J
  [    14]  hello world
  [    23]  ab
  [    26]  cde
"); myprintf("abq4312078qcde"); static char hi[] = "hi"; myprintf(hi); }


我编译了:

q4312078q

然后

q4312078q

如您所见,第一个常量字符串常量之前有16个字节。我使用elf.h进行解析,并且我还看到第一个常量字符串文字之前有16个字节。其中的14个字节仅为零。 1个非零字节是1。另一个是2

评论

堆栈溢出可能重复。

#1 楼

试图提供一个更通用的答案,希望能补充注释中链接的答案。

对于那些不确定的人,可执行文件中的.rodata部分包含具有全局范围的所有只读变量和常量(即将在程序执行的整个过程中进行定义),尽管行变得有点模糊,并且规则并未实际执行,但.rodata节通常包含所有只读的全局和静态变量。很明显,这就是您定义的字符串在那里的原因。编译器和链接器,无论它是在代码中定义的还是程序在显式或隐式使用的其他变量/对象中定义的。

我提到了可以在代码中显式和隐式定义其他对象,而无需实际编写它们。一个明确的示例是程序中所有的代码.rodata(在这种情况下为#include)。例如,隐式包含在程序中的代码是GCC添加的代码,该代码包装并调用您定义的cstdio函数并处理不同的操作系统接口(设置与stdin,stderr,stdout相关的函数)以及设置和拆卸程序对象(该代码是通过C ++调用其构造函数来初始化全局范围内的对象的地方。)尽管在链接的答案中对此进行了深入说明,但实际值(main1)似乎适用于由GCC 2定义的常量:

const int _IO_stdin_used = 0x20001;


该文件是上述GCC初始化代码的一部分,用于控制GCC实现输入的输入/输出库的版本/输出在程序中。

值得注意的是,十六进制转储将帮助您增加信心,这是否确实是您看到额外字节的原因,以及遵循编译和链接过程的原因,当然

值得一提的是在您的示例与SO问题中的示例之间是否要提到14个零字节,这些字节当然填充到16个字节的边界,这是编译器经常为优化执行时间而做的。将init.c替换为-O3(针对大小进行优化)可能会丢弃14个空字节,但这不能保证,并且可能取决于您使用的GCC版本。

评论


不,不是。

–user202729
18年8月23日0:36

是的,我明确表示那只是我的假设。感谢您进行测试。

– NirIzr
18年8月23日在0:43

感谢您在其他帖子中扩展答案。只是一个附带的问题-是否可以以编程方式(例如,使用elf.h解析)确定给定的虚拟内存地址/偏移量是字符串文字而不是其他常量?谢谢!

–HCSF
18年8月23日在1:53

这个问题可能听起来并不那么简单,而且与编程相比,还涉及逆向工程更多,我建议您在stackoverflow.com上打开一个新问题。

– NirIzr
18年8月23日在1:58