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

NASM x64程序提取浮点数小数部分错误显示0.000000求助

提取浮点数小数部分时输出0.0而非0.5的问题

问题描述

在Windows 10 x64环境下使用NASM编写汇编程序,意图提取并打印浮点数的小数部分,但程序输出Floating Point Part: 0.000000,而非预期的Floating Point Part: 0.500000。

原代码

section .data
    fmt db "Floating Point Part: %f", 10, 0
    float_value dq 10.5
    result dq 0.0

section .text
global main
extern printf

main:
    ; Function prologue
    push rbp
    mov rbp, rsp
    sub rsp, 32              ; Allocate shadow space

    ; Load floating-point value into the FPU
    fld qword [rel float_value]

    ; Call floatVal function
    call floatVal

    ; Store result from the FPU to memory
    fstp qword [rel result]

    ; Print the result using printf
    lea rcx, [rel fmt]       ; First argument: format string
    lea rdx, [rel result]    ; Second argument: address of result
    movsd xmm0, qword [rdx]  ; Move the double to xmm0 for printf
    call printf

    ; Function epilogue
    add rsp, 32              ; Deallocate shadow space
    mov eax, 0
    pop rbp
    ret

floatVal:
    ; Function prologue
    push rbp
    mov rbp, rsp
    sub rsp, 32              ; Allocate shadow space

    ; Get the integer part
    fld st0                  ; Copy the value to the top of the stack
    frndint                  ; Round to integer
    fsub                     ; Subtract integer part from original value (st0 - st1)

    ; Function epilogue
    add rsp, 32              ; Deallocate shadow space
    pop rbp
    ret

编译执行步骤

nasm -f win64 flo.asm -o flo.o
gcc -m64 -o flo flo.o -lkernel32 -lmsvcrt
.\flo.exe

预期与实际输出

  • 预期输出:
    Floating Point Part: 0.500000
    
  • 实际输出:
    Floating Point Part: 0.000000
    

环境

  • Windows 10 x64
  • NASM
  • Mingw-w64

已尝试操作

  • 确认浮点运算处理正确
  • 检查栈对齐与shadow space分配
  • 尝试直接打印完整浮点数以定位问题
  • 使用RIP相对寻址确保地址处理正确

疑问

  • 为何程序打印0.000000而非预期的小数部分?
  • 浮点处理或函数调用约定是否存在错误?
  • 如何正确打印浮点数的小数部分?

问题根源

代码存在两个关键错误:

  1. printf调用未设置eax寄存器:Windows x64调用约定中,调用printf这类可变参数函数时,必须在eax中指定通过XMM寄存器传递的浮点参数数量。原代码设置mov eax, 0,导致printf认为没有浮点参数,无法读取xmm0中的有效值,转而读取栈上的无效数据(表现为0.0)。
  2. FPU减法指令逻辑模糊:无操作数的fsub指令实际执行st1 = st1 - st0并弹出st0,虽能得到结果,但逻辑不够直观,且未明确维护FPU栈平衡。
  3. 多余的参数传递:调用printf时错误将rdx设为result的地址,%f参数已通过xmm0传递,该操作完全多余。

修正后的代码

section .data
    fmt db "Floating Point Part: %f", 10, 0
    float_value dq 10.5
    result dq 0.0

section .text
global main
extern printf

main:
    ; Function prologue
    push rbp
    mov rbp, rsp
    sub rsp, 32              ; Allocate shadow space

    ; Load floating-point value into the FPU
    fld qword [rel float_value]

    ; Call floatVal function
    call floatVal

    ; Store result from the FPU to memory
    fstp qword [rel result]

    ; Print the result using printf
    lea rcx, [rel fmt]       ; First argument: format string
    movsd xmm0, qword [rel result]  ; Move the double to xmm0 for printf
    mov eax, 1               ; 告知printf使用了1个XMM浮点参数
    call printf

    ; Function epilogue
    add rsp, 32              ; Deallocate shadow space
    mov eax, 0
    pop rbp
    ret

floatVal:
    ; Function prologue
    push rbp
    mov rbp, rsp

    ; Get the integer part
    fld st0                  ; Copy the value to the top of the stack
    frndint                  ; Round to integer
    fsubr st0, st1           ; st0 = st1 - st0 (原数 - 整数部分)
    fstp st1                 ; 弹出原数,栈顶保留小数部分

    ; Function epilogue
    pop rbp
    ret

修正说明

  1. printf调用修正:移除多余的lea rdx, [rel result],添加mov eax, 1告知printf使用了1个XMM浮点参数。
  2. FPU运算修正:使用fsubr st0, st1直接计算原数减整数部分,逻辑更清晰;用fstp st1清理FPU栈,确保函数返回时栈深度与进入时一致。
  3. 优化shadow space:floatVal函数未调用其他函数,无需分配shadow space,移除相关代码。

验证结果

使用原编译步骤重新执行,将得到预期输出:

Floating Point Part: 0.500000

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 06:37:06