duda add esp, 4 y crash

Iniciado por asmnb, 12 Agosto 2011, 05:02 AM

0 Miembros y 2 Visitantes están viendo este tema.

asmnb

hola ando decidio a apreder asm  :silbar:, trato de compilar este pequeño programa pero no anda (pero compila), compilado con fasm. agradeceria sus correcciones de las cosas que esten mal . mi duda primero es porque no anda y  despues tube que comentar los add esp, 4 que estaban originalmente en el codigo porque no entiendo bine su funcion, si entiendo que suma 4 (un doble palabra) a puntero pila pero no entiendo el objetivo. gracias  :-*


format pe console
entry main
include 'c:\fasm\include\win32a.inc'
section ".data" data readable writeable


hello db 'Hello, world!'
pausa db 'pause'

section ".code" code readable writeable

main:

push hello
call printf
;add esp,4

push pausa
call system
;add esp,4

mov eax,0
ret

section ".idata" import data readable
library msvcrt, "msvcrt"
import msvcrt, printf, "printf" , system, "system"



Eternal Idol

#1
Para hacerla bien corta tenes que poner los nombres de las funciones importadas entre corchetes:

call [printf]
y
call [system]

Esto se debe a que el nombre por si mismo (printf, sleep, etc.) apunta a la sección de datos de tu programa donde el loader pone despues la direccion de la funcion cuando se carga el ejecutable. Cuando no usas los corchetes estas llamando a esa direccion y ahi no hay codigo sino un puntero a una funcion.

Los add los tenes que volver a poner, existen diferentes convenciones de llamada (las mas usadas en Windows son STDCALL y C) y la que usan estas dos funciones al ser de la Run Time de C (MSVCRT= Microsoft Visual C Run Time) es obviamente C. Esta convencion de llamada establece que el llamador es el encargado de sacar lo que puso en la pila (esto permite tener funciones con un numero de parametros variable como printf justamente), en este caso vos pasas un parametro en cada llamada y por eso despues ajustas la pila sumandole el valor de un DWORD.


Código (asm) [Seleccionar]

format pe console
entry main
include 'win32a.inc'
section ".data" data readable writeable


hello db 'Hello %d!', 0
year dd 2011

section ".code" code readable writeable

main:
;db 0xCC
push [year]
push hello
call [printf]
add esp,8

mov eax,0
ret

section ".idata" import data readable
library msvcrt, "msvcrt"
import msvcrt, printf, "printf"


Si hay algo que no entendes lo mejor que podes hacer es descomentar el breakpoint (db 0xCC) y depurar el programa con el WinDbg asi vas a ir viendo por ejemplo que hay en la pila en cada paso (dd @esp).
La economía nunca ha sido libre: o la controla el Estado en beneficio del Pueblo o lo hacen los grandes consorcios en perjuicio de éste.
Juan Domingo Perón

_Enko

#2
Solo un pequeño agregado, si usas funciones de la c runtime, y no quieres estar contando la cantidad de parametros que pushas para luego hacer add esp, X....

fasm te lo puede hacer por vos, win32a.inc incluye la macro ccall y cinvoke.

ccall [printf], szStr, szMessage

;y si no quieres usar los corchetes a cada rato, usa el equivalente

cinvoke printf, szStr, szMessage

ccall va convertir el codigo en:

push szMessage
push szStr
call [printf]
add esp, 8



saludos.

http://www.serviciotecnicocelular.com

asmnb

gracias  ;-) entendi todo lo que explicaron x zuerte  :xD
si tengo mas dudas las voy a decir de nuevo
chau

asmnb



format PE console
entry main
include 'c:\fasm\include\win32a.inc'
section '.data' data readable writeable
msg db "hello world!",0
p db "pause>nul",0

section '.code' code readable executable
main:
push ebp
mov ebp,esp
sub ebp,4
mov dword [esp],msg
call [printf]
mov dword [esp],p
call [system]
mov dword [esp],0
call [exit]

section '.idata' import data readable
library msvcrt,'msvcrt.dll'
import msvcrt,\
printf,'printf',\
system,'system',\
exit,'exit'  


mas dudas me surgieron por favor necestio comprender esto


push ebp
mov ebp,esp
sub ebp,4


el registro ebp se usa  como auxiliar de la pila para dentro de las rutinas es verdad?
entonces entiendo que mueva esp a ebp para tener una copia, y despues porque substrae 4 (DWORD)  ? :huh:


y por otro lado me  pregunto, porque guarda la direccion de msg en esp?
osea seria como hacer un push msg? pero no me queda claro

mov dword [esp],msg
call [printf]


aparte no usa add, 4 en la pila luego de llamar :huh:


_Enko

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

asmnb

gracias por la explicacion, voy a seguir estudiando esto. si vuelvo a tener dudas ya sabran de mi   :laugh: