Linux 系统从开机到用户程序 main 执行的全过程-理论分析
开机 BIOS/UEFI]↓[Bootloader] → 加载内核↓[内核初始化 start_kernel()]↓[创建用户空间进程 init(PID=1)]↓[init → 启动脚本/服务]↓[需要内核功能 → init_module() 加载模块]↓[execve() 执行用户程序]↓[程序 ELF _start → crt0 初始化]↓。
Linux 系统启动到用户程序执行详细总结
1. 开机(Boot)
Linux 系统的启动从硬件上电开始,包括以下关键步骤:
-
BIOS/UEFI 阶段
-
BIOS(旧式)或 UEFI(新式)进行硬件初始化(CPU、内存、I/O 等)。
-
加载 Bootloader(如 GRUB)到内存并跳转执行。
-
-
Bootloader 阶段
-
Bootloader 的主要任务是加载内核映像(
vmlinuz
)到内存。 -
如果内核压缩过(
bzImage
),Bootloader 负责解压。 -
设置启动参数(kernel command line)。
-
将控制权交给内核入口点(
start_kernel()
)。
-
2. 内核初始化(init)
内核接管后,开始进行 内核初始化:
-
内核解压和早期初始化
-
初始化内存管理、CPU、设备树(Device Tree)。
-
建立中断向量表和页表。
-
初始化内核模块子系统。
-
-
start_kernel()
-
内核的 C 入口点。
-
调用一系列初始化函数:
-
setup_arch()
:架构相关初始化。 -
trap_init()
:异常和中断初始化。 -
sched_init()
:调度器初始化。 -
init_mm()
:内存管理初始化。 -
rest_init()
:创建第一个用户进程init
。
-
-
-
第一个用户进程
init
-
内核使用
kernel_init
启动第一个用户空间进程(PID=1)。 -
默认路径为
/sbin/init
或/init
。 -
init
是用户空间的父进程,负责进一步启动用户空间环境。
-
3. init → 启动脚本
init
的主要任务是根据系统配置启动各种服务和守护进程。
-
传统 SysVinit
-
/etc/inittab
定义启动级别和执行脚本。 -
根据运行级别执行
/etc/rc.d/rc*.d/
下的启动脚本。 -
脚本通过
start
、stop
命令启动各类服务。
-
-
Systemd(现代 Linux)
-
/sbin/init
是 systemd。 -
解析 unit 文件(
.service
、.target
等)。 -
按依赖关系启动各类服务。
-
-
核心机制
-
脚本或 systemd unit 的执行最终通过 用户空间 fork/exec 系统调用 启动对应程序。
-
4. init_module(内核模块初始化)
在启动脚本中,某些功能可能依赖 内核模块(Kernel Module),这时会涉及:
-
模块加载
-
insmod / modprobe
命令会调用内核的init_module()
系统调用。 -
内核检查模块合法性(版本、符号依赖)。
-
将模块映射到内核地址空间。
-
-
模块初始化函数
-
模块必须定义
module_init(my_init)
。 -
内核调用
my_init()
完成模块功能初始化。 -
init_module()
完成后模块可被系统使用。
-
5. execve(程序执行)
启动脚本和服务会通过 execve()
系统调用加载实际的用户程序:
-
execve(path, argv, envp)
-
path
:程序路径。 -
argv
:参数数组。 -
envp
:环境变量。
-
-
内核执行过程
-
检查文件权限和可执行性。
-
解析 ELF 文件头(或其他可执行格式)。
-
分配进程虚拟内存空间。
-
加载
.text
、.data
等段到内存。 -
设置栈,复制
argv
、envp
。 -
设置指令指针到程序入口(ELF 的
_start
)。
-
-
进程切换
-
新程序替换旧程序的地址空间。
-
内核调度器切换 CPU 执行新进程。
-
6. 用户程序入口 → main
在用户程序空间:
-
ELF
_start
-
汇编入口点
_start
(由编译器/链接器生成)。 -
做了基本的栈初始化。
-
调用 C 运行时初始化
crt0
:-
设置
argc
、argv
、envp
。 -
初始化全局变量、
stdin/stdout/stderr
。
-
-
-
调用
main()
-
_start
最终调用main(argc, argv)
。 -
用户程序开始真正执行。
-
-
程序退出
-
main
返回值传给_exit()
系统调用。 -
内核回收资源,父进程可通过
wait()
获取退出状态。
-
总结流程图
[开机 BIOS/UEFI]
↓
[Bootloader] → 加载内核
↓
[内核初始化 start_kernel()]
↓
[创建用户空间进程 init(PID=1)]
↓
[init → 启动脚本/服务]
↓
[需要内核功能 → init_module() 加载模块]
↓
[execve() 执行用户程序]
↓
[程序 ELF _start → crt0 初始化]
↓
[main(argc, argv)]
🔑 重点
-
开机阶段:硬件 → Bootloader → 内核
-
内核阶段:内核初始化 → 第一个用户进程
init
-
用户空间启动:init → 启动脚本 → 系统服务 → 模块加载
-
用户程序执行:
execve()
→_start
→main()
-
模块机制:
init_module
只在内核模块加载时用到,属于内核空间初始化,用户空间通过insmod
调用。
更多推荐
所有评论(0)