在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
to next->eip
,它更干净,更易于阅读。