我在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编译器中执行此操作?
答案 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