基于vcmpsd指令结果实现分支跳转的方法及异常排查
基于vcmpsd结果实现分支跳转的问题解决
问题代码与现象
你编写的NASM汇编代码如下:
vpxor xmm3,xmm3,xmm3 vmovsd xmm0,[rdi+rcx] vmovsd xmm1,[rsi+rcx] vsubsd xmm2,xmm0,xmm1 vcmpsd xmm4,xmm2,xmm3,0 je c_this c_not_this: mov rax,0 c_this: mov rax,0
测试中两个double数值相等,相减后xmm2结果为0,但执行vcmpsd后,xmm4的内容为:
(gdb) p $xmm4.v2_double $3 = {-nan(0xfffffffffffff), 0}
je指令并未跳转到c_this标签,因为vcmpsd不影响EFLAGS标志位,je依赖的ZF标志并未被该指令修改。
问题原因
vcmpsd是SIMD浮点比较指令,它的执行结果是将每个64位元素的比较结果以掩码形式写入目标XMM寄存器(比较成立则对应64位元素设为全1,否则设为全0),而非修改EFLAGS标志位。因此直接使用依赖标志位的条件跳转指令(如je)无法识别vcmpsd的比较结果。
你看到的-nan是因为:当比较成立时,对应64位元素被设为全1,而全1的64位符合double类型的NaN编码规则(符号位1、指数位全1、尾数位非0),所以gdb解析为NaN;未比较成立的元素则为0。
解决方法
方法1:通过vpmovmskb转换掩码为标志位
使用vpmovmskb指令将XMM寄存器中的掩码转换为通用寄存器的位,再通过位测试指令设置标志位,进而实现跳转:
vpxor xmm3,xmm3,xmm3 vmovsd xmm0,[rdi+rcx] vmovsd xmm1,[rsi+rcx] vsubsd xmm2,xmm0,xmm1 ; 比较xmm2与xmm3的低64位double,相等则xmm4的低64位设为全1 vcmpsd xmm4,xmm2,xmm3,0 ; 将xmm4每个字节的最高位提取到eax的对应位,低字节最高位为1则eax第0位为1 vpmovmskb eax,xmm4 ; 测试第0位是否为1(即低64位比较是否相等) test al,1 ; 若为0(不相等)则跳转到c_not_this,否则执行c_this jz c_not_this c_this: mov rax,0 jmp end_label c_not_this: mov rax,0 end_label:
方法2:改用影响标志位的浮点比较指令
如果仅需比较单个double数值,直接使用vucomisd或vcomisd指令,它们会直接修改EFLAGS标志位,可配合常规条件跳转指令使用:
vpxor xmm3,xmm3,xmm3 vmovsd xmm0,[rdi+rcx] vmovsd xmm1,[rsi+rcx] vsubsd xmm2,xmm0,xmm1 ; 比较xmm2与xmm3,设置EFLAGS的ZF/PF/CF标志 vucomisd xmm2,xmm3 ; 相等时ZF置1,触发je跳转至c_this je c_this c_not_this: mov rax,0 c_this: mov rax,0
vucomisd:无符号比较,忽略NaN的特殊情况vcomisd:有符号比较,会处理NaN的场景(若任一操作数为NaN,会设置相应标志)
内容的提问来源于stack exchange,提问作者RTC222
相关产品推荐
相关产品推荐

