assembly - Necesita ayuda para verificar el código de ensamblaje
gdb segmentation-fault (1)
Antes que nada, guardé y restauré una al lado de la otra (y mezclé las instrucciones de restauración) para poder ver si las compensaciones estaban mal. Se ve bien desde esa perspectiva.
save_context: restore_context:
mov %rdi,%rax mov %rdi,%rax
mov %rbx, 16(%rax) mov 16(%rax),%rbx
mov %r12, 24(%rax) mov 24(%rax), %r12
mov %r13, 32(%rax) mov 32(%rax), %r13
mov %r14, 64(%rax) mov 64(%rax), %r14
mov %r15, 48(%rax) mov 48(%rax), %r15
mov %rbp, 56(%rax) mov 56(%rax), %rbp
mov %rsp, 64(%rax) mov 64(%rax), %rsp
mov %rdx, (%rsp) mov (%rsp), %rdx
mov %rdx, (%rax) mov (%rax), %rdx
xor %rax,%rax xor %rax,%rax
inc %rax
ret ret
Hasta aquí todo bien.
Sin embargo, ahora quiero ver las compensaciones mencionadas:
16
24
32
64 <-- why 64 here?
48
56
64 <-- Oops 64 again?
Creo que ese es el culpable. Guarda dos registros en la misma dirección.
Ahora, curiosamente, en la salida de gdb parece correcto. Así que supongo que no nos mostró su fuente original.
Para evitar tales problemas, generalmente es mejor definir su estructura con instrucciones de definición que definan los diferentes desplazamientos.
De lo contrario, podrías describir tu contexto un poco más. Esto no se parece al código que podría ejecutar con un sistema operativo, sin embargo, menciona gdb, por lo que parece que se estaría ejecutando en Linux. Hay dos posibilidades en las que puedo pensar: su contexto se sobrescribe antes de que ocurra la restauración, la pila después del guardado cambia mucho (me imagino) y cuando restaura, termina con una pila completamente diferente, pero restaura el %esp
para lo que ahora es "datos aleatorios" en lo que se refiere a la pila. Entonces el ret debería funcionar (recuperas eso) pero después de eso ... ¡quién sabe!
Actualización de preguntas en el comentario:
1) Sí, me estoy ejecutando en Linux porque la versión 32 de esto estaba funcionando bien y supuse que así sería ... ¿Me equivoco al asumir que?
Ah. Podría ser que la pila se administre de manera diferente, pero si llama a sus funciones usted mismo, entonces eso no debería importar aquí. ¿También modifica rdx que no puede permitirse?
2) Veo lo que quiere decir que el contexto se sobrescribe en algún lugar del código. Así que intenté colocar guardar y restaurar inmediatamente después uno del otro. Todavía me da error de segmentación, lo que significa que algo está mal en mi código de ensamblaje.
En realidad, tu código se vería así:
MOV ..., %rdi
CALL save
TEST %rax
JNE done
[...do things, but no RET...]
MOV ..., %rdi
CALL restore
---not reached---
done:
RET
Cuando regrese de la función de guardar, la dirección de devolución que guardó se encuentra justo después de CALL save
, razón por la cual %rax
a 0 o 1 para saber si regresa del guardado o la restauración. Hasta aquí, no veo un problema.
Lo único que se me ocurre es que% rdi cambia entre guardar y restaurar llamadas, pero si cambiaste tu código para hacer solo esas dos llamadas, me imagino que ese no es el caso. ¿SEGV donde el =>
está indicado en tu pregunta? ¿O sería SEGV en la línea antes?
3) ¿Cómo depurar tales errores?
Me gustaría rastrear el uso de stepi
y verificar que exactamente lo que espera sucede en cada instrucción. Observe que el puntero de pila guardado es el que recibe en la restauración y que la dirección de retorno es correcta.
GDB se puede utilizar para print
un conjunto de entradas cada vez que ejecuta un comando. Entonces, si haces eso y luego te stepi
+ ingresas cualquier cantidad de tiempo después de eso, deberías ver tu información en cada paso y ver cuándo sale mal. (es decir, imprimir registros y datos en% rdi?)
Tengo este ensamblaje que compila bien pero obtiene un error de segmentación en la restauración. ¿Alguien puede verificarlo? Esto es para la arquitectura x86_64
save_context:
mov %rdi,%rax /* Get our context pointer */
/* Don''t need to save A */
mov %rbx, 16(%rax) /* Save B */
mov %r12, 24(%rax) /* Save r12 */
mov %r13, 32(%rax) /* Save r13 (8*3+16)*/
mov %r14, 40(%rax) /* Save r13 */
mov %r15, 48(%rax) /* Save r13 */
mov %rbp, 56(%rax) /* Save frame pointer */
mov %rsp, 64(%rax) /* Save stack pointer */
mov (%rsp), %rdx /* Fetch our return address */
mov %rdx, (%rax) /* Save our return address */
xor %rax,%rax /* Construct return code of 1 */
inc %rax
ret
La restauración es algo como esto
restore_context:
mov %rdi,%rax /* Get our context pointer */
mov 64(%rax), %rsp /* Restore stack pointer */
mov (%rax), %rdx /* Fetch our return address */
mov %rdx, (%rsp)
mov 16(%rax),%rbx /* Restore B */
mov 24(%rax), %r12 /* Restore r12 */
mov 32(%rax), %r13 /* Restore r13 */
mov 40(%rax), %r14 /* Restore r14 */
mov 48(%rax), %r15 /* Restore r15 */
mov 56(%rax), %rbp /* Restore frame pointer */
xor %rax,%rax /* Return 0 */
ret
Cuando uso el gdb para depurar la función, obtengo esto. Después de la falla de segmentación.
0x0000000000424c4c <+0>: mov %rdi,%rax
0x0000000000424c4f <+3>: mov 0x18(%rax),%rsp
0x0000000000424c53 <+7>: mov (%rax),%rbx
=> 0x0000000000424c56 <+10>: mov %rbx,(%rsp)
0x0000000000424c5a <+14>: mov 0x10(%rax),%rbx
0x0000000000424c5e <+18>: mov 0x20(%rax),%rbp
0x0000000000424c62 <+22>: mov 0x28(%rax),%r12
0x0000000000424c66 <+26>: mov 0x30(%rax),%r13
0x0000000000424c6a <+30>: mov 0x38(%rax),%r14
0x0000000000424c6e <+34>: mov 0x40(%rax),%r15
0x0000000000424c72 <+38>: xor %rax,%rax
0x0000000000424c75 <+41>: retq
0x0000000000424c76 <+42>: nop
0x0000000000424c77 <+43>: nop
disasseble save_context
0x0000000000424c1c <+0>: mov %rdi,%rax
0x0000000000424c1f <+3>: mov %rbx,0x10(%rax)
0x0000000000424c23 <+7>: mov %rsp,0x18(%rax)
0x0000000000424c27 <+11>: mov %rbp,0x20(%rax)
0x0000000000424c2b <+15>: mov %r12,0x28(%rax)
0x0000000000424c2f <+19>: mov %r13,0x30(%rax)
0x0000000000424c33 <+23>: mov %r14,0x38(%rax)
0x0000000000424c37 <+27>: mov %r15,0x40(%rax)
0x0000000000424c3b <+31>: mov (%rsp),%rdx
0x0000000000424c3f <+35>: mov %rdx,(%rax)
0x0000000000424c42 <+38>: xor %rax,%rax
0x0000000000424c45 <+41>: inc %rax
0x0000000000424c48 <+44>: retq
0x0000000000424c49 <+45>: nopl (%rax)
Más información sobre el contexto
save_context (context) context = {4243415, 0, 0, 4242944, 140737488348624, 0, 0, 140737488348368, 140737488348312, 0}
restore_context (new_context) new_context = {4249788, 0, 0, 0, 0, 0, 6719200, 6719184, 0, 0}
Falla después de restaurar el contexto. intenté save_context y luego restore_context. Eso funciona. Solo verificando si algo está mal con el contexto y el nuevo contexto para 64bit?!?!
Aquí está la versión de 32 bits
save_context:
movl 4(%esp),%eax /* Get our context pointer */
/* Don''t need to save A */
movl %ebx, 12(%eax) /* Save B */
movl %esi, 16(%eax) /* Save SI */
movl %edi, 20(%eax) /* Save DI */
movl %ebp, 24(%eax) /* Save frame pointer */
movl %esp, 28(%eax) /* Save stack pointer */
movl 0(%esp), %edx /* Fetch our return address */
movl %edx, 0(%eax) /* Save our return address */
xorl %eax,%eax /* Construct return code of 1 */
incl %eax
ret
Restore Context:
restore_context:
movl 4(%esp),%eax /* Get our context pointer */
movl 28(%eax), %esp /* Restore stack pointer */
movl 0(%eax),%edx /* Get our return address */
movl %edx, 0(%esp) /* Put it on the stack in the right
spot. */
movl 12(%eax),%ebx /* Restore B */
movl 16(%eax), %esi /* Restore SI */
movl 20(%eax), %edi /* Restore DI */
movl 24(%eax), %ebp /* Restore frame pointer */
xorl %eax,%eax /* Return 0 */
ret
Algúna idea de cómo arreglar esto ?