系统调用在完成执行后如何恢复用户级别寄存器?

时间:2016-07-13 21:08:24

标签: linux stack kernel

在Linux(内核3.14.4)中,进程通常有两个堆栈 - 用户级堆栈和内核堆栈。在进程中调用系统调用时,操作系统将首先将当前寄存器推入内核堆栈,然后切换到内核堆栈以执行系统调用。当系统调用结束时,先前推入内核堆栈的寄存器的值将被输出并恢复到相应的寄存器,以便用户级进程可以继续执行。 (如果我错了,请纠正我)

在下面的代码中,函数main()调用系统调用,并在系统调用之前和之后打印出用户级别寄存器RSP(指向堆栈顶部)的值。通常,在这种情况下,rsp_beofer等于rsp_after。

我想查看系统调用是否可以更改用户级别的RSP。因此,在系统调用内部,我首先验证了用户堆栈的RSP是在内核堆栈上。然后我修改了内核堆栈上的RSP值(减去0x10)。我原以为rsp_before比rsp_after大0x10。但是,事实证明rsp_before仍然等于rsp_after。

我想知道为什么即使我在系统调用中修改了用户级别的RSP后这两个值仍然相等?系统调用在完成执行后如何恢复用户级别寄存器?

int main(void){
    #define __syscall_clobber "r11","rcx","memory"
    #define __syscall "syscall"
    long ret;

    register unsigned long rsp_before asm("rsp");
    printf("rsp_before = %p\n", (unsigned long *)rsp_before);

    /*invoke the system call, in which the value of user level RSP on the kernel stack is decreased by 0x10*/
     __asm__ volatile 
     (
        __syscall
        : "=a" (ret)
        : "0" (316) : __syscall_clobber 
     );

    register unsigned long rsp_after asm("rsp");
    printf("rsp_after = %p\n", (unsigned long *)rsp_after);

}

/*syscall 316*/
asmlinkage long syscall_316(void)
{
    /*get the bottom of current kernel stack*/
    register unsigned long rbp asm("rbp");

    /*the user level RSP is stored at '(unsigned long *)rbp + 15'*/
    *((unsigned long *)rbp + 15) = *((unsigned long *)rbp + 15) - 0x10;

    return 0;
}

0 个答案:

没有答案