对于以下代码:
#includeint 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 /链接器在.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
(注意我有一个不同的地址.)
更进一步,你可以在glibc中找到它的来源:
/* This records which stdio is linked against in the application. */ const int _IO_stdin_used = _G_IO_IO_FILE_VERSION;
和
#define _G_IO_IO_FILE_VERSION 0x20001
如果您考虑小端存储,则与您看到的值相对应.