如何使用Visual Studio调试amd64上的未对齐访问?

sam*_*var 23 debugging 64-bit assembly alignment visual-c++

我想调试和配置一些执行未对齐访问的64位软件,如下例所示:

int foo[2] = { 1, 2 };
*((int *)((char *)foo + 2)) = 3;
Run Code Online (Sandbox Code Playgroud)

gcc的方式

我知道在使用gccgdb时有两种方法可以做到这一点.第一种方法是直接在我的C或C++代码中启用寄存器中的对齐校验位(位18)eflags:

asm volatile("pushf \n"
             "pop %%rax \n"
             "or $0x40000, %%rax \n"
             "push %%rax \n"
             "popf \n" ::: "rax");
Run Code Online (Sandbox Code Playgroud)

这非常方便,因为我可以在应用程序本身中选择是否绕过未对齐的访问检查,例如在调用已知的错误库时.

另一种方式是来自gdb,在调试可执行文件时的任何时刻:

set $eflags |= 1<<18
Run Code Online (Sandbox Code Playgroud)

同样,这可以随意启用或禁用,编写脚本等.非常方便.

视觉工作室

现在,我已经无法在Vista64上使用Visual Studio 20082010完成相同的操作.在任何版本的Visual Studio中,x64模式下的C++程序中的内联汇编不再可用,但我可以使用内在函数代替:

#include <intrin.h>
/* ... */
__writeeflags(__readeflags() | 0x40000);
Run Code Online (Sandbox Code Playgroud)

这与Linux上的代码完全相同.它有点工作:当我的错误代码运行时,我得到了异常.EFL.AC每次遇到断点时,标志都会重置为零.这意味着我无法正确调试具有大量复杂断点的大型应用程序,除非我通过调用我的asm函数来丢弃代码.

所以我尝试EFL |= 0x40000从Visual Studio注册调试会话手动更改(这正是我在Linux上通常做的).也没有效果,一旦我恢复调试,该位就设置为零.这意味着我无法正确调试我没有源代码的代码.

我不明白这里发生了什么.是Visual Studio强制设置EFL.AC=0吗?如果是这样,我可以禁用该"功能"吗?此外,有没有办法EFL.AC在调试会话期间启用/禁用?

现实世界的Windows开发人员如何跟踪代码中的未对齐访问?

编辑:发现__readeflags,这不在x64内在函数列表中.

小智 3

不幸的是,在 VS 中调试 x64 调试器时,会清除任何异常的对齐检查标志(包括首先抛出进入调试器的异常)。您是否尝试过使用 Windbg(功能更强大的 Windows 调试器)单步调试代码?我无法使用 AC 标志来尝试它,但使用 r efl= 或直接从寄存器窗口应该很简单。如果您没有安装windbg,您可以从最新的Windows SDK 获取它。