我对在静态汇编程序库中的 XBEGIN() 和 XEND() 函数中封装事务性 xbegin 和 xend 感兴趣。但是,我不清楚堆栈如何(或是否)恢复到原始的 xbegin 调用状态,因为 xabort 源自其他堆栈级别(更高或更低)。换句话说,动态堆栈上下文(包括中断效果)是否作为事务的另一部分进行管理和回滚?
对于不支持或不支持 _xbegin( ) 和 _xend( ) 内部函数的 VC++ 2010 构建需要这种汇编程序方法,并且 x64 构建不能使用 _asm { } 内联。
我对在静态汇编程序库中的 XBEGIN() 和 XEND() 函数中封装事务性 xbegin 和 xend 感兴趣。但是,我不清楚堆栈如何(或是否)恢复到原始的 xbegin 调用状态,因为 xabort 源自其他堆栈级别(更高或更低)。换句话说,动态堆栈上下文(包括中断效果)是否作为事务的另一部分进行管理和回滚?
对于不支持或不支持 _xbegin( ) 和 _xend( ) 内部函数的 VC++ 2010 构建需要这种汇编程序方法,并且 x64 构建不能使用 _asm { } 内联。
相关:另请参阅David Kanter 的 TSX文章以了解有关它如何在后台工作以及软件如何从中受益的一些理论,以及有关 HSW 上的一些实验性能数字的博客文章(在发现 TSX 错误和微码更新禁用 TSX 之前)那个硬件。)
英特尔 insn 参考手册条目xbegin
非常清楚。(有关英特尔官方 PDF 和其他内容的链接,请参阅x86标签 wiki。)
在 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
修改后的回退地址。
当然,您可能想要做的不仅仅是在中止时无限重试。这并不是一个真实的例子。(这篇文章确实有一个你可能想要使用的逻辑的真实示例,使用内在函数。看起来他们只是测试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
我认为这在 64 位模式下仍然有效,因为文档提到了rax
,而且看起来IACA 的头文件使用__asm _emit
.
XEND
我猜,把它自己的包装函数也放进去会更安全。你只需要一个权宜之计,直到你可以升级到具有内在函数的编译器,所以它不必是完美的,只要额外的读取/写入ret
不会call
导致太多中止。