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

内敛汇编版本的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

每个进程一开始全是执行这两条指令,之后才各自干自己的事去。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值