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

Apple Silicon M1上NASM x86_64代码输出0.0而非正确浮点结果的问题

在Apple Silicon M1上正确编写调用printf传递双精度参数的NASM汇编程序

问题背景

在Apple Silicon M1的macOS上编写x86_64架构的NASM汇编程序,计算0.1+0.2的双精度浮点和并通过printf打印,但运行后输出0.1 + 0.2 = 0.000000,同时收到链接器警告ld: warning: no platform load command found in 'main.o', assuming: macOS。

原代码

section .data
    fmt db "0.1 + 0.2 = %f", 10, 0
    num1 dq 0.1
    num2 dq 0.2
    result dq 0.0

section .text
    extern _printf
    global _main

_main:
    fld qword [rel num1]
    fadd qword [rel num2]
    fstp qword [rel result]

    lea rdi, [rel fmt]
    movsd xmm0, [rel result]
    xor eax, eax
    call _printf

    ret

原编译链接命令

nasm -f macho64 main.asm -o main.o
clang -arch x86_64 main.o -o main
./main

LLDB调试信息

(lldb) breakpoint set --name main
Breakpoint 2: where = float_bug`main, address = 0x0000000100000f6f
(lldb) run
Process 31221 launched: '/Users/dmitroparhomenko/FlowyROS/float_bug' (x86_64)
warning: libobjc.A.dylib is being read from process memory. This indicates that LLDB could not read from the host's in-memory shared cache. This will likely reduce debugging performance.

Process 31221 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 2.1
    frame #0: 0x0000000100000f6f float_bug`main
float_bug`main:
->  0x100000f6f <+0>:  movsd  0x1099(%rip), %xmm0 ; num1, xmm0 = mem[0],zero 
    0x100000f77 <+8>:  movsd  0x1099(%rip), %xmm1 ; num2, xmm1 = mem[0],zero 
    0x100000f7f <+16>: addsd  %xmm1, %xmm0
    0x100000f83 <+20>: movsd  %xmm0, 0x1095(%rip) ; result
Target 0: (float_bug) stopped.
(lldb) register read xmm0
    xmm0 = {0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}
(lldb) expr *(double*)&$xmm0
(double) $0 = 0

问题分析

  1. printf参数传递错误:x86_64的System V ABI(macOS遵循该规范)中,调用printf这类变参函数时,若有浮点参数通过XMM寄存器传递,必须在eax中设置传递的浮点参数数量。原代码中xor eax, eax表示没有浮点参数,导致printf忽略xmm0中的值,输出0.0。
  2. 链接器警告:NASM的macho64输出格式默认不添加平台加载命令,clang链接时会自动补全,警告本身不影响功能,但可通过指定NASM参数消除。

解决方案

方案1:修复x86_64版本代码

修改代码中调用printf前的eax设置,同时添加NASM参数消除链接警告:

修复后的代码

section .data
    fmt db "0.1 + 0.2 = %f", 10, 0
    num1 dq 0.1
    num2 dq 0.2
    result dq 0.0

section .text
    extern _printf
    global _main

_main:
    fld qword [rel num1]
    fadd qword [rel num2]
    fstp qword [rel result]

    lea rdi, [rel fmt]
    movsd xmm0, [rel result]
    mov eax, 1  ; 告知printf有1个浮点参数在XMM寄存器中
    call _printf

    ret

编译链接命令(消除警告)

nasm -f macho64 -DMACOS main.asm -o main.o  ; -DMACOS让NASM添加平台加载命令
clang -arch x86_64 main.o -o main
./main

运行后会正确输出(因浮点精度,实际显示类似0.30000000000000004):

0.1 + 0.2 = 0.300000

方案2:编译为ARM64架构(原生运行,无需Rosetta)

若想直接在M1上以原生ARM64运行,需编写ARM64版本的NASM代码,并使用对应编译命令:

ARM64版本代码

section .data
    fmt db "0.1 + 0.2 = %f", 10, 0
    num1 dq 0.1
    num2 dq 0.2

section .text
    extern _printf
    global _main

_main:
    ; 保存栈帧
    stp x29, x30, [sp, -16]!
    mov x29, sp

    ; 加载浮点数并相加
    ldr d0, [rel num1]
    ldr d1, [rel num2]
    fadd d0, d0, d1

    ; 调用printf:第一个参数x0是格式字符串,d0是浮点参数
    adrp x0, fmt
    add x0, x0, :lo12:fmt
    bl _printf

    ; 恢复栈帧并返回
    ldp x29, x30, [sp], 16
    ret

编译链接命令

nasm -f macho64 main.asm -o main.o  ; ARM64的macho64格式
clang main.o -o main  ; 默认编译为ARM64
./main

关键说明

  • x86_64的System V ABI要求:调用变参函数时,必须用eax声明传递到XMM寄存器的浮点参数数量。
  • ARM64的macOS ABI中,浮点参数通过d0-d7寄存器传递,变参函数无需额外声明数量,直接传递即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.12 22:00:17