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 内崩溃(如果 rsp
在 call
之前不是 16 字节对齐,则可能会使用 movaps
存储 FP arg - 将寄存器作为通常的可变参数函数代码生成的一部分传递到堆栈。)
在strace
或ltrace
下运行您的程序以解码系统调用或库函数调用(如果 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 程序集中立即数与方括号的基本使用