首先,我要模拟的实际机器代码片段如下:
f0 49 0f c7 08 lock cmpxchg16b OWORD PTR [r8]
Intel手册中关于CMPXCHG16B
的摘录:
将RDX:RAX与m128进行比较。如果相等,则设置ZF并将RCX:RBX加载到m128中。 否则,清除ZF并将m128加载到RDX:RAX中。
首先,我用我的仿真程序将指令的所有5个字节替换为跳转到代码洞的指令,幸运的是跳转占据了恰好5个字节!该跳转实际上是一个call
指令e8
,但也可以是jmp
e9
,两者都可以使用。
e8 96 fb ff ff call 0xfffffb96(-649)
这是一个相对跳转,使用二进制补码编码的32位有符号偏移量,该偏移量指向下一条指令地址相对于代码洞的位置。
接下来是我要跳转到的仿真代码:
PUSH R10
PUSH R11
MOV r10, QWORD PTR [r8]
MOV r11, QWORD PTR [r8+8]
TEST R10, RAX
JNE ELSE
TEST R11, RDX
JNE ELSE
MOV QWORD PTR [r8], RBX
MOV QWORD PTR [r8+8], RCX
JMP END
ELSE:
MOV RAX, r10
MOV RDX, r11
END:
POP R11
POP R10
RET
就我个人而言,我对此非常满意,并且我认为它符合手册中给出的功能规范。它会恢复堆栈和两个寄存器 r10
和 r11
到它们原本的顺序,然后继续执行。但是很遗憾,它不起作用!也就是说,代码能够正常工作,但程序似乎在等待提示并消耗电力。这表明我的仿真不完美并且我无意中打破了它的循环。你有看到任何问题吗?
我注意到这是它的原子变体-由于 lock
前缀。我希望除了争用之外还有其他我做错了的地方。或者有没有一种方法来模拟原子性呢?
lock cmpxchg16b
的原子性问题?(虽然我不确定带有lock
前缀的cmpxchg16b是否是原子性的,它在SSE周围有些复杂,我从未深入研究过)。 (编辑:哦,你也说了,我今天有点迷糊) - Ped7g