Hola, en este caso, en si la linea "push ebp" no es para resguardar el valor de epb, porque en el codigo, el valor de ebp nunca se restaura.
es mas, cambia "push ebp" por "push 0" y veras el mismo resultado.
Es mas, aqui el mismo sin las lineas de mas.
push 0
mov dword [esp],msg
call [printf]
mov dword [esp],p
call [system]
mov dword [esp],0
call [exit]
despues del printf, no suma 4 a la pila, porque el valor pusheado se sigue utilizando. (mov dword[esp],p)
Finalmente, despues de exit, no se suma 4 a la pila porque exit, creo que no es cdecl, es decir, es stdcall y se encarga de liberar la pila.
En realidad, de otra forma no podria ser, porque despues de call[exit] ya no se ejecuta mas codigo de tu programa, se termina.
Ahora, sobre push ebp/mov ebp, esp/....
Se utiliza para usar variables locales en los procedimientos sin perder el registro de los argumentos que se les pasa.
push 1234
push 2345
call proca
;etc..............................
proca:
push ebp ;salvamos ebp original
mov ebp, esp
sub esp, 8 ;dejamos espacio para 2 variables locales
mov dword[ebp -8], 0 ;variable local 1
mov dword[ebp -4], 0 ;variable local 2
mov eax, [ebp + 8]; parametro 1
mov eax, [ebp + 12]; parametro 2
mov esp, ebp ;restauramos la pila quitanod
pop ebp ;las dos variables locales
ret 8 ;retornamos quitando 2 argumentos de la pila
Por cierto, de donde sacas esos ejemplos raros?
normalmente se haria
section '.code' code readable executable
main:
cinvoke printf, msg
cinvoke system, p
invoke exit, 0
tendria que buscar, pero exit no deberia ser cdecl sino stdcall, es decir restaura completamente la pila por si solo