x64汇编中如何传递浮点参数?代码输出异常问题排查
问题分析与修正方案
核心错误点
- 整数存储与浮点加载不匹配:你用
movq $7, -16(%rbp)把整数7存入内存,但fld -16(%rbp)是按双精度浮点数(double)格式加载数据。整数7的二进制0x0000000000000007作为double时,是一个极小的非规格化数(约8.47e-308),根本不是7.0,这直接导致后续浮点计算全错。 - 浮点除法操作顺序错误:
fld -16(%rbp)将x加载到st0,接着fld -8(%rbp)把y加载到st0(原x被挤到st1)。此时执行fdivp %st(1),实际是计算st1 = st0 / st1(即y/x),然后弹出st0,最终st0里是y/x的结果,但你想要的是x/y,顺序完全搞反了。 - printf调用约定错误:x86-64系统中,
printf的浮点数参数(对应%lf格式)需要通过XMM寄存器传递(第一个浮点参数放XMM0),而非通用寄存器RSI。同时必须设置%rax为传递的浮点参数个数(这里是1),否则printf无法正确识别参数。
修正后的代码
.section .data outfloatfmt: .asciz "%lf\n" .section .text .extern printf .global main main: pushq %rbp movq %rsp, %rbp subq $16, %rsp ; 正确存储双精度浮点数7.0和2.0到栈上 movabsq $0x401c000000000000, -16(%rbp) ; 7.0的double二进制表示 movabsq $0x4000000000000000, -8(%rbp) ; 2.0的double二进制表示 fld -16(%rbp) ; st0 = 7.0 fld -8(%rbp) ; st0 = 2.0, st1 = 7.0 fdivrp %st(1) ; st0 = st1 / st0 (7.0/2.0=3.5), 弹出st1 fstpl -16(%rsp) ; 将st0的3.5存入栈内存 movsd -16(%rsp), %xmm0 ; 把double加载到XMM0(printf的浮点参数寄存器) leaq outfloatfmt(%rip), %rdi ; 格式字符串地址入RDI movq $1, %rax ; 告诉printf有1个浮点参数在XMM寄存器 callq printf addq $16, %rsp movq %rbp, %rsp popq %rbp ret
额外优化说明
如果不想手动写double的二进制值,可以用.double伪指令直接定义浮点数,更直观:
.section .data outfloatfmt: .asciz "%lf\n" num7: .double 7.0 num2: .double 2.0
然后加载时直接用fld num7(%rip)和fld num2(%rip)即可。
内容的提问来源于stack exchange,提问作者TheSinisterStone
相关产品推荐
相关产品推荐

