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