Curious Guy 007
Curious Guy 007

Reputation: 571

Need help verifying assembly code

I have this assembly which compiles fine but gets a segmentation fault on restore. Can someone verify it .This is for x86_64 architecture

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 goes something like this

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

When I use the gdb to debug the function i get this .After the segmentation fault.

   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)

More info about the context

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}

It fails after restore context. i tried save_context and then restore_context. That works. Just checking if something is wrong with the context and new context for 64bit ?!?!

Here is the 32bit version

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

Any idea how to fix this ?

Upvotes: 3

Views: 2094

Answers (1)

Alexis Wilke
Alexis Wilke

Reputation: 20798

First of all I put the save and restore side by side (and shuffle the restore instructions) so I could see whether the offsets were awry. It looks good from that prospective.

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

So far so good.

However, now I want to look at the said offsets:

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

I think that is the culprit. You save two registers at the same address.

Now strangely enough in the gdb output it looks correct. So I guess you did not show us your original source.

To avoid such problems, it is generally better to define your structure with define instructions defining the different offsets.

Otherwise, could you describe your context a little more. This does not look like code you could run with an OS, yet you mention gdb, so it sounds like you would be running in Linux. There are two possibilities I can think of: your context gets overwritten before the restore happens, the stack after the save changes a lot (I would imagine) and when you restore you end up with a completely different stack, yet you restore %esp to what now is "random data" as far as the stack is concerned. So the ret should work (you restore that much) but after that... who knows!


Update from questions in the comment:

1) Yes i am running on linux because the 32version of this was working fine and I guessed so will this .. Am i wrong to assume that ??

Ah. It could be that the stack is managed differently, but if you call your functions yourself, then that should not matter here. Also you modify rdx which may not be allowed?

2) I see what you mean by context getting overwritten in the code somewhere. So I tried placing save and restore immediately after each other. Still it gives me segmentation fault which means something is wrong in my assembly code.

Actually, your code would look something like this:

  MOV ..., %rdi
  CALL save
  TEST %rax
  JNE done
  [...do things, but no RET...]
  MOV ..., %rdi
  CALL restore
  ---not reached---
done:
  RET

When you return from the save function, the return address that you saved is right after the CALL save, which is why you %rax to 0 or 1 so you know whether you are returning from the save or the restore. Up to here, I do not see a problem.

The one thing I can think of would be that %rdi changes between the save and restore calls, but if you changed your code to do just those two calls, I would imagine that is not the case. Does it SEGV where the => is indicated in your question? Or would it SEGV on the line before?

3) How to debug such errors ?

I would trace using stepi and verify that exactly what you expect happens on each instruction. See that the stack pointer saved is the one you get back in the restore and see that the return address is correct.

GDB can be used to print a set of entries each time you run a command. So if you do that and then stepi + enter any number of time after that, you should see your info on each step and see when it goes awry. (i.e. print registers and data at %rdi?)

Upvotes: 4

Related Questions