NASM手册讨论了这些宏,但据我所知,它并没有真正解释如何使用它们。第3.4.6节声明:
浮点常量只能作为
DB
、DW
、DD
、DQ
、DT
和DO
的参数,或者作为特殊运算符__?float8?__
、__?float16?__
、__?bfloat16?__
、__?float32?__
、__?float64?__
、__?float80m?__
、__?float80e?__
、__?float128l?__
和__?float128h?__
的参数
起初,我认为这是在数据部分之外使用浮点常量。但是当我尝试mov xmm0, __?float32?__(1.23)
时,我得到了一个"无效的操作码和操作数组合";错误。最终,我看到foo: dd __?float32?__(1.23)
是有效的。但我觉得这很奇怪;如果你可以直接做dd 1.23
,这些宏的意义是什么?一种可能是,例如,您需要在四字中定义一个单精度浮点数。这真的是这些宏的唯一用途吗,还是我用错了?
这些宏并没有改变x86没有直接源和XMM或x87目标指令的事实。请记住,NASM是一个汇编器,而不是编译器。
用例包括您想要立即将FP位模式移动到整数寄存器的罕见情况,如mov eax, __?float32?__(1.23)
。之后,您可以执行movd xmm0, eax
,甚至AVX-512vpbroadcastd xmm0, eax
。
通常编译器从内存中的常量中加载FP数据到寄存器中(这通常是一个很好的选择),但这不是唯一的方法。
(AVX-512使立即更有吸引力,因为有效的广播,但你也可以从内存广播只有AVX1,或SSE3movddup
的双。编译器仍然为标量浮点数使用内存常量,这仍然是我通常推荐的,除非分析显示大量的数据缓存丢失,并且通常在您的程序中没有很多I-cache丢失。
或者像if (x) *fp_ptr = 1.0;
这样的东西,你可能想要像mov dword [rdi], __?float32?__(1.0)
那样立即移动到内存中。
另一个用例可能是在NASM%if
条件汇编指令中,或者在您希望FP位模式作为不是dd
的整数值的其他情况下。尽管没有什么明智的想法。
或者作为表达式的一部分,如__?float32?__(1.0) >> 23
,以获得您想要使用的浮点常数的指数(和符号位)。
记录:
mov eax, __?float32?__(1.23)
mov eax, __?float32?__(1.0) >> 23
mov dword [rdi], __?float32?__(1.0)
用nasm -felf64 foo.asm
组装,用objdump -drwC -Mintel foo.o
拆卸
0: b8 a4 70 9d 3f mov eax,0x3f9d70a4
5: b8 7f 00 00 00 mov eax,0x7f
a: c7 07 00 00 80 3f mov DWORD PTR [rdi],0x3f800000
相关:- NASM:为什么__float32__(1.5)必须用于浮点量而不是1.5?- NASM对
dd
/dq
使用不同的解析器,在数字中看到.
意味着浮点数。这就是为什么dd 1.5
工作,mov eax, 1.5
不(尚未)。
旧的NASM文档__float32__(1.23)
;仍然可以组装,但是NASM手册目前只记录了这个答案中使用的?
表单。我认为这使得它不是一个有效的NASM预处理器宏/令牌,如果这是相关的。并且不是一个有效的符号名。