windows DebugBreak()中break指令int 3之前的xchg ax,ax的用途是什么?

yrdbyhpb  于 2023-02-25  发布在  Windows
关注(0)|答案(1)|浏览(175)

在MASM中,我总是插入独立的break指令

00007ff7`63141120 cc              int     3

但是,将该指令替换为MSVC DebugBreak函数会生成

KERNELBASE!DebugBreak:
00007ff8`6b159b90 6690            xchg    ax,ax
00007ff8`6b159b92 cc              int     3
00007ff8`6b159b93 c3              ret

我很惊讶地看到xchg指令在break指令之前

xchg    ax,ax

如另一篇S.O.文章所述:
实际上,xchg ax,ax就是MS反汇编“66 90”的方法。66是操作数大小覆盖,所以它应该是在ax而不是eax上操作的。然而,CPU仍然将其作为nop执行。这里使用66前缀使指令的大小为两个字节,通常是为了对齐。
MSVC与大多数编译器一样,将函数与16字节边界对齐。

问题xchg指令的用途是什么?

x7rlezfr

x7rlezfr1#

MSVC在函数开始的任何单字节指令之前生成2字节nop(除了空函数1中的ret)。我已经尝试了__halt_enable_disable内部函数,并看到了相同的效果。
显然,它是用于修补的。/hotpatch选项为x86提供了相同的更改,并且/hotpatch选项在x64上无法识别。根据/hotpatch文档,这是预期行为(强调我):
因为在ARM架构上指令总是两个字节或更大,而且因为x64编译总是被视为指定了/hotpatch,所以在为这些目标编译时不必指定/hotpatch;
因此,热修补支持对于x64是无条件的,其结果可以在DebugBreak实现中看到。
参见此处:https://godbolt.org/z/1G737cErf
请参阅此帖子了解热修补需要它的原因:Why do Windows functions all begin with a pointless MOV EDI, EDI instruction?。看起来当前的热修补足够聪明,可以使用任何两个字节或更多的指令,而不仅仅是MOV EDI, EDI,但它仍然不能使用单字节指令,因为两个字节的向后跳转可以在指令指针指向第二个指令的确切时刻写入。
1正如注解中所讨论的,空函数有三个字节的ret 0,尽管在MSVC汇编输出中并不明显,因为它在那里仅表示为ret

相关问题