La razón de las direcciones "extrañas", como main+0
, main+1
, main+3
, main+6
y así sucesivamente, es porque cada instrucción ocupa un número variable de bytes. Por ejemplo:
main+0: push %ebp
es una instrucción de un byte por lo que la próxima instrucción está en main+1
. Por otro lado,
main+3: and $0xfffffff0,%esp
es una instrucción de tres bytes por lo que la siguiente instrucción después de eso está en main+6
.
Y, como usted pregunta en los comentarios por qué movl
parece tomar un número variable de bytes, la explicación es la siguiente.
Longitud de instrucción no sólo depende de la código de operación (como movl
), sino también los modos de direccionamiento de los operandos (así las cosas el código de operación están operando en). No he comprobado específicamente para su código, pero sospecho que la instrucción
movl $0x1,(%esp)
es probablemente más corto porque no hay desplazamiento involucrados - sólo se utiliza como dirección de esp
. Mientras que algo como:
movl $0x2,0x4(%esp)
requiere todo lo que hace movl $0x1,(%esp)
, además un byte adicional para la 0x4
offset.
De hecho, aquí es una sesión de depuración que muestra lo que quiero decir:
Microsoft Windows XP [Version 5.1.2600]
(C) Copyright 1985-2001 Microsoft Corp.
c:\pax> debug
-a
0B52:0100 mov word ptr [di],7
0B52:0104 mov word ptr [di+2],8
0B52:0109 mov word ptr [di+0],7
0B52:010E
-u100,10d
0B52:0100 C7050700 MOV WORD PTR [DI],0007
0B52:0104 C745020800 MOV WORD PTR [DI+02],0008
0B52:0109 C745000700 MOV WORD PTR [DI+00],0007
-q
c:\pax> _
se puede ver que la segunda instrucción con un desplazamiento es en realidad diferente a la primera sin ella. Es un byte más largo (5 bytes en lugar de 4, para contener el desplazamiento) y en realidad tiene una codificación diferente c745
en lugar de c705
.
También puede ver que puede codificar la primera y la tercera instrucción de dos maneras diferentes, pero básicamente hacen lo mismo.
La instrucción and $0xfffffff0,%esp
es una manera de forzar esp
estar en un límite específico. Esto se usa para asegurar la alineación adecuada de las variables. Muchos accesos a memoria en procesadores modernos serán más eficientes si siguen las reglas de alineación (como un valor de 4 bytes que debe alinearse con un límite de 4 bytes). Algunos procesadores modernos incluso presentarán un error si no sigues estas reglas.
Después de esta instrucción, tiene la garantía de que esp
es tanto menor o igual a su valor anterior y alineado con un límite de 16 bytes.
El prefijo gs:
significa simplemente utilizar el registro gs
segmento de acceder a la memoria en lugar de la forma predeterminada.
La instrucción mov %eax,-0xc(%ebp)
medios para trazar el contenido del registro ebp
, restar 12 (0xc
) y luego poner el valor de eax
en esa posición de memoria.
Consulte la explicación del código. Su función function
es básicamente una gran no operación. El ensamblaje generado se limita a la configuración y al desmontaje del marco de la pila, junto con la comprobación de corrupción del marco de pila que utiliza la ubicación de memoria %gs:14
antes mencionada.
Carga el valor desde esa ubicación (probablemente algo así como 0xdeadbeef
) en el marco de la pila, hace su trabajo, luego verifica la pila para asegurarse de que no esté dañada.
Su trabajo, en este caso, no es nada. Entonces, todo lo que ves es la administración de funciones.
La configuración de la pila se produce entre function+0
y function+12
. Todo lo que sigue es configurar el código de retorno en eax
y derribar el marco de la pila, incluido el control de corrupción.
De forma similar, main
consiste en la configuración del marco de la pila, presionando los parámetros para function
, llamando al function
, derribando el marco de la pila y saliendo.
Los comentarios han sido insertados en el código de abajo:
0x08048428 <main+0>: push %ebp ; save previous value.
0x08048429 <main+1>: mov %esp,%ebp ; create new stack frame.
0x0804842b <main+3>: and $0xfffffff0,%esp ; align to boundary.
0x0804842e <main+6>: sub $0x10,%esp ; make space on stack.
0x08048431 <main+9>: movl $0x3,0x8(%esp) ; push values for function.
0x08048439 <main+17>: movl $0x2,0x4(%esp)
0x08048441 <main+25>: movl $0x1,(%esp)
0x08048448 <main+32>: call 0x8048404 <function> ; and call it.
0x0804844d <main+37>: leave ; tear down frame.
0x0804844e <main+38>: ret ; and exit.
0x08048404 <func+0>: push %ebp ; save previous value.
0x08048405 <func+1>: mov %esp,%ebp ; create new stack frame.
0x08048407 <func+3>: sub $0x28,%esp ; make space on stack.
0x0804840a <func+6>: mov %gs:0x14,%eax ; get sentinel value.
0x08048410 <func+12>: mov %eax,-0xc(%ebp) ; put on stack.
0x08048413 <func+15>: xor %eax,%eax ; set return code 0.
0x08048415 <func+17>: mov -0xc(%ebp),%eax ; get sentinel from stack.
0x08048418 <func+20>: xor %gs:0x14,%eax ; compare with actual.
0x0804841f <func+27>: je <func+34> ; jump if okay.
0x08048421 <func+29>: call <_stk_chk_fl> ; otherwise corrupted stack.
0x08048426 <func+34>: leave ; tear down frame.
0x08048427 <func+35>: ret ; and exit.
creo que la razón de la %gs:0x14
puede ser evidente desde arriba, pero, por si acaso, voy a elaborar aquí.
Utiliza este valor (un centinela) para poner en el marco de pila actual para que algo en la función haga algo tonto como escribir 1024 bytes en una matriz de 20 bytes creada en la pila o, en su caso:
char buffer1[5];
strcpy (buffer1, "Hello there, my name is Pax.");
entonces el centinela se sobrescribirán y el cheque al final de la función detectará que, llamando a la función de fallo para hacerle saber, y luego probablemente abortar el fin de evitar cualquier otro problema.
Si se coloca 0xdeadbeef
en la pila y esto fue cambiado a otra cosa, a continuación, un xor
con 0xdeadbeef
produciría un valor distinto de cero que se detecta en el código con la instrucción je
.
El bit correspondiente se parafrasea aquí:
mov %gs:0x14,%eax ; get sentinel value.
mov %eax,-0xc(%ebp) ; put on stack.
;; Weave your function
;; magic here.
mov -0xc(%ebp),%eax ; get sentinel back from stack.
xor %gs:0x14,%eax ; compare with original value.
je stack_ok ; zero/equal means no corruption.
call stack_bad ; otherwise corrupted stack.
stack_ok: leave ; tear down frame.
Olvidó la etiqueta de la tarea. –
Para cada uno de estos puntos, es posible que desee explicar cuál cree que es la respuesta, y luego, si está fuera, puede aclararse. –
no, esta no es una tarea .. – Adi