【发布时间】:2013-02-22 08:41:21
【问题描述】:
在linux/arch/x86/include/asm/switch_to.h,有宏switch_to的定义,真正线程切换奇迹的关键行是这样写的(直到Linux 4.7改变时):
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 */ \
命名操作数具有内存限制,例如[prev_sp] "=m" (prev->thread.sp)。 __switch_canary 被定义为空,除非 CONFIG_CC_STACKPROTECTOR 被定义(然后它是使用 %ebx 的加载和存储)。
我了解它是如何工作的,例如内核堆栈指针备份/恢复,以及 push next->eip 和 jmp __switch_to 如何在函数末尾加上 ret 指令,这实际上是一个“假”调用指令匹配真正的ret指令,有效地使next->eip成为下一个线程的返回点。
我不明白的是,为什么要破解?为什么不只是call __switch_to,然后是ret、jmp 到next->eip,这样更干净、更易于阅读。
【问题讨论】:
标签: assembly linux-kernel x86