第一个系统调用:exec 的执行流程
概要:介绍 initcode.S 如何通过汇编压栈参数、设置系统调用号并触发中断来发起 exec 系统调用,以及 exec 成功/失败两个分支和 /init 接管后初始化用户环境的流程。
1. 触发机制与核心功能
initcode.S 的核心任务是触发 exec 系统调用。
- 功能:
exec用新程序的代码和数据替换当前进程的内存与寄存器。 - 状态保留: 替换过程中,进程的 文件描述符 (FD)、进程 ID (PID) 以及 父进程 保持不变。
2. 汇编层面的调用准备 (initcode.S)
在指令级别,initcode.S 通过以下步骤手动构建系统调用环境:
- 压栈参数: 将
$argv(参数指针),$init(字符串 “/init”), 以及$0(用于对齐/结束) 依次推入栈中。 - 设置寄存器: 将系统调用号
SYS_exec存入%eax寄存器。 - 触发中断: 执行
int T_SYSCALL指令,陷入内核,告知内核运行exec。
参数说明: 系统调用最终指向名为
$init的程序(即以空字符结尾的字符串/init)。
3. 执行路径:成功与失败
exec 调用后会产生两个分支:
- 成功路径:
exec不会返回。它直接跳转并运行/init程序的二进制代码,替换掉原有的initcode。 - 失败路径: 如果
exec因某种原因失败并返回,initcode将进入一个无限循环,不断调用exit系统调用。
4. /init 进程接管与系统建立
一旦 /init 成功运行,它将负责初始化用户环境:
- 创建设备文件: 在需要时创建控制台设备文件(console node)。
- 设置标准流: 依次打开该设备,占据文件描述符 0 (stdin)、1 (stdout) 和 2 (stderr)。
- 主循环逻辑:
- 开启一个控制台 Shell。
- 持续回收(wait)没有父进程的僵尸进程。
- 若 Shell 退出,则重新开启。
留下评论