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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 14:10:16