exec 是否直接跳转到它创建的新进程?还是通过内核中断?

Does exec directly jump to the new proccess it creates? Or by kernel interrupt?

在 UNIX 中,新进程由 exec 系统调用启动。至于新进程是如何启动的,Operating Systems Principles and Practices一书中说,首先OS为新进程分配新内存,然后将初始状态存储到内核中断堆栈,最后使用popadiret指令退出内核启动进程,将处理器状态设置为内核中断堆栈中存储的状态,并跳转到内核中存储的代码地址中断堆栈。

但我想知道,为什么不直接在 exec 函数中设置初始状态并直接跳转到新进程?

关于内核中断如何启动进程,我的陈述有什么不对吗?

Exec does NOT create a new process. Fork 确实如此。

The exec() family of functions replaces the current process image
with a new process image.

正在检查 _execve

的 glibc 实现
/* Replace the current process, executing FILE_NAME with arguments ARGV and
   environment ENVP.  ARGV and ENVP are terminated by NULL pointers.  */

您可以深入了解细节并查看它是如何实现的。


But I wonder, why not just set initial states and jump to new process directly within the exec function?

线程就是这样工作的,进程有自己的状态,有自己的优先级、文件描述符、中断 table 等等。

In UNIX, a new process is started by exec system call.

不是真的。 forkclone 创建一个新进程。 exec 将用 现有 进程中的另一个程序替换当前 运行ning 程序。

But I wonder, why not just set initial states and jump to new process directly within the exec function?

这意味着您要在用户级别完全模拟 exec()(使用 open()read() 等)而不是使用内核。

在许多情况下,这在理论上是可行的。但是,在某些情况下这是不可能的。 (考虑具有 -rws--x--x 访问权限的文件!)

并且需要整个文件格式解释器在用户级别的 exec() 函数中。特别是在使用静态链接的可执行文件时,每个调用 exec() 的程序都必须包含解析可执行文件的文件格式的代码。

在这种情况下,不同的程序可能支持不同的文件格式:一些为 Linux 内核 1.2.13 编写的程序将能够 运行 两者(当时新引入的) ELFa.out 可执行文件,而其他人只能 运行 a.out文件;不是所有程序都能被所有程序启动。

内核实现(使用系统调用)将支持或不支持独立于调用 exec() 的程序的特定文件类型。

下一个问题是用户级实现可能会“忘记”一些反初始化代码:假设您使用为 Linux 2.4 编写的 exec() 实现并调用 timer_create() 系统调用。因为 exec() 实现不知道这样的计时器存在,所以它不会停止计时器。

内核实现(使用系统调用)了解操作系统的所有功能,因此在启动新程序之前完全清理“旧程序”。