在Linux系统中,当用户在Shell界面输入一个可执行文件名并按下回车键时,一系列复杂步骤随即展开,旨在将可执行文件加载到内存中,并创建新的进程来执行,这一过程不仅涉及底层操作系统的资源管理,还体现了现代操作系统的多任务处理和内存管理机制。
1、启动新进程
用户通过shell输入./可执行文件名命令。
Shell识别这不是内建命令,调用fork()系统调用来创建一个新进程,作为shell的子进程。
fork()通过sys_fork()函数实现,为新进程分配一个唯一的进程号(PID),并初始化其进程控制块(task_struct)。
2、初始化task_struct
内核为新进程分配一块内存,用于存储task_struct和内核栈。
复制父进程(shell)的task_struct到新进程,并进行必要的个性化设置,如PID、父进程ID、时间片、TSS段等。
3、内存映射与分页
为新进程创建或复制页表,并设置相应的页面目录。
确定新进程的代码段、数据段、BSS段的基地址和限长,这些信息来源于可执行文件的头部信息。
4、全局描述符表(GDT)关联
将新进程的TSS(任务状态段)和LDT(局部描述符表)挂接到GDT的相应位置,确保进程切换时能够正确恢复和保存上下文。
5、设置进程状态
将新进程的状态设置为就绪,等待CPU调度执行。
6、加载可执行文件
调用execve()系统调用(通过do_execve()函数实现),解析可执行文件的头部信息。
根据可执行文件的格式(如ELF),将必要的段(代码、数据、BSS等)加载到内存中。
初始化新进程的栈,包括环境变量、命令行参数等。
更新task_struct中的相关内存映射信息,确保新进程能够正确访问其内存空间。
本文凡亿教育原创文章,转载请注明来源!