进程可以在内核不知道的情况下执行新程序吗?通常,当程序执行时,内核在接收到系统调用(例如 exec() 或 fork())后会给它自己的进程。在这种情况下,一切都通过内核,最终使用 ELF 处理程序等程序启动程序。当然,在实践中,当运行一个新程序时,您需要一个单独的进程,但如果没有必要怎么办?程序/进程 xhathat 是否可以将可执行二进制文件从文件系统(是的,通过系统调用)传输(如果还没有)到它自己的虚拟内存区域并开始在其进程内执行它?在这种情况下,内核仍然只知道程序/进程 xhathat 正在做某事,但它不会单独知道 xhathat 执行的这个程序?
至于“内核不知道”......这是什么意思?
我的意思是,内核实际上并不“启动/执行程序”(通常内核总是这样做,无论它是二进制文件还是包含 shebang 的解释脚本),而只是间接地“启动/执行程序”。是的,它从大容量存储中加载一个新程序到这个xhathat进程的内存区域中,但不会启动/执行它,也不知道它的启动/执行。它不执行 exec()、fork() 等各种启动/执行的内核系统调用。例如,当内核没有有意识地启动某个程序时,该程序也不会出现在进程中(因为它只是 xhathat 进程内的“进程/执行”)。你能赶上吗?据我所知,二进制编译的程序(当然也包括解释的程序)也是可能的。当我意识到 bash 或 systemd 或任何“启动/执行”程序/进程的东西时,我才想到这一点,通常内核实际上会执行启动/执行(甚至是 shebang 脚本,如我之前所述)。然而,当我了解到这一点后,我不得不想,难道就一定要这样吗?我接受你的回答,不必如此;当然,这样做通常更好(内核启动所有程序/进程),这就是所做的。
顺便说一句,完成我所描述的操作需要什么(简单地说)内核?我唯一想到的就是从大容量存储器中下载这个新程序,但是如果该程序已经在中央存储器中并且不需要单独从大容量存储器中下载怎么办?该进程是否可以直接开始执行新程序/“进程”而不与内核进行任何交互?
答案1
是的,这是可能的。已经运行的进程需要将新程序加载(或映射)到进程虚拟地址空间中的适当位置,必要时加载动态加载器,在堆栈上设置所需的数据结构,然后跳转到新程序的位置。内存中的入口点。 (其中许多操作都涉及内核,但与加载新程序无关。)
fork
如果没有内核的帮助,进程无法创建全新的地址空间,但这通常不是什么大问题,因为启动程序不应期望在新程序运行后重新获得控制权,因此这并不重要这两个程序共享它们的地址空间。
看格鲁格的Userland Exec的设计与实现以获得更详细的解释。
答案2
是也不是……
因此,简单地说,许多程序语言都是解释性的。因此,如果您的第一个程序是在 python 解释器中运行的 python 程序,那么只需导入另一个文件并开始运行它就很简单了。
使用二进制程序而不是解释程序来完成同样的事情只是稍微困难一点。
至于“内核不知道”......这是什么意思?第二个程序从哪里来?你是从磁盘加载的吗? (内核会为你做这件事......)你是从网络加载的吗? (内核也这样做。)如果你想替换可执行页面,现代内核在大多数情况下不允许写入带有可执行代码的页面,或者可写页面包含将要执行的代码,因此要更新本机机器代码页而不仅仅是解释新的东西,内核必须参与加载这些页面并使它们可执行。
如果没有内核的直接参与,一个进程无法启动另一个进程。它可能能够替换自身或向自身添加更多可执行代码,而无需大量内核参与,但您无法避免需要执行某种 I/O 来获取这些页面。
内核“知道”正在运行的进程,因为:
- 作为页表权限的一部分,它知道内存中的哪些页面可供进程执行。这不能轻易绕过。
- 它(通常)知道这些可执行页面来自哪个文件,因为它们被映射到内存并按需分页,这意味着内核按需将磁盘上文件中的页面加载到内存中。即使页面已经缓存在内存中,这仍然作为页面缓存系统的一部分发生。
- 内核知道用于启动初始可执行文件的名称。
- 内核知道进程启动时的命令行和环境——尽管进程可以在大多数系统上编辑它
- 内核知道哪些文件被打开并被红色。
上述大部分内容都可以ps
在所有 UNIX 系统上用该命令显示。以上所有内容均可在/proc/
Linux 系统上使用(页表信息除外)。
那么不使用exec()可以完成吗?当然!可以在不以某种方式涉及内核的情况下完成吗?并不真地。