I'm using the following compiler options in VS2013:
/Gh (Enable _penter Hook Function)
http://msdn.microsoft.com/en-us/library/c63a9b7h.aspx
/GH (Enable _pexit Hook Function) http://msdn.microsoft.com/en-us/library/xc11y76y.aspx
As I'm trying to implement some basic profiling for my code. However with the 64-bit compiler its not possible to use the naked attribute:
http://msdn.microsoft.com/en-us/library/h5w10wxs.aspx
I don't think this is really a problem, however what is a problem is that I can't find a way to save the registers as inline assembly is not supported in this compiler. So if change any registers then their value is trashed. For example:
; int __cdecl DllMain(void *hModule, unsigned int ulReason, _CONTEXT *pContext)
push rbx
sub rsp, 20h
call _penter
Here we must make sure that _penter will not trash the value of 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
In this case its ok as _penter is fixing up rsp - however the values of eax and rcx are being overwritten. In x86 compiler I can simply add inline asm to push and pop these registers. How can I do this in the x64 compiler?
This is in fact an issue with MSVC x64 that doesn't respect non-naked (absent in x64) declaration of _penter/_pexit functions.
Below goes an example of how I worked around this issue (not only you have to save volatile registers contents of which are considered to be destroyed by the call, but the flags register as well, as _penter/_pexit may get inserted in-between assembly commands having dependency on flags; this can only be done in a separate assembly file since MSVC does not provide inline assembly in 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
You can also take a look at the working code here: https://github.com/tyoma/micro-profiler/blob/master/micro-profiler/collector/hooks.asm
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With