.rodata 部分的前 16 个字节是什么?

逆向工程 C++ 小精灵 编译器
2021-06-23 02:57:43

.rodata部分的前 16 个字节是什么?

例如,我有以下代码:

#include <cstdio>

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

int main() {
        myprintf("hello world");
        myprintf("\0\0");
        myprintf("ab\0cde");
        static char hi[] = "hi";
        myprintf(hi);
}

我编译:

$ 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

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

1个回答

试图提供一个更一般的答案,希望能补充评论中链接的这个答案。

对于那些不确定的人来说,.rodata可执行文件中部分包含所有具有全局作用域的只读变量和常量(即将在程序执行的整个持续时间内定义),尽管线条变得有点模糊并且有例外没有实际执行的规则,该.rodata部分通常保存所有只读的全局和静态变量。这显然是您定义的字符串存在的原因。

尽管您的代码除了少数字符串文字之外没有直接定义任何构造,但该.rodata部分将保存编译器和链接器视为全局范围只读的所有数据,无论它是在您的代码中定义还是在您的附加变量/对象中定义程序显式或隐式使用。

现在回答你的问题;我提到可以在您的代码中显式和隐式定义其他对象,而无需您实际编写它们。一个明确的例子是#include你程序中的所有代码cstdio在这种情况下)。隐含在你的程序中的代码是,例如,GCC 添加的代码,它包装和调用你定义的main函数并处理不同的操作系统接口(设置与 stdin、stderr、stdout 相关的函数)以及设置和拆卸程序对象(该代码是通过在 C++ 中调用其构造函数来初始化全局范围对象的地方)。

尽管在链接的答案中对此进行了深入解释,但实际值(12)似乎是针对 GCC 定义的常量init.c

const int _IO_stdin_used = 0x20001;

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

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

您的示例与SO 问题中的示例之间值得一提的差异是 14 个零字节,这些字节当然填充到 16 个字节的边界,这是编译器经常为优化执行时间而做的事情。替换-O3with -Os(优化大小)可能会删除 14 个空字节,尽管这不能保证并且可能取决于您使用的 GCC 版本。