.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 ++调用其构造函数来初始化全局范围内的对象的地方。)尽管在链接的答案中对此进行了深入说明,但实际值(main
和1
)似乎适用于由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
评论
堆栈溢出可能重复。