如何查看 MASM 指令的结果,例如 PROC、.SETFRAME。 .PUSHREG
How to see result of MASM directives such as PROC, .SETFRAME. .PUSHREG
使用 MASM 编写 x64 汇编代码,我们可以使用这些指令来提供帧展开信息。例如,从 .SETFRAME
定义:
These directives do not generate code; they only generate .xdata and .pdata.
由于这些指令不产生任何代码,我无法在反汇编中看到它们的效果 window。因此,当我使用或不使用这些指令编写汇编函数时,我看不出有什么区别。如何查看这些指令的结果 - 使用 dumpbin
或其他方式?
如何编写可以测试这种展开能力的代码?例如,我故意编写导致异常的汇编代码。我想看看在使用或不使用这些指令编写函数时异常处理行为的区别。
在我的例子中,调用者是用 C++ 编写的,可以使用 try-catch
、SSE 等 - 任何与这种情况相关的东西。
最好的办法可能是让您的 asm 函数调用另一个 C++ 函数,并让您的 C++ 函数抛出 C++ 异常。 (不像来自 asm 的非法内存会出错并可能导致 SEH 处理程序。正常的 C++ 异常比 Windows SEH 更简单)。
因此,创建一个 C++ 异常需要通过您的 asm 函数展开堆栈的情况;如果它有效,那么你的堆栈展开元数据指令是正确的。具体来说,try{}catch
在 C++ 调用者中,throw
在 C++ 函数中 call
来自 asm.
我认为那个 thrower 可以是 extern "C"
这样您就可以从 asm 调用它而无需名称修改。或者通过函数指针调用它,或者只查看 MSVC 编译器输出并将损坏的名称复制到 asm.
顺便说一句,此元数据的非Windows(例如GNU/Linux)等价物是创建.eh_frame
部分的DWARF .cfi
指令。
我不知道 Windows 的等效细节,但我知道它们使用类似的元数据,可以在不依赖 RBP 帧指针的情况下展开堆栈。这让编译器可以优化代码,不会在函数 prologues/epilogues 中浪费 push rbp
/ mov rbp,rsp
和 leave
上的指令,并释放 RBP 用作通用寄存器. (在 32 位代码中更有用,其中除了堆栈指针之外还有 7 个而不是 6 个寄存器比 15 和 14 大得多。)
想法是给定一个 RIP,您可以查找从 RSP 到堆栈上 return 地址的偏移量,以及任何调用保留寄存器的位置。因此,您可以恢复它们并使用该 return 地址继续展开到父级。
回答您的问题:
How can I see the result of these directives - using dumpbin or something else?
您可以使用 dumpbin /UNWINDINFO out.exe
查看因使用 .SETFRAME
而对 .pdata
添加的内容。
输出将如下所示:
00000054 00001530 00001541 000C2070
Unwind version: 1
Unwind flags: None
Size of prologue: 0x04
Count of codes: 2
Frame register: rbp
Frame offset: 0x0
Unwind codes:
04: SET_FPREG, register=rbp, offset=0x00
01: PUSH_NONVOL, register=rbp
对输出的一些解释:
- 在输出中找到的第二个十六进制数是函数地址
00001530
- 展开代码表示函数序言中发生的事情。在这个例子中发生的是:
- RBP 入栈
- RBP用作帧指针
其他功能可能如下所示:
000000D8 000016D0 0000178A 000C20E4
Unwind version: 1
Unwind flags: EHANDLER UHANDLER
Size of prologue: 0x05
Count of codes: 2
Unwind codes:
05: ALLOC_SMALL, size=0x20
01: PUSH_NONVOL, register=rbx
Handler: 000A2A50
这里的一个主要区别是这个函数有一个异常处理程序。这由 Unwind flags: EHANDLER UHANDLER
和 Handler: 000A2A50
.
表示
使用 MASM 编写 x64 汇编代码,我们可以使用这些指令来提供帧展开信息。例如,从 .SETFRAME
定义:
These directives do not generate code; they only generate .xdata and .pdata.
由于这些指令不产生任何代码,我无法在反汇编中看到它们的效果 window。因此,当我使用或不使用这些指令编写汇编函数时,我看不出有什么区别。如何查看这些指令的结果 - 使用 dumpbin
或其他方式?
如何编写可以测试这种展开能力的代码?例如,我故意编写导致异常的汇编代码。我想看看在使用或不使用这些指令编写函数时异常处理行为的区别。
在我的例子中,调用者是用 C++ 编写的,可以使用 try-catch
、SSE 等 - 任何与这种情况相关的东西。
最好的办法可能是让您的 asm 函数调用另一个 C++ 函数,并让您的 C++ 函数抛出 C++ 异常。 (不像来自 asm 的非法内存会出错并可能导致 SEH 处理程序。正常的 C++ 异常比 Windows SEH 更简单)。
因此,创建一个 C++ 异常需要通过您的 asm 函数展开堆栈的情况;如果它有效,那么你的堆栈展开元数据指令是正确的。具体来说,try{}catch
在 C++ 调用者中,throw
在 C++ 函数中 call
来自 asm.
我认为那个 thrower 可以是 extern "C"
这样您就可以从 asm 调用它而无需名称修改。或者通过函数指针调用它,或者只查看 MSVC 编译器输出并将损坏的名称复制到 asm.
顺便说一句,此元数据的非Windows(例如GNU/Linux)等价物是创建.eh_frame
部分的DWARF .cfi
指令。
我不知道 Windows 的等效细节,但我知道它们使用类似的元数据,可以在不依赖 RBP 帧指针的情况下展开堆栈。这让编译器可以优化代码,不会在函数 prologues/epilogues 中浪费 push rbp
/ mov rbp,rsp
和 leave
上的指令,并释放 RBP 用作通用寄存器. (在 32 位代码中更有用,其中除了堆栈指针之外还有 7 个而不是 6 个寄存器比 15 和 14 大得多。)
想法是给定一个 RIP,您可以查找从 RSP 到堆栈上 return 地址的偏移量,以及任何调用保留寄存器的位置。因此,您可以恢复它们并使用该 return 地址继续展开到父级。
回答您的问题:
How can I see the result of these directives - using dumpbin or something else?
您可以使用 dumpbin /UNWINDINFO out.exe
查看因使用 .SETFRAME
而对 .pdata
添加的内容。
输出将如下所示:
00000054 00001530 00001541 000C2070
Unwind version: 1
Unwind flags: None
Size of prologue: 0x04
Count of codes: 2
Frame register: rbp
Frame offset: 0x0
Unwind codes:
04: SET_FPREG, register=rbp, offset=0x00
01: PUSH_NONVOL, register=rbp
对输出的一些解释:
- 在输出中找到的第二个十六进制数是函数地址
00001530
- 展开代码表示函数序言中发生的事情。在这个例子中发生的是:
- RBP 入栈
- RBP用作帧指针
其他功能可能如下所示:
000000D8 000016D0 0000178A 000C20E4
Unwind version: 1
Unwind flags: EHANDLER UHANDLER
Size of prologue: 0x05
Count of codes: 2
Unwind codes:
05: ALLOC_SMALL, size=0x20
01: PUSH_NONVOL, register=rbx
Handler: 000A2A50
这里的一个主要区别是这个函数有一个异常处理程序。这由 Unwind flags: EHANDLER UHANDLER
和 Handler: 000A2A50
.