Visual Studio 2013 / GH / Gh _penter / _pexit 64bit如何保存寄存器?

时间:2014-05-23 11:32:24

标签: assembly visual-studio-2013 inline-assembly

我在VS2013中使用以下编译器选项:

  

/ Gh(启用_penter挂钩功能)

     

http://msdn.microsoft.com/en-us/library/c63a9b7h.aspx

     

/ GH(启用_pexit挂钩功能)   http://msdn.microsoft.com/en-us/library/xc11y76y.aspx

因为我正在尝试为我的代码实现一些基本的分析。但是使用64位编译器时,无法使用naked属性:

http://msdn.microsoft.com/en-us/library/h5w10wxs.aspx

我不认为这确实是一个问题,但是问题在于我无法找到保存寄存器的方法,因为此编译器不支持内联汇编。因此,如果更改任何寄存器,则其值将被删除。例如:

; int __cdecl DllMain(void *hModule, unsigned int ulReason, _CONTEXT *pContext)
push    rbx
sub     rsp, 20h
call    _penter

这里我们必须确保_penter不会丢弃rsp的值:

; int __cdecl penter(LARGE_INTEGER PerformanceCount)
PerformanceCount= LARGE_INTEGER ptr  8

sub     rsp, 28h
xor     eax, eax
lea     rcx, [rsp+28h+PerformanceCount] ; lpPerformanceCount
mov     qword ptr [rsp+28h+PerformanceCount], rax
call    cs:__imp_QueryPerformanceCounter
add     rsp, 28h
retn
_penter endp

在这种情况下,它的确定为_penter正在修复rsp - 但是eax和rcx的值正在被覆盖。在x86编译器中,我可以简单地添加内联asm来推送和弹出这些寄存器。我怎样才能在x64编译器中执行此操作?

2 个答案:

答案 0 :(得分:1)

您必须将汇编编码移动到.asm文件,因为Visual Studio不支持x64中的内联汇编代码。

答案 1 :(得分:1)

这实际上是MSVC x64的一个问题,它并不尊重_penter / _pexit函数的非裸(x64中缺席)声明。

下面举例说明我如何处理这个问题(不仅你必须保存易失性寄存器的内容,这些内容被认为是被调用破坏,但是标志也会注册,因为_penter / _pexit可能会被插入在具有依赖于标志的汇编命令之间;这只能在单独的汇编文件中完成,因为MSVC不在x64中提供内联汇编:

PUSHREGS    macro
    push    rax
    lahf
    push    rax
    push    rcx
    push    rdx
    push    r8
    push    r9
    push    r10
    push    r11
endm

POPREGS macro
    pop r11
    pop r10
    pop r9
    pop r8
    pop rdx
    pop rcx
    pop rax
    sahf
    pop rax
endm

...

profile_enter   proc
    PUSHREGS
    ; > your code goes here. Be aware that it must preserve any non-volatile registers used and align the stack pointer for any calls made.
    POPREGS
    ret
profile_enter   endp

您还可以在此处查看工作代码: https://github.com/tyoma/micro-profiler/blob/master/micro-profiler/collector/hooks.asm