相关:另请参阅 David Kanter's TSX writeup 了解有关它如何在后台工作以及软件如何从中受益的一些理论,以及 this blog post 了解 HSW 上的一些实验性能数据(在发现 TSX 错误和禁用微码更新之前TSX 在那个硬件上。)
英特尔 insn 参考手册entry for xbegin 非常清楚。 (请参阅x86 标签 wiki,获取英特尔官方 PDF 和其他内容的链接。)
在 RTM 中止时,逻辑处理器丢弃 所有架构
在 RTM 执行期间执行的寄存器和内存更新
将架构状态恢复到与最外层对应的状态
XBEGIN 指令。中止后的回退地址是根据最外面的 XBEGIN 指令计算的。
因此该指令的工作方式类似于条件分支,其中分支条件是“在XEND 之前发生中止吗?”例如:
; NASM syntax, I assume MASM is similar
ALIGN 16
retry:
; eax holds abort info, all other architectural state + memory is unchanged
inc [retry_count] ; or whatever other debug instrumentation you want to add
global xbegin_wrapper_with_retry
xbegin_wrapper_with_retry:
xbegin retry
ret
如果发生中止,就好像在xbegin 之后运行的所有代码根本没有运行,只是跳转到修改了eax 的后备地址。
当然,您可能想要做的不仅仅是在中止时无限重试。这并不是一个真实的例子。 (This article 确实有一个你可能想要使用的逻辑的真实示例,使用内在函数。看起来他们只是测试eax 而不是使用xbegin 作为if 中的跳转,除非编译器会优化该检查。IDK 如果它是最有效的方法。)
“中断效果”是什么意思?在当前的实现中,任何改变特权级别的事情(如系统调用或中断)都会导致事务中止。因此,环形级别的更改永远不需要回滚。 CPU 在遇到无法回滚的情况时会中止事务。这意味着可能的错误包括在事务中放入一些总是导致中止的东西,而不是你做了一些无法回滚的事情。
您可能想尝试让编译器在没有函数调用的情况下发出三字节 XEND 指令,因此将返回地址压入堆栈不是事务的一部分。例如
// no idea if this is safe, or if it might get reordered by the optimizer
#define xend_MSVC __asm _emit 0x0F __asm _emit 0x01 __asm _emit 0xD5
I think this does still work in 64bit mode,因为文档提到了rax,看起来IACA's header file 使用了__asm _emit。
我猜,将XEND 放在它自己的包装函数中会更安全。您只需要一个权宜之计,直到您可以升级到具有内在函数的编译器,因此只要来自 ret 和 call 的额外读取/写入不会导致太多中止,它就不必是完美的.