问题
In Linux (kernel 3.14.4), a process usually has two stacks - the user level stack and the kernel stack. When a system call is invoked in the process, the OS will first push the current registers into the kernel stack, and then switch to the kernel stack to execute the system call. When the system call finishes, the values of the registers that were previously pushed into the kernel stack will be poped out and restored to the corresponding registers, so that the user level process can continue executing. (correct me if I am wrong)
In the following code, the function main() invoked a system call, and printed out the value of the user level register RSP (pointing to the top of the stack) before and after the system call. Normally, rsp_beofer equals to rsp_after in this case.
I wanted to see whether a system call can change the user level RSP. Therefore, inside the system call, I first validated that the RSP of the user stack was on the kernel stack. Then I modified the value of RSP (decrease it by 0x10) on the kernel stack. I was expecting that rsp_before is 0x10 larger than rsp_after. However, it turned out rsp_before is still equal to rsp_after.
I am wondering why these two values are still equal even after I modifed the user level RSP in the system call? How does a system call restore the user level registers when it finishes executing?
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;
}
来源:https://stackoverflow.com/questions/38361742/how-does-a-system-call-restore-the-user-level-registers-when-it-finishes-executi