今天我们分析一下时间片轮转代码中内嵌的汇编代码,
asm volatile( "movl %1,%%esp\n\t" /* set task[pid].thread.sp to esp */ "pushl %1\n\t" /* push ebp */ "pushl %0\n\t" /* push task[pid].thread.ip */ "ret\n\t" /* pop task[pid].thread.ip to eip */ "popl %%ebp\n\t" : : "c" (task[pid].thread.ip),"d" (task[pid].thread.sp) /* input c or d mean %ecx/%edx*/ );
movl %1,%%esp\n\t 将进程的栈顶(task[pid].thread.sp)赋给esp寄存器
pushl %1\n\t 保存ebp的值(此时esp等于ebp)
pushl %0\n\t 然后保存进程的入口地址
ret\n\t ret即为popl eip,把此时esp所指向地址内容(即为process函数,进程的入口)赋给eip,esp上移易为重新指到task[pid].thread.sp
此时函数跳转到process函数。
popl %%ebp\n\t 此句话为程序调用结束时释放栈内元素
下面将将调度函数中的汇编指令
情况1:若此指令前面已经执行过
asm volatile( "pushl %%ebp\n\t" /* save ebp */ "movl %%esp,%0\n\t" /* save esp */ "movl %2,%%esp\n\t" /* restore esp */ "movl $1f,%1\n\t" /* save eip */ "pushl %3\n\t" "ret\n\t" /* restore eip */ "1:\t" /* next process start here */ "popl %%ebp\n\t" : "=m" (prev->thread.sp),"=m" (prev->thread.ip) : "m" (next->thread.sp),"m" (next->thread.ip) );
pushl %%ebp\n\t movl %%esp,%0\n\t这两句话分别表示存储当前进程的eip和esp
movl %2,%%esp这句话是把esp指向下一个进程
movl $1f,%1\n\t存储当前进程的eip
pushl %3把下一个进程的eip入栈
ret执行process
情况1:若此指令首次执行
asm volatile( "pushl %%ebp\n\t" "movl %%esp,%0\n\t" "movl %2,%%esp\n\t" "movl %2,%%ebp\n\t" "movl $1f,%1\n\t" "pushl %3\n\t" "ret\n\t" : "=m" (prev->thread.sp),"=m" (prev->thread.ip) : "m" (next->thread.sp),"m" (next->thread.ip) );
大体与情况一相同,只不过需要把ebp赋值,因为进程首次执行,因此需要把ebp赋值,否则系统不知去哪里找