linux 运行的程序,把可执行文件或者动态库删除,程序会崩溃吗

当程序运行的时候,如果把可执行文件删除或者把这个程序依赖的动态库删除,程序会继续正常运行还是会崩溃 ?

当程序运行的时候,如果将可执行文件覆盖或者将程序依赖的动态库覆盖,程序会继续正常运行还是会崩溃 ?

这两个问题中有两个变量,一个是操作的对象,可执行文件还是依赖库;一个是操作的类型,把文件删除还是把文件覆盖。

本文通过实验的方式来记录这 4 中情况。

先列出结论,如下:

操作对象

删除

覆盖: cp new old

覆盖: mv new old

可执行文件

程序继续运行,不崩溃

操作失败,提示文件忙

程序继续运行,不崩溃

程序继续运行,不崩溃

动态库

程序继续运行,不崩溃

程序崩溃

程序继续运行,不崩溃

1 实验代码 

hello.c

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

void say_hello() {
    printf("hello\n");
    return;
}

hello.c 中实现了一个函数 say_hello(),将这个文件编译成一个动态库,名字为 libhello.so。

编译命令如下:

gcc -shared -fPIC -o libhello.so hello.c

hello.h

void say_hello();

hello.h 中是函数 say_hello() 的声明。这是使用 c 语言开发时常用的方式,头文件中是函数的声明,没有实现,c 文件是是函数的实现。引用库的时候包含头文件,然后再链接库。

main.c 

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "hello.h"

int main() {
  say_hello();
  sleep(500);
  return 0;
}

main.c 中包含了 hello.h 头文件,然后在编译的时候需要链接 libhello.so 这个动态库,否则编译会失败,提示找不到函数 say_hello() 的定义。

编译命令如下:

gcc main.c libhello.so

编译完成之后,使用 ldd 查看 a.out 依赖的动态库时会提示 libhello.so 找不到,这个时候我们还需要把 libhello.so 的路径设置到 LD_LIBRARY_PATH 环境变量中,命令如下:

export LD_LIBRARY_PATH=/home/wyl/exelib/:$LD_LIBRARY_PATH

设置之后,再使用 ldd 查看 a.out 依赖的库,就能看奥 libhello.so 的位置了。

2 实验记录

2.1 删除可执行文件 

2.1.1 rm -rf 删除文件 

 程序运行之后,通过 ps -ef |grep a.out 可以查看进程的 pid。得到进程的 pid 之后,就可以使用命令 cat /proc/[pid]/maps 看到进程的文件映射信息。如下图所示,能看到进程中映射的 a.out 信息。

然后删除 a.out,再使用 cat /proc/[pid]/maps 查看文件映射信息,可以看到 a.out 信息后边增加了一个标记 deleted。

这个时候程序没有崩溃,还在运行。

a.out 也没有真正从磁盘删除,只有 a.out 退出之后,这个文件没有程序使用之后,文件才会真正从磁盘删除。

什么信息能佐证文件是不是真正从磁盘删除呢,可以通过查看 inode 号。ls -i a.out 可以查看一个文件的 inode,然后使用 lsof | grep xxx 来过滤这个 inode 号,如果 inode 存在,说明文件没有被删除;否则,说明被删除了。

2.1.2 mv 移动文件 

mv 移动文件,把文件移动到另外一个目录,程序也会继续运行,不会崩溃。

如下图所示,是程序运行只后,执行 mv a.out a.out-bak,把文件重命名,这个时候能够看到系统能自动识别出来文件发生了重命名。

刚才的 mv,我们并没有改变 a.out 的目录。我们继续移动 a.out-bak 移动到其它挂载点的目录下,那么系统就显示 deleted 了,跟把 a.out 删除现象是一样的。

从上边的实验可以看出来,使用 mv 移动文件的时候,移动的目标位置也会影响系统的显示。

a.out 原本的路径是 /home/wyl/exelib,

第一次移动的时候是用的命令是 mv a.out a.out-bak,没有改变 a.out 的路径,这个时候系统是能自动识别出来的。

第二次移动的时候是用的命令是mv a.out-bak /run/,改变了 a.out 的路径,这个时候系统的显示和文件被删除是相同的。

在 linux 中移动文件,如果是在一个挂在点之内移动,那么就相当于给文件重名名,内核中的 inode 保持不变,系统能自动识别;

如果文件的移动跨了挂载点,那么就相当于将旧文件删除,然后创建了一个新的文件。

实验用的虚拟机的挂载点如下,可以看到 /home/wyl/exelib 所在的挂载点和 /run 所在的挂载点是不一样的。

2.2 覆盖可执行文件

 想到文件覆盖的话,我们能想到 cp new old 或者 mv new old。但是我们如果想要覆盖可执行文件的话,使用 cp 无法操作成功,提示文件正忙。我们只能使用 mv 的方式。

使用 mv 的方式覆盖文件之后,系统显示和文件被删除是一样的,都是在 a.out 后边标记了 deleted。

2.3 删除或覆盖动态库

删除或者覆盖动态库的时候,和删除或者覆盖可执行文件的时候,现象是基本相同的。

只有一点不一样,就是 cp old.so new.so 时可以执行成功的,并且这个操作会导致程序崩溃。

mv 覆盖是删除旧的,创建新的;cp 覆盖是覆盖旧文件的内容。

  • 21
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值