您的位置:首页 > 其它

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

2009-04-11 12:52 169 查看
内敛汇编版本的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

每个进程一开始全是执行这两条指令,之后才各自干自己的事去。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: