嵌入式实战场景题第三弹(详解版)
满满干货,每一道题都是经典!!!
此部分不只包含面经内容,均是实战类型不必全文背诵,有思路即可
后续收录于专栏:https://www.nowcoder.com/creation/manager/columnDetail/MJNwoM
1.基于内核栈的进程切换要做那些事情
考察点:进程和进程切换的理解,对内核各部分的理解
1. PCB 切换
进程切换的第一步是进程控制块(PCB)的切换。PCB 中保存着进程的各种状态信息,包括该进程上一次停止时内核栈栈顶的指针(esp)。:
- 保存当前进程 PCB:首先,系统会保存当前进程 PCB 中的内核栈栈顶指针以及其他重要状态信息。
- 切换到目标进程 PCB:然后,系统会切换到目标进程的 PCB,即将要运行的进程的 PCB。
- 准备内核栈切换:此时,系统已经拥有了目标进程 PCB 中的所有必要信息,包括内核栈栈顶指针,为后续的内核栈切换做准备。
2. 内核栈切换
内核栈切换是基于 PCB 切换之后进行的。由于 PCB 中已经包含了指向目标进程内核栈栈顶的指针,因此可以很方便地进行内核栈的切换。
- 切换内核栈指针:系统会根据目标进程 PCB 中的内核栈栈顶指针,将当前的内核栈指针切换到目标进程的内核栈。
- 更新上下文信息:在切换内核栈的同时,系统会更新相关的上下文信息,如寄存器状态等,以确保目标进程在恢复执行时能够正确地从其上次停止的位置继续执行。
3. LDT 切换
进程切换还包含局部描述符表(LDT)的切换。LDT 是用于内存映射的表,它定义了进程可以访问的内存段。
- 加载目标进程的 LDT:在进程切换时,系统会加载目标进程的 LDT,以确保目标进程能够访问其自己的内存段。
- 更新段寄存器:同时,系统会更新相关的段寄存器(如 CS、DS、ES 等),以反映新的 LDT 设置。
4. 用户栈切换
用户栈切换是在内核中运行一段代码后,通过中断返回指令(iret)退出内核时实现的。
- 准备用户栈切换:在内核中执行完必要的操作后,系统会准备用户栈切换。这包括将内核栈中的 SS(栈段寄存器)和 SP(栈指针寄存器)的值更新为目标进程用户栈的相应值。
- 执行 iret 指令:最后,系统会执行 iret 指令,该指令会根据 SS 和 SP 的值切换到目标进程的用户栈,并恢复用户态的执行环境。
2.PCB切换时的汇编,切栈之前需要做哪些动作?
1.压栈寄存器
在切换内核栈前,需将当前进程的通用寄存器(如 ebp
、eax
、ebx
等)压入旧进程的内核栈,确保上下文完整保存
举个汇编例子:
switch_to: pushl %ebp ; 保存基址寄存器 movl %esp, %ebp ; 保存当前栈指针到ebp pushl %ecx ; 保存其他寄存器 pushl %ebx pushl %eax
2.保存旧进程栈指针
将当前栈指针(esp
)的值存入旧进程的 PCB 中,具体汇编如下
movl %esp, [current->kernel_esp] ; 保存旧进程的栈指针
3.关闭中断确保原子性
在切换过程中需关闭中断(通过 cli
指令),防止上下文切换被中断打断,导致状态不一致
4.更新全局当前进程指针
将全局变量 current
(指向当前进程 PCB 的指针)更新为目标进程的 PCB 地址。
5.加载目标进程的 LDT
在切换内核栈前,需加载目标进程的 LDT 选择子(通过 lldt
指令),确保内存分段映射正确:
6.预加载目标进程内核栈指针
将目标进程 PCB 中的内核栈指针加载到临时寄存器,为后续切换做准备:
具体举个例子:
switch_to: pushl %ebp ; 保存寄存器 pushl %ecx pushl %ebx pushl %eax movl %esp, [current->kernel_esp] ; 保存旧栈指针 cli ; 关闭中断 movl next_pcb, %eax
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
BG双9,目前在某外企。打算把之前校招时做的笔记通过专栏发出来,本专栏适合于C/C++、嵌入式方向就业的同学,本篇面经总结数千篇面经的知识集合,实时更新全网最新的嵌入式/C++最新内容,囊括了C语言、C++、操作系统、计算机网络、嵌入式、算法与数据结构、数据库等一系列知识点,在我看来这些是求职者在面试中必须掌握的知识点。最后呢祝各位能找到自己合适的工作。