x86-64平台下GCC中"%d\n"格式字符串如何存储及传给printf?
关于x86-64下printf字符串参数传递的疑问
调试的C程序
#include <stdio.h> #include <stdlib.h> int main() { int a = 12; printf("%d\n", a); }
对应的汇编代码
0x0000000000001139 <+0>: push rbp 0x000000000000113a <+1>: mov rbp,rsp 0x000000000000113d <+4>: sub rsp,0x10 0x0000000000001141 <+8>: mov DWORD PTR [rbp-0x4],0xc 0x0000000000001148 <+15>: mov eax,DWORD PTR [rbp-0x4] 0x000000000000114b <+18>: mov esi,eax 0x000000000000114d <+20>: lea rax,[rip+0xeb0] # 0x2004 0x0000000000001154 <+27>: mov rdi,rax 0x0000000000001157 <+30>: mov eax,0x0 0x000000000000115c <+35>: call 0x1030 <printf@plt> 0x0000000000001161 <+40>: mov eax,0x0 0x0000000000001166 <+45>: leave 0x0000000000001167 <+46>: ret
疑问与解答
你对变量a的传递逻辑理解正确,而"%d\n"字符串并未存储在栈中,rdi寄存器里存放的是这个字符串在内存中的地址,它指向程序的只读数据段(.rodata)——这是编译阶段就确定的、专门存放常量字符串等只读数据的内存区域。
核心看这两行汇编指令:
lea rax,[rip+0xeb0]:通过RIP相对寻址计算出字符串的绝对内存地址,注释里的# 0x2004就是最终计算得到的地址值。mov rdi,rax:将这个地址赋值给rdi,完全符合x86-64调用约定中第一个参数用rdi传递的规则。
采用RIP相对寻址是因为x86-64程序默认是位置无关代码(PIC),这样程序加载到任意内存地址时,都能通过当前指令地址(RIP)的偏移量找到目标字符串的位置。
你可以在GDB中执行x/s 0x2004,直接查看该地址存储的内容,就能看到"%d\n"字符串。
内容的提问来源于stack exchange,提问作者koiboi
相关产品推荐
相关产品推荐

