This procedure is supposed to load register values from memory into the CPU. The values are passed to it from C, as the first and only parameter to the procedure. Of course one of the registers it loads is RIP, and so the behaviour I want is that the CPU will jump to execute wherever RIP points.
The code is as follows (GNU assembly):
Code: Select all
load_regs:
push %rbp
mov %rsp, %rbp
xchg %bx, %bx
# Load RFLAGS
mov 152(%rdi), %rax
push %rax
popfq
# Load CR3
mov 160(%rdi), %rax
mov %rax, %cr3
# Load general purpose regs
mov 8(%rdi), %rbx
... These lines omitted
mov 120(%rdi), %r15
cli
# Push RFLAGS
pushfq
# Push CS
mov 136(%rdi), %rax
push %rax
# Push saved instruction pointer as iret return address
mov 128(%rdi), %rax
push %rax
mov (%rdi), %rax
iretq
Code: Select all
| STACK 0xffff80007ff85f18 [0xffffffff80000d10]
| STACK 0xffff80007ff85f20 [0x0010001000100008]
| STACK 0xffff80007ff85f28 [0x0000000000000082]
My understanding of iretq is that it should perform the following operation:(https://namazso.github.io/x86/html/IRET ... IRETQ.html)
Code: Select all
RIP := Pop();
CS := Pop(); (* 64-bit pop, high-order 48 bits discarded *)
tempRFLAGS := Pop();
I'll explain the logic of the `load_regs` procedure:
- Up until the cli instruction I simply take the corresponding register values from the struct pointer and load them into the registers. This works.
- After the cli instruction, I set up the top of the stack for iretq to use. First RFLAGS is pushed, then the CS register is pushed from the struct.
- Finally, I push the RIP value from the struct on to the stack, and then put the correct value of rax into that register.
What's going wrong here? Clearly most of this procedure is working as intended, at least to my understanding, because the stack looks as if it's set up correctly by the end.