我使用ASM写的本质上相当于memset()。我写的代码有效,除了当我尝试恢复堆栈时,它会因访问冲突而崩溃。我已经使用内联汇编将代码放入MSVC中,因此我可以对其进行调试。
函数返回时出现问题。但是,当我取出add esp, 4
行时,代码正确执行,但在main()函数返回后,MSVC表示变量周围的堆栈已损坏。
我不愿意在没有add esp, 4
的情况下继续,因为我知道这会在以后引起问题。
我将如何解决这个问题?
int main(int argc, char **argv)
{
char szText[3];
/*__asm
{
push 3
mov edx, 65
lea ecx, szText
call memset
}*/
memset((void*)&szText, 'A', 3);
return 42;
}
void __declspec(naked) __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
mov ecx, [esp+4] ; 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 ; Clean up the stack
ret
}
}
答案 0 :(得分:3)
memset_return:
mov esi, eax ; Restore ESI
add esp, 4 ; Clean up the stack
ret
这是错的,你没有在函数体中从ESP中减去4。你实际上会跳过返回地址,RET会从堆栈中弹出参数并跳转到它的值。 KABOOM。修正:
memset_return:
mov esi, eax ; Restore ESI
ret 4
您还有编写函数原型,以便编译器知道该函数的调用约定是非标准的。如果它不知道,它将在呼叫站点生成错误的代码。在主方法之前粘贴它:
void __fastcall memset(void *pDest, int iValue, int iSize);
并且避免将其命名为“memset”,这是代码生成器也发出的内在函数。它将调用您的函数而不是标准函数。哪个会很糟糕,标准的签名会有很大差异。选择另一个名称以避免这几乎不可能调试事故。
答案 1 :(得分:1)
使用ret 4
代替add esp, 4 / ret