assembly gdb segmentation-fault x86-64 cpu-registers

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 ?