x86 NASM 使用 printf 打包双打

Posted

技术标签:

【中文标题】x86 NASM 使用 printf 打包双打【英文标题】:x86 NASM use printf for packed doubles 【发布时间】:2017-12-24 00:20:57 【问题描述】:

我是使用 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,这里是我用来组装和链接的命令:

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

【问题讨论】:

你检查了调用约定吗?为什么你期望printf 从 xmm0 读取两个双精度数? 我不确定,但怀疑我只是在一个寄存器 (xmm0) 中传递浮点数。您是否建议将一个浮点数放入 xmm1 并将 2 个放入 rax? 是的。 x86-64 System V 调用约定不会将单独的 FP args 打包到一个向量寄存器中。顺便说一句,您打印的是double,而不是float。 printf 没有为 float 转换,因为 C 调用者永远不能在没有提升到 double 的情况下传递一个。 我将其更改为在两个寄存器中传递它们并编辑了问题中的代码,但是程序仍然没有打印任何内容。另外,我知道我正在打印双打,我只是在使用惰性术语 别偷懒了;根据您的问题标题,我期待 ***.com/questions/37082784/… 的副本。 【参考方案1】:

您可能会在未刷新 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 参数都在堆栈中。)

或者这就是它在您退出之前放入 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 调用约定不要求传递参数的寄存器的上半部分为零,包括 xmm regs,因此您可以留下任何您想要的高垃圾。 (Caveat for integer regs for compat with clang)

【讨论】:

以上是关于x86 NASM 使用 printf 打包双打的主要内容,如果未能解决你的问题,请参考以下文章

使用 div 指令的 x86 NASM 程序集中的浮点异常 [重复]

YASM/NASM x86 程序集中立即数与方括号的基本使用

YASM/NASM x86 程序集中立即数与方括号的基本使用

拼命尝试使用 wprintf 在 64 位 NASM x86 程序集中打印 unicode

assembly x86(nasm)的日常

assembly x86(nasm)选择排序