需要帮助验证汇编代码

时间:2014-05-21 22:37:09

标签: assembly gdb segmentation-fault x86-64 cpu-registers

我有这个程序集编译得很好但在恢复时会出现分段错误。有人可以验证它。这适用于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

恢复就像这样

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

当我使用gdb来调试函数时,我得到了这个。在分段错误之后。

   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

反汇编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)

有关上下文的更多信息

save_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}

恢复上下文后失败。我尝试了save_context,然后是restore_context。这样可行。只是检查64bit的上下文和新上下文是否有问题?!?!

这是32位版本

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:
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

知道如何解决这个问题吗?

1 个答案:

答案 0 :(得分:4)

首先,我将保存和恢复并排放置(并恢复恢复指令),以便我可以看到偏移是否错误。从那个角度来看,它看起来很不错。

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

到目前为止一切顺利。

但是,现在我想看看上述偏移量:

16
24
32
64   <-- why 64 here?
48
56
64   <-- Oops 64 again?

我认为那是罪魁祸首。您可以在同一地址保存两个寄存器。

现在奇怪的是在gdb输出中它看起来是正确的。所以我猜你没有告诉我们你原来的来源。

为避免此类问题,通常最好使用定义不同偏移的定义指令来定义结构。

否则,你能不能再描述一下你的背景了。这看起来不像你可以用OS运行的代码,但你提到了gdb,所以听起来你会在Linux上运行。我可以想到两种可能性:在恢复发生之前你的上下文被覆盖,保存后的堆栈发生了很大的变化(我想象),当你恢复时你最终会得到一个完全不同的堆栈,但是你还原{{1现在是什么&#34;随机数据&#34;就堆栈而言。所以ret应该工作(你恢复那么多)但在那之后......谁知道!


更新评论中的问题:

  

1)是的我在Linux上运行,因为32版本工作正常,我猜这将是这样的......我错误地认为??

阿。可能是堆栈的管理方式不同,但如果你自己调用你的函数,那么这应该不重要。你还修改了可能不被允许的rdx吗?

  

2)我看到你在代码中被覆盖的上下文意味着什么。所以我尝试在彼此之后立即进行保存和恢复。它仍然给我分段错误,这意味着我的汇编代码出错了。

实际上,您的代码看起来像这样:

%esp

当您从保存功能返回时,您保存的返回地址就在 MOV ..., %rdi CALL save TEST %rax JNE done [...do things, but no RET...] MOV ..., %rdi CALL restore ---not reached--- done: RET 之后,这就是您CALL save为0或1的原因所以您知道是否从保存返回或恢复。到目前为止,我没有看到任何问题。

我能想到的一件事就是%rdi在保存和恢复调用之间发生了变化,但是如果你改变你的代码只做那两个调用,我会想到情况并非如此。是否在您的问题中指出%rax的SEGV?或者它之前是SEGV吗?

  

3)如何调试此类错误?

我会使用=>进行跟踪,并验证您在每条指令上发生的确切结果。看到保存的堆栈指针是您在还原中返回的堆栈指针,并且看到返回地址是正确的。

每次运行命令时,GDB都可用于stepi一组条目。因此,如果您这样做,然后print +在此之后输入任意数量的时间,您应该看到每个步骤的信息,看看它何时出错。 (即在%rdi打印寄存器和数据?)