Linux 系统启动到用户程序执行详细总结

1. 开机(Boot)

Linux 系统的启动从硬件上电开始,包括以下关键步骤:

  1. BIOS/UEFI 阶段

    • BIOS(旧式)或 UEFI(新式)进行硬件初始化(CPU、内存、I/O 等)。

    • 加载 Bootloader(如 GRUB)到内存并跳转执行。

  2. Bootloader 阶段

    • Bootloader 的主要任务是加载内核映像(vmlinuz)到内存。

    • 如果内核压缩过(bzImage),Bootloader 负责解压。

    • 设置启动参数(kernel command line)。

    • 将控制权交给内核入口点(start_kernel())。


2. 内核初始化(init)

内核接管后,开始进行 内核初始化

  1. 内核解压和早期初始化

    • 初始化内存管理、CPU、设备树(Device Tree)。

    • 建立中断向量表和页表。

    • 初始化内核模块子系统。

  2. start_kernel()

    • 内核的 C 入口点。

    • 调用一系列初始化函数:

      • setup_arch():架构相关初始化。

      • trap_init():异常和中断初始化。

      • sched_init():调度器初始化。

      • init_mm():内存管理初始化。

      • rest_init():创建第一个用户进程 init

  3. 第一个用户进程 init

    • 内核使用 kernel_init 启动第一个用户空间进程(PID=1)。

    • 默认路径为 /sbin/init/init

    • init 是用户空间的父进程,负责进一步启动用户空间环境。


3. init → 启动脚本

init 的主要任务是根据系统配置启动各种服务和守护进程。

  1. 传统 SysVinit

    • /etc/inittab 定义启动级别和执行脚本。

    • 根据运行级别执行 /etc/rc.d/rc*.d/ 下的启动脚本。

    • 脚本通过 startstop 命令启动各类服务。

  2. Systemd(现代 Linux)

    • /sbin/init 是 systemd。

    • 解析 unit 文件(.service.target 等)。

    • 按依赖关系启动各类服务。

  3. 核心机制

    • 脚本或 systemd unit 的执行最终通过 用户空间 fork/exec 系统调用 启动对应程序。


4. init_module(内核模块初始化)

在启动脚本中,某些功能可能依赖 内核模块(Kernel Module),这时会涉及:

  1. 模块加载

    • insmod / modprobe 命令会调用内核的 init_module() 系统调用。

    • 内核检查模块合法性(版本、符号依赖)。

    • 将模块映射到内核地址空间。

  2. 模块初始化函数

    • 模块必须定义 module_init(my_init)

    • 内核调用 my_init() 完成模块功能初始化。

    • init_module() 完成后模块可被系统使用。


5. execve(程序执行)

启动脚本和服务会通过 execve() 系统调用加载实际的用户程序:

  1. execve(path, argv, envp)

    • path:程序路径。

    • argv:参数数组。

    • envp:环境变量。

  2. 内核执行过程

    • 检查文件权限和可执行性。

    • 解析 ELF 文件头(或其他可执行格式)。

    • 分配进程虚拟内存空间。

    • 加载 .text.data 等段到内存。

    • 设置栈,复制 argvenvp

    • 设置指令指针到程序入口(ELF 的 _start)。

  3. 进程切换

    • 新程序替换旧程序的地址空间。

    • 内核调度器切换 CPU 执行新进程。


6. 用户程序入口 → main

在用户程序空间:

  1. ELF _start

    • 汇编入口点 _start(由编译器/链接器生成)。

    • 做了基本的栈初始化。

    • 调用 C 运行时初始化 crt0

      • 设置 argcargvenvp

      • 初始化全局变量、stdin/stdout/stderr

  2. 调用 main()

    • _start 最终调用 main(argc, argv)

    • 用户程序开始真正执行。

  3. 程序退出

    • main 返回值传给 _exit() 系统调用。

    • 内核回收资源,父进程可通过 wait() 获取退出状态。


总结流程图

[开机 BIOS/UEFI] 
      ↓
[Bootloader] → 加载内核
      ↓
[内核初始化 start_kernel()]
      ↓
[创建用户空间进程 init(PID=1)]
      ↓
[init → 启动脚本/服务]
      ↓
[需要内核功能 → init_module() 加载模块]
      ↓
[execve() 执行用户程序]
      ↓
[程序 ELF _start → crt0 初始化]
      ↓
[main(argc, argv)]


🔑 重点

  1. 开机阶段:硬件 → Bootloader → 内核

  2. 内核阶段:内核初始化 → 第一个用户进程 init

  3. 用户空间启动:init → 启动脚本 → 系统服务 → 模块加载

  4. 用户程序执行execve()_startmain()

  5. 模块机制init_module 只在内核模块加载时用到,属于内核空间初始化,用户空间通过 insmod 调用。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐