4

$ g++ program.cpp

$ ./a.out &

(program.cpp 已修改。)

$ g++ program.cpp

如果可执行文件被覆盖,运行过程如何仍能产生准确的结果?

4

4 回答 4

7

因为旧文件仍然存在。目录条目将指向一个新文件,但只要旧文件保持打开状态,它就会存在。一旦关闭,它最终将被删除。也就是说,在 Unix 上。在 Windows 上,您可能无法执行此操作,因为文件已打开且无法覆盖。

于 2012-04-18T06:15:39.860 回答
5

这实际上取决于ld(由 调用g++)如何创建新的可执行文件。如果它只是做了一个open(如果文件不存在,则使用适当的标志进行创建),那么正在运行的进程会发生什么取决于分页,但很有可能发生崩溃。如果它是unlink第一个,在创建新文件之前,正在运行的进程将继续使用旧图像,只有在进程结束时才会释放旧图像。

传统上,最初的 Unix 链接器使用第一种策略,其优点是保留对现有可执行文件的访问权限。然而,这是在虚拟内存时代之前,当一个可执行文件被一次性加载时,在对 的调用中exec,之后文件发生的事情是无关紧要的。今天,如果我正在编写一个链接器,我会使用第二个,但首先读取原始文件的模式,然后以相同的模式创建新文件。

ls -il您可以通过创建可执行文件、然后更改模式、对其执行、然后重新编译并再次执行来轻松查看正在使用的策略ls -il。如果 inode 编号已更改,则链接器会unlink在打开输出之前执行操作。如果模式已经改变(回到你的环境中的任何默认值),链接器在执行 unlink.

以 Linux 下的 g++ 为例,inode 编号和模式都发生了变化。(我会考虑模式改变了一个错误的事实。)另一方面,IIRCld在 Solaris 下没有删除文件——我不记得做过上述测试,但我确实对程序崩溃时有模糊的记忆我们重新编译了他们正在使用的 DLL 之一。

最后,FWIW,为什么删除文件不会导致应用程序崩溃:Unix下的文件(由inode表示)是引用计数的,当引用计数变为0时会自动删除。(非常像shared_ptr。)有一个引用计数对于指向文件的每个目录条目(每个硬链接),以及引用该文件的每个打开文件描述符。在 Unix 下“删除”文件实际上并没有触及文件,它只是删除指向它的目录条目(这会减少使用计数,这可能会导致文件被删除)。已加载的可执行文件包含其可执行文件及其已加载的所有 s 的打开文件描述符.so,这被视为对该文件的引用,因此删除指向它的最后一个目录条目仍会使引用计数大于 0。

编辑:我可能会补充说,取消链接也会破坏硬链接(它将继续指向旧版本)。今天这可能不是问题,因为每个人都只使用软链接(它是对文件名的引用,而不是对文件本身的引用),但我记得在早期,在软链接存在之前,我们煞费苦心地避免断开链接:在我使用的编辑器中,我们将输出写入一个全新的文件,然后将其移动到原始文件(如果 inode 计数为 1),或复制它(如果 inode 计数大于 1 ; 即如果有其他我们不知道的文件的硬链接)。

于 2012-04-18T08:09:12.703 回答
1

没有。

前面的./a.out过程将 的内容映射a.out到内存中(在各个部分,您可以在 中看到它们/proc/$PID/smaps)。

后者g++ program.cpp 取消链接现有a.out文件并创建一个具有相同名称的新文件。早期的可执行文件仍然映射到内存中的早期文件没有被修改。

于 2012-04-18T06:18:15.153 回答
0

在 Unix 上,一旦旧文件关闭,它将被删除,而在 Windows 上,它会抛出一个错误,指出无法将可执行文件复制到所需位置

于 2012-04-18T06:17:59.200 回答