- 论坛徽章:
- 11
|
本帖最后由 zylthinking 于 2011-11-28 19:27 编辑
- 15#define switch_to(prev,next,last) do { \
- 16 asm volatile("pushl %%esi\n\t" \
- 17 "pushl %%edi\n\t" \
- 18 "pushl %%ebp\n\t" \
- 19 "movl %%esp,%0\n\t" /* save ESP */ \
- 20 "movl %3,%%esp\n\t" /* restore ESP */ \
- 21 "movl $1f,%1\n\t" /* save EIP */ \
- 22 "pushl %4\n\t" /* restore EIP */ \
- 23 "jmp __switch_to\n" \
- 24 "1:\t" \
- 25 "popl %%ebp\n\t" \
- 26 "popl %%edi\n\t" \
- 27 "popl %%esi\n\t" \
- 28 :"=m" (prev->thread.esp),"=m" (prev->thread.eip), \
- 29 "=b" (last) \
- 30 :"m" (next->thread.esp),"m" (next->thread.eip), \
- 31 "a" (prev), "d" (next), \
- 32 "b" (prev)); \
- 33} while (0)
复制代码 如代码, 分析寄存器的变化:
首先是 ABI:
eax, ecx, edx 被调用者保存
ebx, esi, edi 被被调用者保存
esp, ebp 无所谓保存不保存, 因为是用于过程调用本身的, 调用者与被调用者都遵守正确的规则即可, 但在任务切换时, esp, ebp也会被替换, 因此也需要保存, 包括eip也要保存
那么在 switch_to 时呢, 自然这个是宏; 但期间发生了任务切换, 如果任务A在切换前 EAX 保存了一个值, 然后切换到任务B, 被B改了, 又切换回来, 任务A是不知道EAX被修改的, 那么任务A的代码就面临着危险。
从宏中看,
1. EAX, EDX 和 prev, next 结合, 那么编译器会产生代码, 将其原来结合的变量压栈, 用完后弹出;
2。ebp, esi, edi 被保存到了栈上, 切换回后弹出, ebx switch_to 宏明确表明其值会发生变化, 因此也会被压栈, 而后被恢复, 因此没有问题
3。 esp, eip 保存到 task_struct 中, 也没有问题。
但 ecx 呢? 这个在切换出去的过程中被其他任务修改了该怎么办???
进一步更隐晦的: eax, edx, 如果 witch_to 之前结合的就是 prev, next, 那么还会被编译器压栈么??? 那么, 也存在被修改了的问题;
比如 schedule 代码:
switch_to(prev, next, prev);
__schedule_tail(prev);
如果在 switch_to 之前, eax 就和 prev 结合了, 那么编译器会不会优化而省略 push eax, mov eax, eax,这样的步骤???
如果真的发生了, 那么, 任务再次切换回来时, eax 结合的可是被切换走的哪个任务, __schedule_tail 可就完全错了。 |
|