对于以下代码:
#include <stdio.h>
int main() {
printf("Hello World");
printf("Hello World1");
return 0;
}
生成的用于调用 printf 的程序集如下(64 位):
400474: be 24 06 40 00 mov esi,0x400624
400479: bf 01 00 00 00 mov edi,0x1
40047e: 31 c0 xor eax,eax
400480: e8 db ff ff ff call 400460 <__printf_chk@plt>
400485: be 30 06 40 00 mov esi,0x400630
40048a: bf 01 00 00 00 mov edi,0x1
40048f: 31 c0 xor eax,eax
400491: e8 ca ff ff ff call 400460 <__printf_chk@plt>
和.rodata 部分如下:
Contents of section .rodata:
400620 01000200 48656c6c 6f20576f 726c6400 ....Hello World.
400630 48656c6c 6f20576f 726c6431 00 Hello World1.
基于汇编代码,printf 的第一个调用具有地址 400624 的参数,该参数与.rodata 的开头有 4 个字节的偏移量。我知道它在这里跳过了这 4 个点前缀的前 4 个字节。但我的问题是为什么 GCC / linker 为.rodata 中的字符串产生这个前缀?我在 Ubuntu 14.04 上使用 4.8.4 GCC。编译 cmd 只是:gcc -Ofast my-source.c -o my-program
对于初学者来说,这些不是四个点,点只是表示不可打印的字符。您可以在十六进制转储中看到这些字节是01 00 02 00
。
最终程序包含链接器添加的其他目标文件,这些文件是 C 运行时库的一部分。
您可以看到地址是0x400620
。然后,您可以尝试找到一个匹配的符号,例如,您可以将其加载到gdb
中,然后使用info symbol
命令:
(gdb) info symbol 0x4005f8
_IO_stdin_used in section .rodata of /tmp/a.out
(注意我有一个不同的地址。)
更进一步,你可以找到source for this in glibc:
/* This records which stdio is linked against in the application. */
const int _IO_stdin_used = _G_IO_IO_FILE_VERSION;
and
#define _G_IO_IO_FILE_VERSION 0x20001
这对应于您在考虑 little-endian 存储时看到的值。
它确实不是前缀数据。.rodata
可以包含任何内容。前四个字节 [看似] 是一个字符串,但它恰好链接到那里 (即它是为了别的东西)。它与你的“Hello World”无关
本站系公益性非盈利分享网址,本文来自用户投稿,不代表边看边学立场,如若转载,请注明出处
评论列表(34条)