printf函数参数传递机制及对应ARM64汇编指令解析咨询
ARM64汇编中printf相关指令疑问解答
原C程序
void f() { int i, x = 0; for (i = 0; i < 10; i++) x++; printf("Value of x: %d\n", x); }
对应ARM64汇编代码
00000000000007d4 <f>: 7d4: a9be7bfd stp x29, x30, [sp, #-32]! 7d8: 910003fd mov x29, sp 7dc: b9001fff str wzr, [sp, #28] 7e0: b9001bff str wzr, [sp, #24] 7e4: 14000007 b 800 <f+0x2c> 7e8: b9401fe0 ldr w0, [sp, #28] 7ec: 11000400 add w0, w0, #0x1 7f0: b9001fe0 str w0, [sp, #28] 7f4: b9401be0 ldr w0, [sp, #24] 7f8: 11000400 add w0, w0, #0x1 7fc: b9001be0 str w0, [sp, #24] 800: b9401be0 ldr w0, [sp, #24] 804: 7100241f cmp w0, #0x9 808: 54ffff0d b.le 7e8 <f+0x14> 80c: b9401fe1 ldr w1, [sp, #28] 810: 90000000 adrp x0, 0 <__abi_tag-0x278> 814: 9121c000 add x0, x0, #0x870 818: 97ffff9a bl 680 <printf@plt> 81c: d503201f nop 820: a8c27bfd ldp x29, x30, [sp], #32 824: d65f03c0 ret
疑问解答
1. add x0, x0, #0x870 的作用
ARM64的adrp指令会把目标地址所在4KB页面的起始地址加载到x0中,而add x0, x0, #0x870是在这个页面基地址的基础上加上偏移量0x870,最终得到的就是字符串"Value of x: %d\n"在内存中的实际地址。
2. 818行指令 bl 680 <printf@plt> 的含义
bl是带链接的分支指令:执行时会把当前指令的下一条地址(返回地址)保存到x30(链接寄存器),然后跳转到0x680地址处执行。<printf@plt>表示这是**过程链接表(PLT)**中的printf入口。PLT是动态链接的机制,用来处理对外部库函数(比如libc里的printf)的调用,程序运行时会通过PLT找到printf的实际地址并执行。
3. printf函数的参数传递规则
ARM64遵循AAPCS64(ARM 64位架构过程调用标准):
- 前8个整数/指针参数用
x0-x7寄存器传递,浮点参数用d0-d7传递,超出的参数才会放到栈上。 - 对于
printf("Value of x: %d\n", x):- 第一个参数(格式字符串的地址)通过
x0传递,也就是前面adrp+add指令计算出的地址; - 第二个参数(变量x的值)通过
w1传递(x是int类型,用32位寄存器w1,对应64位x1的低32位),也就是80c行ldr w1, [sp, #28]把栈上的x值加载到w1中。
- 第一个参数(格式字符串的地址)通过
4. 为什么汇编中看不到字符串"Value of x: %d\n"?
字符串属于程序的只读数据段(.rodata),你看到的汇编是函数f所在的代码段(.text)内容,汇编器不会把只读数据直接放到代码段里,只会通过地址引用它——前面的adrp+add就是在计算这个字符串的地址。如果查看程序的只读数据段,就能找到该字符串的二进制内容。
内容的提问来源于stack exchange,提问作者JaytheInj
相关产品推荐
相关产品推荐

