对x86上下文切换的一点理解
阿里云国内75折 回扣 微信号:monov8 |
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6 |
本文代码基于linux内核4.19.195。
我们都知道上下文切换在函数context_switch中完成x86架构代码最终会调用函数 __switch_to_asm((prev), (next)));完成寄存器及内核栈的切换。
/*
* %rdi: prev task
* %rsi: next task
*/
ENTRY(__switch_to_asm)
UNWIND_HINT_FUNC
/*
* Save callee-saved registers
* This must match the order in inactive_task_frame
*/
pushq %rbp
pushq %rbx
pushq %r12
pushq %r13
pushq %r14
pushq %r15
pushfq //标志寄存器压栈指令
/* switch stack */ //栈切换
movq %rsp, TASK_threadsp(%rdi)
movq TASK_threadsp(%rsi), %rsp
#ifdef CONFIG_STACKPROTECTOR
movq TASK_stack_canary(%rsi), %rbx
movq %rbx, PER_CPU_VAR(irq_stack_union)+stack_canary_offset
#endif
#ifdef CONFIG_RETPOLINE
/*
* When switching from a shallower to a deeper call stack
* the RSB may either underflow or use entries populated
* with userspace addresses. On CPUs where those concerns
* exist, overwrite the RSB with entries which capture
* speculative execution to prevent attack.
*/
FILL_RETURN_BUFFER %r12, RSB_CLEAR_LOOPS, X86_FEATURE_RSB_CTXSW
#endif
/* restore callee-saved registers */
popfq
popq %r15
popq %r14
popq %r13
popq %r12
popq %rbx
popq %rbp
jmp __switch_to
END(__switch_to_asm)
第一次看这个函数感觉就是标准的上下文切换写法最开始把prev进程的rbp、rbx、r12、r13、r14、r15寄存器完成保存最后面再恢复next进程的这些寄存器。
诶等等那rax、rbx这些寄存器去哪了呢不用恢复吗
继续深入了看了几遍以及看了__switch_to函数都没看到有保存和切换rax的代码那么为啥内核不保存呢
回到__switch_to_asm函数猛然发现有一行注释写道
save callee-saved registers
根本原因就在这里因为__switch_to_asm是一个被C语言调用的函数作为调用者有义务保存相关寄存器至于保存哪些寄存器是由x86的函数调用约定规定的因而作为被调用方只需要保存相关的没有被调用方保存的寄存器即可剩下的寄存器在函数结束后由调用方自行恢复这里如果还做保存就是浪费力气了。