免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1893 | 回复: 1
打印 上一主题 下一主题

switch_to 疑问 [复制链接]

论坛徽章:
11
未羊
日期:2013-12-16 12:45:4615-16赛季CBA联赛之青岛
日期:2016-04-11 19:17:4715-16赛季CBA联赛之广夏
日期:2016-04-06 16:34:012015亚冠之卡尔希纳萨夫
日期:2015-11-10 10:04:522015亚冠之大阪钢巴
日期:2015-07-30 18:29:402015亚冠之城南
日期:2015-06-15 17:56:392015亚冠之卡尔希纳萨夫
日期:2015-05-15 15:19:272015亚冠之山东鲁能
日期:2015-05-14 12:38:13金牛座
日期:2014-12-04 15:34:06子鼠
日期:2014-10-16 13:40:4715-16赛季CBA联赛之八一
日期:2016-07-22 09:41:40
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2011-11-28 19:24 |只看该作者 |倒序浏览
本帖最后由 zylthinking 于 2011-11-28 19:27 编辑
  1.   15#define switch_to(prev,next,last) do {                                  \
  2.   16        asm volatile("pushl %%esi\n\t"                                  \
  3.   17                     "pushl %%edi\n\t"                                  \
  4.   18                     "pushl %%ebp\n\t"                                  \
  5.   19                     "movl %%esp,%0\n\t"        /* save ESP */          \
  6.   20                     "movl %3,%%esp\n\t"        /* restore ESP */       \
  7.   21                     "movl $1f,%1\n\t"          /* save EIP */          \
  8.   22                     "pushl %4\n\t"             /* restore EIP */       \
  9.   23                     "jmp __switch_to\n"                                \
  10.   24                     "1:\t"                                             \
  11.   25                     "popl %%ebp\n\t"                                   \
  12.   26                     "popl %%edi\n\t"                                   \
  13.   27                     "popl %%esi\n\t"                                   \
  14.   28                     :"=m" (prev->thread.esp),"=m" (prev->thread.eip),  \
  15.   29                      "=b" (last)                                       \
  16.   30                     :"m" (next->thread.esp),"m" (next->thread.eip),    \
  17.   31                      "a" (prev), "d" (next),                           \
  18.   32                      "b" (prev));                                      \
  19.   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 可就完全错了。

论坛徽章:
0
2 [报告]
发表于 2011-11-28 19:54 |只看该作者
不知道你是哪个版本的code,我在2.6.33中看到的确实是全部显式的保存了。

/*
* Saving eflags is important. It switches not only IOPL between tasks,
* it also protects other tasks from NT leaking through sysenter etc.
*/
#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   */        \
                     __switch_canary                                        \
                     "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),                \
                       [prev_ip] "=m" (prev->thread.ip),                \
                       "=a" (last),                                        \
                                                                        \
                       /* clobbered output registers: */                \
                       "=b" (ebx), "=c" (ecx), "=d" (edx),                \
                       "=S" (esi), "=D" (edi)       
                        \
                                                                               \
                       __switch_canary_oparam                                \
                                                                        \
                       /* input parameters: */                                \
                     : [next_sp]  "m" (next->thread.sp),                \
                       [next_ip]  "m" (next->thread.ip),                \
                                                                               \
                       /* regparm parameters for __switch_to(): */        \
                       [prev]     "a" (prev),                                \
                       [next]     "d" (next)                                \
                                                                        \
                       __switch_canary_iparam                                \
                                                                        \
                     : /* reloaded segment registers */                        \
                        "memory");                                        \
} while (0)
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP