对x86上下文切换的一点理解

本文代码基于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的函数调用约定规定的,因而,作为被调用方,只需要保存相关的没有被调用方保存的寄存器即可,剩下的寄存器在函数结束后由调用方自行恢复,这里如果还做保存就是浪费力气了。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值