swtich_to宏分析 ------ 内联汇编翻译成标准汇编

发布时间:2014-10-25 2:21:21
来源:分享查询网

内敛汇编版本的switch_to #define switch_to(prev, next, last)     /do {         / /*        /  * Context-switching clobbers(彻底击败) all registers, so we clobber /  * them explicitly, via unused output variables.  /  * (EAX and EBP is not listed because EBP is saved/restored /  * explicitly for wchan access and EAX is the return value of /  * __switch_to())      /  */        / unsigned long ebx, ecx, edx, esi, edi;    /         / 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   */ /       "jmp __switch_to/n" /* regparm call  */ /       "1:/t"      /       "popl %%ebp/n/t"  /* restore EBP   */ /       "popfl/n"   /* restore flags */ /         /       /* output parameters */                       /       : [prev_sp] "=m" (prev->thread.sp),  /       /*m表示把变量放入内存,即把[prev_sp]存储的变量放入内存,最后再写入prev->thread.sp*//         [prev_ip] "=m" (prev->thread.ip),  /         "=a" (last),                                           /         /*=表示输出,a表示把变量last放入ax,eax = last*/         /         /         /* clobbered output registers: */  /         "=b" (ebx), "=c" (ecx), "=d" (edx),  /         /*b 变量放入ebx,c表示放入ecx,d放入edx,S放入si,D放入edi*//         "=S" (esi), "=D" (edi)    /                /         /* input parameters: */    /       : [next_sp]  "m" (next->thread.sp),  /       /*next->thread.sp 放入内存中的[next_sp]*//         [next_ip]  "m" (next->thread.ip),  /                /         /* regparm parameters for __switch_to(): */ /         [prev]     "a" (prev),    /         /*eax = prev  edx = next*//         [next]     "d" (next)    /         /       : /* reloaded segment registers */   /   "memory");     /} while (0)     标准汇编版本的switch_to: 1 把prev和next分别保存在寄存器中,即寄存器传参 movl prev,%eax movl next,%edx   2 把eflags和ebp保存在当前的堆栈中 pushfl pushl %ebp   3 把esp的内容保存到prev->thread.esp中,以使该字段指向prev内核栈的栈顶 movl %esp,484(%eax) 注:484(%eax) ,表示内存但愿的地址=(%eax) + 484   4 把next->thread.sp装入esp,内核开始在next的指令空间中操作,这条指令完成了进程之间的切换。 可以会想thread_info数据结构,内核栈和进程描述符组成的8K的数据结构 movl 484(%edx),%esp   5 把标记为1f的地址存入prev->thread.eip,即被替换出的进程在下次被schedule()选择执行时,从这条指令开始执行 movl $1f,480(%eax)   6 把next->thread.eip(绝大多数情况是一个被标记为1的地址)的值压入next的内核栈 pushl 480(%edx)   7 跳到__swtich_to() c语言函数开始执行 jmp __swtich_to   8 这里被进程next替换的进程prev再次获得CPU:它执行一些保存eflags和ebp的寄存器内容指令,这两条指令的第一条指令被标记为1(这是《深入理解unix》书上说的)。感觉从__swtich_to返回时ip已经指向了next的第一条指令,因为在执行ret指令的时候,把sp处保存的next->ip弹出赋给了next的eip,所以书上说prev再次获得cpu应该是不对的。 1:     pop %ebp     popfl   从标号1:开始已经进入了next的指令空间,可以这么理解1:就是next进程的第一条指令,执行         pop %ebp     popfl 后完成了最后的切换,即栈和状态字的恢复,恢复成next的堆栈基址和状态字。   个人理解:linux里面的每个进程(新创建的进程除外)的第一条指令应该都是 1:     pop %ebp     popfl 每个进程一开始全是执行这两条指令,之后才各自干自己的事去。

返回顶部
查看电脑版