You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何printf打印浮点数时main函数需压入r4寄存器才可正常工作?

根本原因

这个现象和r4寄存器本身没有任何关系,本质是你违反了32位ARM平台的**AAPCS(ARM架构过程调用标准)**的强制要求:所有对外可见的函数在入口点,栈指针sp必须保持8字节对齐。

  • 程序启动进入main函数时,系统给的初始栈是天然满足8字节对齐的。
  • 你第一版代码只执行了push {lr},单寄存器压栈占4字节,直接把栈搞成了4字节对齐,不符合调用约定。
  • 为什么乱码恰好出现在浮点数打印?因为printf处理double类型时,内部实现会用到要求8字节对齐的浮点访存指令(比如vldr/vstr),或是直接在栈上存储double值,4字节对齐的栈会导致浮点值读取错位,把相邻内存的垃圾数据拼成浮点数输出,就是你看到的那串超长乱码数字。
  • 你修改后的版本压入了r4和lr两个寄存器,合计占8字节,压栈后栈偏移刚好是8的整数倍,误打误撞满足了8字节对齐要求,所以printf能正常运行。

你可以自己做验证:哪怕完全不操作r4寄存器,只要把栈调整到8字节对齐,程序一样能正常输出1.4,参考代码:

.global main
main:
    push {lr}
    sub sp, sp, #4  @ 额外预留4字节栈空间,凑够8字节偏移
    bl foo
    add sp, sp, #4
    mov r0, #0
    pop {pc}

GCC编译C代码生成的汇编不会出这个问题,是因为编译器默认严格遵守AAPCS约定,生成函数序言时会自动保证栈对齐,不会出现只压入1个4字节寄存器就发起子函数调用的写法。

内容的提问来源于stack exchange,提问作者Jonatan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 19:09:21