1、step1:复制两个变量到寄存器:复制两个变量到寄存器:prev a(prev)next d(next)即即:eax=prev_A 或或 eax=%p(%ebp_A)edx=next_A 或或 edx thread.sp=esp_A 在调用在调用switch_to时,时,prev是指向是指向A进程自己的进程描述符进程自己的进程描述符的。的。ebp%ebp 0 4 8 12 eflags-4 进程进程A的内核栈空间的内核栈空间0 x124 0 x120 0 x11c 0 x118 0 x114 0 x110 0 x10c0 x108 0 x104 0 x100%eax%edx%ecx%ebx%e
2、si%edi%esp%ebpprev_Anext_AA_ebp%espEsp_A内存空间内存空间寄存器组寄存器组next_ip%flagsA_flag%eax%edx%ecx%ebx%esi%edi%esp%ebpprev_Anext_AA_ebpEsp_A内存空间内存空间寄存器组寄存器组next_ipebp%ebp 0 4 8 12 eflags-4 进程进程A的内核栈空间的内核栈空间0 x2080 x204 0 x2000 x114 0 x110 0 x10c0 x108 0 x104 0 x100%esp0 x20c进程进程B的内核栈空间的内核栈空间step4:从从next(进程(进程B
3、)的描述符中取出之前从)的描述符中取出之前从B切换出去时切换出去时保存的保存的esp_B。movl%next_sp,%espnt/*restore ESP*/它可以表示成:它可以表示成:esp_B thread.sp%flagsA_flagstep5:把标号为把标号为1的指令地址保存到的指令地址保存到A进程描述符的进程描述符的ip域:域:movl$1f,%prev_ipnt /*save EIP */它可以表示成:它可以表示成:prev_A-thread.ip=%1f ebp%ebp 0 4 8 12 eflags-4 进程进程A的内核栈空间的内核栈空间0 x2080 x204 0 x2000
4、 x114 0 x110 0 x10c0 x108 0 x104 0 x100%esp0 x20c进程进程B的内核栈空间的内核栈空间%eax%edx%ecx%ebx%esi%edi%esp%ebpprev_Anext_AA_ebpEsp_A内存空间内存空间寄存器组寄存器组Prev_A_ipnext_ip$1f%flagsA_flagstep6:将返回地址保存到堆栈,然后调用_switch_to()函数,_switch_to()函数完成硬件上下文切换。pushl%next_ipnt /*restore EIP */根据esp的位置,压到了B的堆栈里面 jmp _switch_ton /*regp
5、arm call */ebp%ebp 0 4 8 12 eflags-4 进程进程A的内核栈空间的内核栈空间0 x2080 x204 0 x2000 x114 0 x110 0 x10c0 x108 0 x104 0 x100%esp0 x20c进程进程B的内核栈空间的内核栈空间%eax%edx%ecx%ebx%esi%edi%esp%ebpprev_Anext_AA_ebpEsp_A内存空间内存空间寄存器组寄存器组Prev_A_ipnext_ipnext_ip%flagsA_flagnext_ipebpeflagsstep7:_switch_to 切换硬件上下文件ebp%ebp 0 4 8
6、12 eflags-4 进程进程A的内核栈空间的内核栈空间0 x2080 x204 0 x2000 x114 0 x110 0 x10c0 x108 0 x104 0 x100%esp0 x20c进程进程B的内核栈空间的内核栈空间%eax%edx%ecx%ebx%esi%edi%esp%ebpprev_Anext_AA_ebpEsp_A内存空间内存空间寄存器组寄存器组Prev_A_ipnext_ipnext_ipTSS_A%flagsAflagnext_ipebpeflags%eip$1f step7:_switch_to 切换硬件上下文件ebp%ebp 0 4 8 12 eflags-4 进
7、程进程A的内核栈空间的内核栈空间0 x2080 x204 0 x2000 x114 0 x110 0 x10c0 x108 0 x104 0 x100%esp0 x20c进程进程B的内核栈空间的内核栈空间%eax%edx%ecx%ebx%esi%edi%esp%ebpprev_Bnext_BA_ebpEsp_A内存空间内存空间寄存器组寄存器组Prev_A_ipnext_ipnext_ipTSS_B%flagsA_flagebpeflagsStep9:_switch_to()返回后继续从1:标号后面开始执行,修改ebp到B的内核堆栈,恢复B的eflags:popl%ebpnt /*restore
8、 EBP */popfln /*restore flags*/ebp%ebp 0 4 8 12 eflags-4 ebp进程进程A的内核栈空间的内核栈空间0 x2080 x204 0 x2000 x114 0 x110 0 x10c0 x108 0 x104 0 x100%esp0 x20c进程进程B的内核栈空间的内核栈空间%eax%edx%ecx%ebx%esi%edi%esp%ebpprev_Bnext_BEsp_A内存空间内存空间寄存器组寄存器组Prev_A_ipnext_ipeflagsnext_ip%flagsB_flagB_ebpStep10:将eax写入last,以在B的堆栈中保存正确的prev信息。=a(last)即 last_B=%eaxebp%ebp 0 4 8 12 eflags-4 进程进程A的内核栈空间的内核栈空间0 x2080 x204 0 x2000 x114 0 x110 0 x10c0 x108 0 x104 0 x100%esp0 x20c进程进程B的内核栈空间的内核栈空间%eax%edx%ecx%ebx%esi%edi%esp%ebpnext_BEsp_A内存空间内存空间寄存器组寄存器组Prev_A_iplastnext_ipnext_ip%flagsB_flagB_ebp