Intel XMM寄存器加载与乘法操作异常问题求助
问题:XMM寄存器浮点乘法测试异常分析
我编写了以下汇编程序测试XMM寄存器的数据乘法功能:
# file: xmm.a .global _start: _start: movsd (%rip), %xmm4 movsd -8(%rip), %xmm7 mulsd %xmm4, %xmm7 jmp _start
使用as xmm.a -o xmm.o汇编、ld xmm.o -o xmm链接后,通过gdb --args ./xmm调试_start函数,得到如下输出:
该程序应直接将16字节代码数据加载至xmm4和xmm7寄存器并执行乘法,但实际未按预期工作。
我的系统是基于Intel i7处理器的Windows Subsystem for Linux(Ubuntu 20.04.6 LTS)。
(gdb) disassemble /r _start Dump of assembler code for function _start: 0x00401000 <+0>: f2 0f 10 25 00 00 00 00 movsd 0x0(%rip),%xmm4 0x00401008 <+8>: f2 0f 10 3d f8 ff ff ff movsd -0x8(%rip),%xmm7 <_start+8> 0x00401010 <+16>: f2 0f 59 fc mulsd %xmm4,%xmm7 => 0x401014 <+20>: eb ea jmp 0x401000 <_start> End of assembler dump. (gdb) x/8i _start-8 0x400ff8: add %al,(%rax) 0x400ffa: add %al,(%rax) 0x400ffc: add %al,(%rax) 0x400ffe: add %al,(%rax) 0x401000 <_start>: movsd 0x0(%rip),%xmm4 0x401008 <_start+8>: movsd -0x8(%rip),%xmm7 0x401010 <_start+16>: mulsd %xmm4,%xmm7 => 0x401014 <_start+20>: jmp 0x401000 <_start> (gdb) print $xmm4 $3 = {v4_float = {2.38630424e-29, -nan(0x783d10), 0, 0}, v2_double = {-nan(0x83d100ff20000), 0}, v16_int8 = { 0, 0, -14, 15, 16, 61, -8, -1, 0, 0, 0, 0, 0, 0, 0, 0}, v8_int16 = {0, 4082, 15632, -8, 0, 0, 0, 0}, v4_int32 = {267517952, -508656, 0, 0}, v2_int64 = {-2184660617396224, 0}, uint128 = 18444559413092155392} (gdb) print $xmm7 $4 = {v4_float = {0.0351714566, -nan(0x7ffff8), 0, 0}, v2_double = {-nan(0xffff83d100ff2), 0}, v16_int8 = { -14, 15, 16, 61, -8, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0}, v8_int16 = {4082, 15632, -8, -1, 0, 0, 0, 0}, v4_int32 = {1024462834, -8, 0, 0}, v2_int64 = {-33335275534, 0}, uint128 = 18446744040374276082} (gdb)
按照IEEE754浮点标准,加载的数据和乘法结果均不符合规范,我不清楚问题出在哪里。
问题原因与解决方案
核心问题
你的代码没有在指令后定义要加载的浮点常量。movsd (%rip), %xmm4 使用RIP相对寻址,会读取当前指令结束后内存地址的8字节数据,但你的_start函数结束后没有放置任何合法的IEEE754双精度浮点数,导致实际加载的是后续的机器码(比如jmp指令的eb ea等字节),这些字节组合成的数值不是合法的双精度浮点数,因此寄存器中出现NaN。
修正后的代码
# file: xmm.a .global _start _start: movsd (%rip), %xmm4 # 加载后续第一个双精度常量 movsd -16(%rip), %xmm7 # 加载后续第二个双精度常量(偏移量需根据指令长度计算) mulsd %xmm4, %xmm7 jmp _start # 定义测试用的双精度浮点数据,放在代码段之后 .double 2.5, 4.0 # 两个8字节的双精度数,对应2.5和4.0,乘积应为10.0
关键修正点
- 移除
.global _start后的冒号,符合GAS汇编语法规范; - 在代码末尾添加
.double伪指令,定义合法的IEEE754双精度浮点常量,让RIP相对寻址能读取到正确数据; - 调整
movsd的RIP偏移量:执行movsd -16(%rip), %xmm7时,RIP指向这条指令的下一条指令(mulsd的地址),-16字节刚好指向第一个.double数据,(%rip)则指向第二个.double数据。
验证方法
重新编译链接后用GDB调试,查看寄存器值:
(gdb) print $xmm4.v2_double[0] $1 = 2.5 (gdb) print $xmm7.v2_double[0] $2 = 4.0 # 执行一次乘法后 (gdb) stepi (gdb) print $xmm7.v2_double[0] $3 = 10.0
内容的提问来源于stack exchange,提问作者dash-
相关产品推荐
相关产品推荐

