Linux 64位上下文开关

Linux 64位上下文开关,linux,assembly,linux-kernel,x86,x86-64,Linux,Assembly,Linux Kernel,X86,X86 64,在32位模式下的switch_to宏中,在调用switch_to函数之前执行以下代码: asm volatile("pushfl\n\t" /* save flags */ \ "pushl %%ebp\n\t" /* save EBP */ \ "movl %%esp,%[prev_sp]\n\t" /* save ESP */ \ "movl %[next_sp],%%esp\n\t"

在32位模式下的switch_to宏中,在调用switch_to函数之前执行以下代码:

asm volatile("pushfl\n\t"       /* save    flags */ \
         "pushl %%ebp\n\t"      /* save    EBP   */ \
         "movl %%esp,%[prev_sp]\n\t"    /* save    ESP   */ \
         "movl %[next_sp],%%esp\n\t"    /* restore ESP   */ \
         "movl $1f,%[prev_ip]\n\t"  /* save    EIP   */ \
         "pushl %[next_ip]\n\t" /* restore EIP   */ \
         __switch_canary                    \
         "jmp __switch_to\n"    /* regparm call  */ 
EIP被推送到堆栈上(还原EIP)。当切换到结束时,有一个返回到该位置的ret。 以下是相应的64位代码:

    asm volatile(SAVE_CONTEXT                     \
     "movq %%rsp,%P[threadrsp](%[prev])\n\t" /* save RSP */   \
     "movq %P[threadrsp](%[next]),%%rsp\n\t" /* restore RSP */    \
     "call __switch_to\n\t" 
在那里,只保存和恢复rsp。我想裂缝已经开始了 堆栈的顶部。但我找不到这样做的指导。 64位上下文切换,特别是对于RIP寄存器,实际上是如何完成的


提前谢谢

在32位内核中,
线程.ip
可能是以下之一:

  • 中的
    1
    标签切换到
  • ret\u from\u fork
  • ret\u from\u kernel\u thread
通过使用
push
+
jmp
对模拟
调用
,可以确保返回到正确的位置

在64位内核中,
thread.ip
不是这样使用的。执行总是在调用
后继续执行(在32位的情况下,它曾经是
1
标签)。因此,不需要模拟
调用
,它可以正常完成。在
切换到
返回后,使用条件跳转将
从\u fork
发送到
ret\u(您省略了此部分):

使用
entry\u 64.S
中的另一个条件跳转,将
ret\u from\u kernel\u线程
合并到
ret\u from\u fork
路径中:

ENTRY(ret_from_fork)
        DEFAULT_FRAME

        LOCK ; btr $TIF_FORK,TI_flags(%r8)

        pushq_cfi $0x0002
        popfq_cfi                               # reset kernel eflags

        call schedule_tail                      # rdi: 'prev' task parameter

        GET_THREAD_INFO(%rcx)

        RESTORE_REST

        testl $3, CS-ARGOFFSET(%rsp)            # from kernel_thread?
        jz   1f

call
显然保存了
%%rip
。是的,但我们讨论的是下一个进程的rip。它以相同的方式保存在目标堆栈上
ENTRY(ret_from_fork)
        DEFAULT_FRAME

        LOCK ; btr $TIF_FORK,TI_flags(%r8)

        pushq_cfi $0x0002
        popfq_cfi                               # reset kernel eflags

        call schedule_tail                      # rdi: 'prev' task parameter

        GET_THREAD_INFO(%rcx)

        RESTORE_REST

        testl $3, CS-ARGOFFSET(%rsp)            # from kernel_thread?
        jz   1f