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