I'm trying to put some C hooks into some code that someone else wrote in asm. I don't know much about x86 asm and I want to make sure I'm doing this safely.
So far I've got this much:
EXTERN _C_func
CALL _C_func
And that seems to work, but I'm sure that's dangerous as-is. At the very least it could be destroying EAX, and possibly more.
So I think all I need to know is: Which registers does C destroy and how do I ensure the registers are being saved properly? Is there anything else I can do to make sure I can safely insert hooks into arbitrary locations?
I'm using Visual Studio for the C functions, if that helps. Thank you.
UPDATE:
I looked up the "paranoid" method several people suggested and it looks like this:
pushfd
pushad
call _C_func
popad
popfd
AD = (A)ll general registers
FD = (F)lags
(I'm not sure what the 'd' stands for, but it means 32-bit registers instead of 16-bit.)
But the most efficient method is illustrated in Kragen's answer below. (Assuming you don't need the preserve the flags. If you do, add the FD instructions.)
Also, be careful about allocating lots of stack variables in your C function as it could overrun the asm subroutine's stack space.
I think that about does it, thanks for you help everyone!
If the calling convention is cdecl and the signature of C_funct is simply:
void C_func(void);
Then that is perfectly "safe", however the registers EAX, ECX and EDX are "available for use inside the function", and so may be overwritten.
To protect against this you can save the registers that you care about and restore them afterwards:
push eax
push ecx
push edx
call _C_func
pop edx
pop ecx
pop eax
By convention the registers EBX, ESI, EDI, and EBP shouldn't be modified by the callee.
I believe that the flags may be modified by the callee - again if you care about preserving the value of flags then you should save them.
See the Wikipedia page on x86 calling conventions.
You need to be aware of calling conventions. See this article for a discussion on calling conventions.
If you are paranoid about registers, you can always push all registers onto the stack before calling the function (functions shouldn't return without cleaning up, except for those registers that carry return information).
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