Content #
//include/linux/sched.h
#define switch_to(n) {\
struct {long a,b;} __tmp; \
__asm__("cmpl %%ecx,_current\n\t" \
"je 1f\n\t" \
"movw %%dx,%1\n\t" \
"xchgl %%ecx,_current\n\t" \
"ljmp %0\n\t" \
"cmpl %%ecx,_last_task_used_math\n\t" \
"jne 1f\n\t" \
"clts\n" \
"1:" \
::"m" (*&__tmp.a),"m" (*&__tmp.b), \
"d" (_TSS(n)),"c" ((long) task[n])); \
}
“m” (*&__tmp.a) #
表示将__tmp.a的内存地址作为输入操作数(%0),但并未显式赋值。实际使用时,__tmp.a的值是未初始化的随机值(取决于栈状态),但代码中仅利用了它的内存地址,而非其内容。
movw %%dx, %1 #
这条指令将%%dx(TSS选择子)写入__tmp.b的低16位(%1对应__tmp.b)。注意:__tmp.a和__tmp.b是连续内存(结构体成员),movw %%dx, %1可能覆盖__tmp.a的部分内容(取决于对齐),但代码逻辑并不依赖__tmp.a的具体值。
为什么不需要显式设置 __tmp.a? #
硬件任务切换的特性: ljmp到TSS选择子时,CPU会直接加载TSS中的状态(包括EIP),完全忽略远跳转指令中的偏移量。因此__tmp.a的值(偏移部分)不会被使用。代码优化:显式初始化__tmp.a是多余的(如movl $0, %0),故省略以提升性能。