$ g++ program.cpp
$ ./a.out &
(program.cpp已修改。)
$ g++ program.cpp
如果覆盖可执行文件,运行过程如何仍能产生准确的结果?
答案 0 :(得分:7)
因为旧文件仍然存在。目录条目将指向一个新文件,但只要它保持打开状态,旧文件就会存在。关闭后,它将最终被删除。也就是说,在Unix上。在Windows上,您可能无法执行此操作,因为文件已打开且无法覆盖。
答案 1 :(得分:5)
这实际上取决于ld
(由g++
调用)如何创建
新的可执行文件。如果只是open
(带有正确的标志)
如果文件不存在则创建,那么会发生什么
运行过程取决于分页,但很有可能发生崩溃。
如果它首先执行unlink
,则在创建新文件之前,正在运行
进程将继续使用旧图像,该图像将仅被释放
当过程结束。
传统上,最初的Unix连接器使用了第一种策略
具有保持现有访问权限的优点
可执行文件。然而,这是在虚拟内存时代之前的时候
在exec
的调用中,一次性加载了一个可执行文件
之后发生的文件无关紧要。今天,如果我是
写一个链接器,我会使用第二个,但首先要读取模式
原始文件,并使用相同的模式创建新文件。
您可以通过创建来轻松查看正在使用的策略
可执行文件,然后更改模式,然后对其执行ls -il
重新编译,再次执行ls -il
。如果inode编号已更改,
链接器在打开输出之前正在执行unlink
。如果是的话
模式已更改(返回到您环境中的默认值),
链接器在执行之前无法读取原始模式
unlink
。
对于Linux下的g ++,无论是inode编号还是模式
更改。 (我会考虑模式改变了一个错误的事实。)IIRC,on
另一方面,Solaris下的ld
没有删除文件 - 我没有删除
回想起上面的测试,但我确实对程序有模糊的记忆
当我们重新编译他们正在使用的DLL之一时崩溃。
最后,FWIW,为什么删除文件不会导致应用程序崩溃:
Unix下的文件(由inode表示)是引用计数,并且是
当引用计数变为0时自动删除。(非常多
例如shared_ptr
。)每个目录条目都有一个引用计数
指向文件(每个硬链接),以及每个打开的文件描述符
指的是文件。在Unix下“删除”文件实际上并不存在
触摸该文件,它只是删除指向它的目录条目
(减少使用计数,这可能导致文件正在使用
删除)。加载的可执行文件包含一个打开的文件描述符
可执行文件及其加载的所有.so
,计为a
引用该文件,因此删除指向的最后一个目录条目
它仍将使引用计数大于0。
编辑:我可能会补充说,取消链接也会破坏硬链接(这会 仍然指向旧版本)。这可能不是问题 今天,因为每个人都只使用软链接(这是一个引用 文件名,而不是文件本身),但我记得回来了 早期,在软链接存在之前,我们努力避免破坏 链接:在我编辑的编辑器中,我们将输出写成了一个全新的 文件,然后将其移动到原始文件(如果inode计数 是1),或复制它(如果inode计数大于1;即如果 还有其他硬链接到我们不知道的文件)。
答案 2 :(得分:1)
没有
较早的./a.out
进程会将a.out
的内容映射到内存中(在各个部分中,您可以在/proc/$PID/smaps
中看到它们。)
后面的g++ program.cpp
取消链接现有的a.out
文件,并创建一个具有相同名称的新文件。早期的可执行文件仍然映射到内存中的早期文件未被修改。
答案 3 :(得分:0)
在Unix上,一旦旧文件关闭,它将被删除,而在Windows上,它会抛出错误,说无法在所需位置复制可执行文件