中止的xbegin事务是否还原xbegin启动时存在的堆栈上下文

Does an aborted xbegin transaction restore the stack context that existed at the xbegin start?

本文关键字:xbegin 存在 堆栈 启动 上下文 是否 事务 还原      更新时间:2023-10-16

我感兴趣的是将事务性xbegin和xend封装在静态汇编程序库中的xbegin()和xend()函数中。然而,我不清楚堆栈是如何(或是否)恢复到原始的xbegin调用状态的,因为xabort源自其他堆栈级别(更高或更低)。换句话说,动态堆栈上下文(包括中断效果)是否只是作为事务的另一部分进行管理和回滚?

此汇编程序方法对于不支持或不可用_xbegin()和_xend()内部函数的VC++2010生成是必需的,并且x64生成不能使用_asm{}内联。

相关:另请参阅David Kanter的TSX文章,了解它如何在引擎盖下工作以及软件如何从中受益的一些理论,以及这篇博客文章,了解HSW上的一些实验性能数据(在TSX错误被发现和微代码更新禁用该硬件上的TSX之前)。


xbegin的Intel insn-ref手动输入非常清楚。(有关英特尔官方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放在自己的包装函数中也会更安全。在升级到具有内部函数的编译器之前,您只需要一个权宜之计,所以只要retcall的额外读/写不会导致太多中止,它就不必是完美的。