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

本文详细解析了Linux内核中的上下文切换函数switch_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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值