实现的最终效果:改变进程执行的上下文。
1.使用execve就是一次系统调用,首先要做的将新的可执行文件的绝对路径从调用者(用户空间)拷贝到系统空间中。
2.在得到可执行文件路径后,就找到可执行文件打开,由于操作系统已经为可执行文件设置了一个数据结构,就初始化这个数据结构,保存一个可执行文件必要的信息。
3.可执行文件不是真正上能够自己运行的,需要有代理人来代理。在系统内核中有一个formats队列,循环遍历这个队列,看看现在被初始化的这个数据结构是哪个代理人可以代理的。如果没有就继续查看数据结构中的信息。按照系统配置了是否可以动态加载模块,加载一次模块,再循环遍历看是否有代理人前来认领。
4.找到正确的代理人后,代理人首先要做的就是放弃以前从父进程继承来的资源(虽然代理程序各不相同,但这是一个共性的操作)。主要是对信号处理表,用户空间和文件3大资源的处理。
a.信号处理表:将父进程的信号处理表复制过来(可能已经复制了,也可能没有复制,通过检查信号处理表的共享参数就可以知道)。信号处理分3种情况:一对该信号不理睬,二对信号采取默认动作,三对信号采取指定动作。前面2种可以直接复制,最后一种,所谓的默认动作就是用户指定了程序处理,这段程序的代码必然是父进程自己拥有的,他的位置就存在用户空间中,下面我们会放弃继承到的父进程用户空间,对第3种情况的处理就是将其改成默认处理。所以,在新建的子进程中,对信号如果子进程没有采取指定处理,那么一律都会是默认处理,当然如果父进程对某个信号采取了不理睬,子进程也会不理睬,除非子进程后来又做了修改。
b.用户空间,放弃原来的用户空间(子进程可能有自己的页面,或者就是通过指针共享了父进程的页面)这些一律放弃,将进程控制块task_struct中对用户空间的描述的数据结构mm_struct的下属结构vma全部置0.简而言之就是现在子进程的用户空间是个空架子,一个页面也没有,父进程空间被放弃。
c.进程控制块task_struct中有file的指针记录了进程打开的文件信息,子进程对继承到的文件采取关闭应当关闭的信息。file的数据结构中有位图记录了应当关闭的文件,子进程放弃这些文件。一般来说,执行的效果是除了标准输入文件,标准输出文件,标准错误输出文件。其它的文件都不会被子进程继承。(标准输入一般就是键盘,标准输出就是显示器。因此如果子进程有打印语句的话,那么他的打印出来的字符会打印到父进程打印的地方,前面写文章有点错误,我已经改掉了)。
5.至此我们已经做了的实际动作就是信号处理表,用户空间和文件。但用户空间是个空架子,真正的程序代码没载入,数据段也没载入,堆栈没有开辟,执行参数和环境变量也没有被印射。但可以知道,每个可执行文件的载入是不同的,比如linux下shell文件和a.out文件2个有很明显的不同,你可以对他们采用同样的载入办法吗。下面就是各个代理人自己开始为自己的代理方申请空间,准备用户内存。最后调用 start_thread 开始启动进程。
这里是大致的流程,很多细节没有提到,比如在用户空间释放过程中,我们可以看到很多问题。例如原来的是vfork创建的是线程,你放了空间,为新进程申请了空间,虽然是个空架子,但他已经不是线程了,你要从父进程的线程组中拿掉他。如果是内核线程启动了新的进程,内核线程是没有自己的用户空间的。这是原来用户空间的共享计数会为0,该如何处理,这些问题在这里都没提到。如果有兴趣,大家可以自己看linux源代码。
分享到:
相关推荐
通过理解`sys_execve`的工作原理,我们可以更好地了解进程的生命周期以及如何在Linux环境下启动和控制程序。 `sys_execve`系统调用有三个参数:`filename`、`argv`和`envp`。这里分别解释它们的作用: 1. `...
在Linux环境下模拟实现命令解释器是一项挑战性的操作系统大作业,旨在深入理解操作系统的运作机制以及命令行接口(CLI)的工作原理。在这个项目中,学生需要编写一个程序,该程序能够接收用户输入的命令,解析这些...
这篇描述提到的"Linux下的例子C实现"很可能是一个包含了一系列C语言编程示例的资源包,旨在帮助开发者理解和学习如何在Linux环境下编写C程序。下面将详细讲解与Linux下C编程相关的知识点。 1. **Linux环境**:Linux...
本实例将重点讲解如何在Linux环境下,特别是Ubuntu 9.10版本中,实现对`sys_execve`系统调用的hook。 `sys_execve`是Linux内核中的一个关键系统调用,它负责执行新的程序。当用户尝试运行一个程序时,最终都会通过`...
《Linux内核设计与实现》第三版是陈莉君翻译的经典之作,这本书深入浅出地讲解了Linux操作系统内核的工作原理和实现细节。对于想要深入理解操作系统,特别是Linux内核的人来说,这是一本不可多得的参考书。本书涵盖...
本文对Linux系统下端口复用技术的基础知识进行了介绍,包括内存管理、系统调用、进程调度、文件系统、socket内核结构、协议栈的内核实现、ELF文件结构、ELF文件装载过程等知识点。 对Linux系统下端口复用技术的理解...
在Linux环境下,使用C++编写一个简单的命令解释器是一个典型的系统编程任务,它涉及到对操作系统接口的直接...在实现过程中,会遇到诸如命令行解析、进程间通信、权限管理等复杂问题,这些都是对开发者技能的全面考验。
具体实现过程中,首先需要分析`execve()`的系统调用接口,了解其参数含义,然后在模块中设置适当的钩子以拦截调用。在模块加载到内核后,可以动态修改内核的行为,比如在执行`execve()`前检查程序路径。为了实现这一...
### Linux下ELF可执行文件载入过程源码分析 #### 引子 在Linux操作系统中,每一个可执行文件在被执行之前都需要经过一系列复杂的加载过程。这个过程涉及到多个内核函数以及用户空间与内核空间的数据交换。本文将对...
通过上述步骤,我们清楚地了解了在Linux环境下执行应用程序的基本过程。这个过程不仅涉及shell作为父进程的初始化行为,还包括了子进程利用`execve()`系统调用加载和执行目标程序的细节。此外,内核层面的处理流程也...
C语言中的指针是其强大之处,Linux环境下,指针可以用来访问内存,实现高级数据结构,如链表、树等,还能用于系统调用,如通过指针传递参数给内核。理解指针的概念,掌握指针运算和指针类型的声明至关重要。 在...
此外,Linux还提供了丰富的系统调用,如`open`用于打开文件,`write`用于写入文件,`fork`用于创建子进程,`execve`用于执行新程序等。这些系统调用使得C程序可以直接与操作系统交互,实现更底层的操作。 在Linux...
理解和分析进程创建、调度、通信、同步以及终止的过程对于深入理解Linux至关重要。 2. **内存管理**:Linux内核采用分页内存管理机制,将物理内存划分为固定大小的页,并通过虚拟内存系统为进程提供独立的地址空间...
3. **Linux系统调用**:Linux API主要由系统调用组成,如`open()`用于打开文件,`read()`和`write()`用于文件读写,`fork()`创建子进程,`execve()`执行新程序等。理解和掌握这些系统调用是编写高效、可靠的Linux...
在Linux环境下进行C语言编程,可以利用标准C库和Linux系统调用来实现更强大的功能。以下是一些核心概念: 1. 标准输入/输出:学会使用`stdin`、`stdout`和`stderr`进行输入输出操作。 2. 系统调用:熟悉常见的系统...
在Linux操作系统下进行C编程是一项基础且至关重要的技能,它涉及到对系统调用、标准库以及编译构建过程的理解。Linux作为一个开源的操作系统,为开发者提供了丰富的资源和强大的工具,使得C语言编程更加灵活和高效。...
5. **系统调用**:Linux内核提供了丰富的系统调用接口,如`fork`用于创建子进程,`execve`用于执行新的程序,`waitpid`用于等待子进程结束,`pipe`和`socket`则用于进程间通信。理解这些系统调用是深入Linux编程的...
在Linux环境下,C语言可以直接调用系统调用(如`fork`、`execve`、`pipe`、`socket`等)来实现进程创建、文件操作、网络通信等功能。此外,C语言还支持进程间通信(IPC)技术,如管道(pipe)、消息队列、共享内存和...
例如,在上面的示例中,使用 ltrace 工具可以看到程序调用了 puts() 库函数,而使用 strace 工具可以看到程序的系统调用过程,包括 execve、brk、access、mmap2、open、read、fstat64、close 等系统调用。...
7. **系统调用**:Linux内核提供了大量系统调用,如open(), close(), read(), write(), fork(), execve()等,C程序员可以直接调用这些系统调用实现对硬件和系统的低级别访问。 8. **错误处理**:在Linux下编程,...