2009-08-09 22 views
8

Acabo de empezar a jugar con ASM y no estoy seguro de si mi comprensión de las llamadas a procedimientos es correcta.¿cómo funcionan las llamadas a procedimiento en el ensamblador?

dicen que en algún momento en el código no es una llamada a procedimiento

call dword ptr[123] 

y el procedimiento consiste en un solo comando, ret:

ret 0004 

cuál sería el efecto de esta llamada a procedimiento , y donde se almacenaria el valor de retorno? He leído en alguna parte que un valor de retorno de 2 bytes se almacena en AX, pero cuando se sustituye la llamada a procedimiento por

mov AX, 0004 

(junto con los necesarios NOP) el programa se bloquea.

Respuesta

12

en ensamblador x86 el parámetro de la instrucción ret significa:

RET immediate

Volver a llamar a procedimiento y el pop inmediatos bytes de la pila.

(citando Intel® 64 and IA-32 Architectures Software Developer's ManualsVol 2B)

Así que cuando escribe:

ret 0004 

Usted está diciendo la CPU para volver a la instrucción inmediatamente después de la call, y para hacer estallar fuera de 4 bytes la pila. Esto es genial si presionó 4 bytes en la pila antes de la llamada.

push eax 
call dword ptr[123] 

Tenga en cuenta que esto no tiene nada que ver con el valor de retorno. De hecho, un procedimiento en Assembly no tiene forma de especificar que un valor sea return value. Todo esto se hace por convención. La mayoría de los compiladores que conozco usarán EAX para mantener el valor de retorno, pero esto es cierto solo porque la función de llamada esperará el resultado allí.

lo tanto, su código de llamada sería:

call dword ptr [123] 
mov dword ptr [result], eax 

y su función que devuelve el valor 4 sería:

mov eax, 4 
ret 
+0

gracias! la mayoría de los tutoriales que busqué en Google simplemente usaban ret, y no explicaban el funcionamiento inmediato de de. Me confundí aún más cuando el ensamblador LLVM aparentemente tenía un comando "ret ". – int3

+0

¿Hay alguna razón por la cual RET puede regresar a algún lugar que no sea la llamada? Acabo de crear una pregunta y encontré esto en las preguntas relacionadas – lisovaccaro

+0

sí, si manipuló la dirección de retorno que 'CALL' insertó en la pila. –

-1

No creo que el valor de retorno se almacena en el registro AX

+0

¿Alguna idea de dónde, entonces? – int3

+0

@ int3: depende de la convención de llamadas. No hay nada automático aquí. La función de llamada y la función llamada tienen que acordar dónde está el valor de retorno. –

1
// possibly there are arguments pushed here 
... 
call dword ptr[123] // push next OP code offset in the stack and jump to procedure 

// procedure 
... 
ret 0004 // pop offset, set EIP to that offset and decrease ESP by 4 

que, además, disminuir el ESP si hubiéramos empujado argumentos en la pila antes de llamar al procedimiento.


Si hay argumentos insertados, el programa se bloquea porque no los muestra. El desplazamiento de retorno para el procedimiento actual será incorrecto ya que obtendrá un valor de uno de los argumentos empujados como el desplazamiento.

2

Todo depende de la calling convention que se utilice. No voy a repetir el artículo de Wikipedia aquí, solo lea la definición.

En el C calling convention, por ejemplo, el valor de retorno estaría en EAX/AX/AL. Su única instrucción no tiene una: es una función vacía que toma alrededor de 4 bytes de parámetros (posiblemente un único int) que no hace nada. Como es deber del destinatario limpiar la pila en esta convención de llamadas, ignorar hacer eso y reemplazar la llamada con un 'mov ax' no funciona.

También sospecho que puede estar jugando con el ensamblaje de 32 bits mientras lee un documento de 16 bits. No es un gran problema, pero debes ser consciente de las diferencias.

Cuestiones relacionadas