关于进程切换
以下是2.4.0内核中switch_to的定义:
#define switch_to(prev,next,last) do {
asm volatile("pushl %%esint"
17: "pushl %%edint"
18: "pushl %%ebpnt"
"movl %%esp,%0nt" /* save ESP */
"movl %3,%%espnt" /* restore ESP */
"movl $1f,%1nt" /* save EIP */
"pushl %4nt" /* restore EIP */
23: "jmp __switch_ton"
"1:t"
"popl %%ebpnt"
"popl %%edint"
"popl %%esint"
:"=m" (prev->thread.esp),"=m" (prev->thread.eip),
"=b" (last)
:"m" (next->thread.esp),"m" (next->thread.eip),
"a" (prev), "d" (next),
"b" (prev));
} while (0)
它在23行通过jmp __switch_to“调用”函数__switch_to(),其原型为
void __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
结合switch_to的17和18行,可知next_p的值原在edi中,prev_p在ebp中。
但switch_to的输入部却表明,prev_p是在eax及ebx中,next_p是在edx中。请问这是怎么回事。谢谢
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
asm-i386/system.h中定义的
void FASTCALL(__switch_to(struct task_struct *prev, struct task_struct *next));
多谢seanseu兄的热心帮助。不过2.4.0内核中是这样定义__switch_to的:
void __switch_to(struct task_struct *prev_p,struct task_struct *next_p),
并未将它定义成fastcall啊。这是怎么回事呢?谢谢
关于eflags寄存器的保存,我看了一下2.6.11的代码,其中switch_to已经做出了如下修改:
#define switch_to(prev,next,last) do {
16 unsigned long esi,edi;
17 asm volatile("pushflnt"
18 "pushl %%ebpnt"
19 "movl %%esp,%0nt" /* save ESP */
20 "movl %5,%%espnt" /* restore ESP */
21 "movl $1f,%1nt" /* save EIP */
22 "pushl %6nt" /* restore EIP */
23 "jmp __switch_ton"
24 "1:t"
25 "popl %%ebpnt"
26 "popfl"
27 :"=m" (prev->thread.esp),"=m" (prev->thread.eip),
28 "=a" (last),"=S" (esi),"=D" (edi)
29 :"m" (next->thread.esp),"m" (next->thread.eip),
30 "2" (prev), "d" (next));
31 } while (0)
可以看到esi,edi寄存器已经改为通过局部变量保存,而且增加了pushflnt,保存了eflags.关于这点我也比较疑惑,似乎和编译器有关,或者与__switch_to有关,没有仔细研究,不知有大侠是否有研究.另外,把esi和edi改为局部变量保存也是有原因的,不知有人是否知道.似乎与2.6内核的压栈出栈有关.
struct task_struct fastcall * __switch_to(struct task_struct *prev_p, struct task_struct *next_p),这个是__switch_to的函数定义,关于寄存器传值,可以去看一下fastcall的说明.也就是regparm(3)的说明
谢谢。那么请问,编译器在编译__switch_to()时,遇到prev_p就应该编译为eax或ebx,遇到next_p就应该编译为edx.编译器是怎样做到这一点的呢?因为在__switch_to()中并未对编译规则作出说明啊
那么ecx和eflags寄存器为什么不保存呢?
默认的参数传递都是什么?什么时候是通过寄存器,什么时候通过堆栈?
另外__switch_to中只看到加载next进程调试寄存器的操作,却没有保存prev进程的调试寄存器,why?
__switch_to参数并不是通过stack传递的,而是通过寄存器传,所以prev_p是在eax及ebx中,next_p是在edx中。一开始的三个push只是保存该进程的这三个寄存器。因为编译器假定这三个寄存器在switch_to中是不改变的。