LinuxLab3---结合中断上下文切换和进程上下文切换分析Linux内核的一般执行过程

一、实验要求

结合中断上下文切换和进程上下文切换分析Linux内核一般执行过程

  • 以fork和execve系统调用为例分析中断上下文的切换
  • 分析execve系统调用中断上下文的特殊之处
  • 分析fork子进程启动执行时进程上下文的特殊之处
  • 以系统调用作为特殊的中断,结合中断上下文切换和进程上下文切换分析Linux系统的一般执行过程

完成一篇博客总结分析Linux系统的一般执行过程,以期对Linux系统的整体运作形成一套逻辑自洽的模型,并能将所学的各种OS和Linux内核知识/原理融通进模型中。

 

二、fork函数

 1.fork函数功能

fork函数系统调用创建一个子进程,子进程复制了父 进程中所有的进程信息,包括内核堆栈、进程描述符等,子进程作为一个独立的进程也会被调度,当子进程获得CPU开始运行时,从用户态空间来看,就是fork系统调用的下一条指令。但fork系统调用在子进程当中也是返回的,也就是说fork系统调用在内核里面变成了父子两个进程,父进程正常fork系统调用返回到用户态,fork出来的子进程也要从内核里返回到用户态。

2.fork函数过程

主要调用过程

  • _do_fork
    • copy_process 复制进程描述符和执⾏时所需的其他数据结构
      • dup_task_struct 复制进程描述符task_struct、创建内核堆栈等
      • copy_thread_tls 初始化⼦进程内核栈和thread
    • wake_up_new_task 将⼦进程添加到就绪队列
  • 系统调用返回

系统调用号57

 

 

 

 调用_do_fork函数

 

 _do_fork函数主要调用copy_process和wake_up_new_task函数

 

 copy_process函数

复制进程描述符

  复制所有进程信息,初始化子进程内核栈

 

子进程从ret_from_fork开始执行

 

 总体过程

 

 

 

 fork调用会有两次返回。第⼀次返回到原来的⽗进程的位置继续向下执⾏,这和其他的系统调⽤是⼀样的。

在⼦进程中fork也返回了⼀次,会返回到⼀个特定的点ret_from_fork,通过内核构造的堆栈环境,它可以正常系统调⽤返回到⽤户态。

三、execve函数

Linux系统⼀般会提供了execl、 execlp、 execle、 execv、 execvpexecve6个⽤以加载执⾏⼀个可执⾏⽂件的库函数,这些库函数统称为exec函数,差异在于对命令⾏参数和环境变量参数的传递⽅式不同。 exec函数都是通过execve系统调⽤进⼊内核,对应的系统调⽤内核处理函数为__x64_sys_execve,它们都是通过调⽤do_execve来具体执⾏加载可执⾏⽂件的⼯作。

 整体的调用关系为如下

  • __x64_sys_execve
  • do_execve() 
  • do_execveat_common() 
  • __do_execve_file
  • exec_binprm()
  • search_binary_handler() 
  • load_elf_binary() 
  • start_thread() 

代码分析

调用do_execve

 对参数进行了类型转换,调用do_execveat_common

 

 

 调用__do_execve_file

打开要加载的可执行文件

 

 

 交给真正的可执行文件加载器

 

 

 查找可执行文件处理函数

 

 

 寻找能够解析当前可执行文件的代码并加载

 

 

 

load_binary实际调用load_elf_binary

load_elf_binary中进行了一系列操作,按照ELF文件格式加载,然后启动新的进程

 

 

将之前pt_regs保存的堆栈和返回地址设置为新的ip,返回用户态时转而执行elf_entry指向的代码 

 

 

 四、Linux系统的一般执行过程

Linux中最基本和一般的场景,正在运行的的用户进程X切换到用户进程Y的过程。

(1)正在运⾏的⽤户态进程X。

(2)发⽣中断(包括异常、系统调⽤等),硬件完成
  当前CPU上下文压入用户态进程X的内核堆栈。
  加载当前进程内核堆栈相关信息,跳转到中断处理程序,即中断执行路径的起点。

(3)保存现场,完成中断上下文切换,从进程X的用户态到进程X的内核态

(4)中断处理过程中或中断返回前调⽤了schedule函数,其中完成了进程调度算法选择next进程、进程地址空间切换、关键的进程上下⽂切换等。

(5)switch_to调⽤了__switch_to_asm汇编代码做了关键的进程上下⽂切换。将当前进程X的内核堆栈切换到进程调度算法选出来的next进程(本例假定为进程Y)的内核堆栈,并完成了进程上下⽂所需的指令指针寄存器状态切换。之后开始运⾏进程Y。

(6)中断上下⽂恢复,与(3)中断上下⽂切换相对应。注意这⾥是进程Y的中断处理过程中,⽽(3)中断上下⽂切换是在进程X的中断处理过程中,因为内核堆栈从进程X切换到进程Y了。

(7)iret pop cs:rip/ss:rsp/rflags,从Y进程的内核堆栈中弹出(3)中对应的压栈内容。此时完成了中断上下⽂的切换,即从进程Y的内核态返回到进程Y的⽤户态。

(8)继续运⾏⽤户态进程Y。

 

posted @ 2020-06-15 13:43  USTC老虞  阅读(215)  评论(0)    收藏  举报