x86 NASM 将 printf 用于压缩双打

x86 NASM use printf for packed doubles

我刚开始使用 SIMD 指令,正在尝试使用 printf 打印浮点数。我已经查看了许多可能的解决方案,但似乎这段代码在 运行 时不会打印任何内容。相关代码如下:

extern _printf

section .text
global _main

_main:
    ...
    movapd xmm0, oword [rel v1]
    movapd xmm1, oword [rel v2]
    addpd xmm0, xmm1
    movapd xmm1, xmm0
    psrldq xmm1, 8

    mov rax, 2
    mov rdi, fmt
    call _printf
    ...

section .data
fmt: db "%f %f\n", 0
v1: dq 1.1
    dq 2.2
v2: dq 3.3
    dq 4.4

我正在开发 mac,这是我用于 assemble 和 link 的命令:

nasm -g -f macho64 -o prog.o prog.asm
ld -lc -macosx_version_min 10.13 -lSystem -o prog prog.o

您可能没有刷新 stdio 缓冲区就退出了。默认情况下,stdout 在连接到终端时是行缓冲的(否则是全缓冲的)。

您的格式字符串不以换行符结尾:它以文字反斜杠和 n 结尾,因为 NASM 不处理 C双引号内的转义序列。为此使用反引号:

fmt: db `%f %f\n`, 0

或使用数字ASCII码fmt: db "%f %f", 10, 0


当您使用 C stdio 函数调用时,您应该通过从 main 返回或调用 libc 的 exit 函数退出,不是 通过直接进行 sys_exit 系统调用 。库函数首先刷新 stdio 缓冲区并运行析构函数和其他任何东西;系统调用刚刚退出。

我在这里假设您的程序正在干净地退出而不是在 printf 内部崩溃(如果 rspcall 之前不是 16 字节对齐,则可能会使用 movaps 将 FP arg 传递寄存器存储到堆栈,作为通常的可变参数函数代码生成的一部分。)

运行 你的程序在 straceltrace 下解码系统调用或库函数调用(如果 OS X 有这两种工具)。


您的原始代码(在更新以解决此问题之前)应该从 xmm0 打印低 double 并从堆栈中取出 8 个字节的数据用于第二次 %f 转换(因为 al=1 表示寄存器中有一个 FP arg,堆栈中有任何剩余的 FP arg。)

或者这就是它在您退出之前放入 stdout I/O 缓冲区的内容。


顺便说一句,不要忘记 ALIGN 16 您要使用对齐加载的数据。此外,您选择了一种低效的解包方式(此处不需要整数洗牌,如果您要进行整数洗牌,请使用 pshufd 进行复制+洗牌)。你可以这样做:

DEFAULT REL

...
movapd xmm0, [rel v1]
addpd  xmm0, [rel v2]
movhlps xmm1, xmm0         ; false dependency on the old value of xmm0

...
movapd    xmm1, xmm0    ; copy
unpckhpd  xmm1, xmm1    ; broadcast the high half

x86-64 System V 调用约定不要求 arg 传递寄存器的上半部分为零,包括 xmm regs,因此您可以留下任何您想要的高垃圾。 ()