问题
As the title of my question says the sleep() function works properly (and every other function call in the C function, the problem is that after it's finished running I get an error that says:
"Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call. This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention."
I believe the way I'm handling the registers when I call the sleep function is done properly because it actually works, I posted the whole function just in case it's needed to detect where I might be misplacing the stack contents in another function call.
The function basically prints an elevator going up from the last floor on the bottom to the top-most one.
int deSubidaASM() {
int sleepTime = 900;
char *clear = "cls";
char *piso = "[x]";
char *pisoVacio = "[ ]";
char *texto = "%s\n";
char *fuerza = "Fuerza G: 1";
_asm {
mov ebx, 0 //int a=0
mov ecx, 9 //int b=9
_while1: //while (a <= 9)
cmp ebx, 9 //
jg _fin //if ebx>9, end
_Fuerza: //writes on screen
mov eax, fuerza
push eax
mov eax, texto
push eax
mov esi, ecx //
call printf
mov ecx, esi //
pop edx
pop edx
_sleep:
mov eax, sleepTime
push eax //pushes the sleep time input
mov esi, ebx //auxiliary variable to keep the cycle counters
mov edi, ecx //same as the above line comment
call Sleep //sleep() call
mov ecx, edi //returns the values from the aux variables
mov ebx, esi //same as the above line comment
pop eax //cleans the stack
_clearscreen:
mov eax, clear //Bloque para clearscreen
push eax
mov esi, ebx
mov edi, ecx
call system
mov ecx, edi
mov ebx, esi
pop edx
_while2 : //while (b >= 0)
cmp ecx, 0 //
jle _resetearWhile2 //if ecx<0 restart while2
cmp ebx, ecx // if the levels match
je _printPiso //print elevator
jne _printVacio //print floor
_printPiso :
mov eax, piso
push eax
mov eax, texto
push eax
mov esi, ecx //
call printf
mov ecx, esi //
pop edx
pop edx
dec ecx
jmp _while2
_printVacio :
mov eax, pisoVacio
push eax
mov eax, texto
push eax
mov esi, ecx //
call printf
mov ecx, esi //
pop edx
pop edx
dec ecx
jmp _while2
_resetearWhile2:
mov ecx, 9 //b=9
inc ebx
jmp _while1
_fin :
}
}
回答1:
The WinApi Sleep() function follows the STDCALL calling convention. It had already cleaned up the stack when it returns. When you do the same, the stack is "overcleaned" ;-). Remove the line:
pop eax //cleans the stack
I don't know what compiler you use. My compiler (Visual Studio 2010) needs another call to Sleep():
call dword ptr [Sleep]
回答2:
Too much for a comment. I mean push and pop the registers you are interested in preserving, including those you are juggling around from esi <-> ebx
and edi <-> ecx
.
_sleep:
push ecx // save the regs
push edx
push ebp
mov eax, sleepTime // func argument
push eax // pushes the sleep time input
call Sleep // sleep() call
pop eax // clean off stack
pop ebp // restore regs
pop edx
pop ecx
来源:https://stackoverflow.com/questions/34455786/sleep-inline-assembly-call-works-but-generates-runtime-check-failure