如何阻止 ESP 在 __fastcall 中被损坏?
我试图在汇编中编写一个函数,将内存块设置为指定值,很像 memset(),但是,当我从堆栈中获取第三个参数时(它使用 fastcall 调用约定),寄存器 ECX 得到一些乱码值。
通过使用内联汇编将代码放入 Visual Studio 中,我发现调用函数时 ESP 发生了显着变化。 前两个参数被放入 ECX 和 EDX 中没有任何问题,只是第三个参数造成了麻烦。
我知道代码可以工作,当我在 VS 中调试时手动设置寄存器中的值时,内存块填充了正确的值。
我对汇编比较陌生,所以我的代码可能有点狡猾,但有人知道如何解决这个问题吗?
代码如下:
#ifdef __GNUC__
#define __fastcall __attribute__((fastcall)) // 'Cause I'm a M$ fanboy
#endif
void __fastcall memset(void *pDest, int iValue, int iSize)
{
__asm
{
; Assume the pointer to the memory is stored in ECX
; Assume the value is stored in EDX
; Assume the size of the block is stored on the stack
mov eax, esi ; Put ESI somewhere it won't be touched (I think)
mov esi, ecx ; Move the address of the memory into ESI
xor ecx, ecx ; Zero ECX
pop ecx ; Get the size of the block into ECX. ECX is our loop counter
memset_count:
cmp ecx, 0 ; If we are at the end of the block,
jz memset_return ; Jump to return
mov [esi], edx ; Move our value into the memory
inc esi ; Otherwise, increment out position in the memory
dec ecx ; Decrement out counter
jmp memset_count ; Start again
memset_return:
mov esi, eax ; Restore ESI
add esp, 4 ; Remove our third argument from the stack
ret
}
}
#define ret return
int main(int argc, char **argv)
{
char szText[3];
/*
__asm
{
push 3
mov edx, 65
lea ecx, szText2
call memset
}
*/
memset(&szText, 'A', 3);
ret 42;
}
I'm attempting to write a function in assembly that sets a block of memory to a specified value, much like memset(), however, when I go to get the third argument off the stack (it uses the fastcall calling convention), the register, ECX, gets some garbled value.
By putting the code into Visual Studio using inline assembly, I see that ESP is significantly changed when the function is called.
The first two arguments are being put into ECX and EDX without any issue, it's just the third one that is causing trouble.
I know the code works the block of memory is filled with the correct value when I manually set the value in the register whilst debugging in VS.
I'm relatively new to assembly, so my code is probably a bit dodgy, but does anyone know how to fix this problem?
The code is below:
#ifdef __GNUC__
#define __fastcall __attribute__((fastcall)) // 'Cause I'm a M$ fanboy
#endif
void __fastcall memset(void *pDest, int iValue, int iSize)
{
__asm
{
; Assume the pointer to the memory is stored in ECX
; Assume the value is stored in EDX
; Assume the size of the block is stored on the stack
mov eax, esi ; Put ESI somewhere it won't be touched (I think)
mov esi, ecx ; Move the address of the memory into ESI
xor ecx, ecx ; Zero ECX
pop ecx ; Get the size of the block into ECX. ECX is our loop counter
memset_count:
cmp ecx, 0 ; If we are at the end of the block,
jz memset_return ; Jump to return
mov [esi], edx ; Move our value into the memory
inc esi ; Otherwise, increment out position in the memory
dec ecx ; Decrement out counter
jmp memset_count ; Start again
memset_return:
mov esi, eax ; Restore ESI
add esp, 4 ; Remove our third argument from the stack
ret
}
}
#define ret return
int main(int argc, char **argv)
{
char szText[3];
/*
__asm
{
push 3
mov edx, 65
lea ecx, szText2
call memset
}
*/
memset(&szText, 'A', 3);
ret 42;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

被调用代码堆栈上的第一件事将是调用的返回地址。第二件事将是第一个论点。
为了避免更改 ESP 并解决“弹出错误的内容”问题,请尝试类似“mov ecx,[esp+4]”(而不是“pop ecx”)的操作。
The first thing on the called code's stack will be the return address for the call. The second thing will be the first argument.
To avoid changing ESP, and to fix the "popping the wrong thing" problem, try something like "mov ecx,[esp+4]" (instead of the "pop ecx").