程序替换原理
用新进程的代码和数据覆盖旧进程的代码和数据,没有创建新进程,用旧进程的壳执行了新进程。
站在被替换进程的角度:本质就是程序从磁盘加载到了内存。
怎么加载呢?那就要用到相关的替换函数了
替换函数
有六种以exec开头的函数,统称exec函数:
#include <unistd.h>`
int execl(const char *path, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);
int execle(const char *path, const char *arg, ...,char *const envp[]);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execve(const char *path, char *const argv[], char *const envp[]);
注意:这些函数的参数以NULL结尾。
函数解释
这些函数如果调用成功则加载新的程序从启动代码开始执行,不再返回。 如果调用出错则返回-1
所以exec函数只有出错的返回值而没有成功的返回值。
例子:用list -l-a 指令替换原程序:
可见只执行了第一个printf,程序替换后,原程序后面的代码都不执行了,因为已经被覆盖了。
fork创建子进程,让子进程去替换,父进程等待。
调用举例
#include <unistd.h>
int main()
{
char *const argv[] = {"ps", "-ef", NULL};
char *const envp[] = {"PATH=/bin:/usr/bin", "TERM=console", NULL};
execl("/bin/ps", "ps", "-ef", NULL);
// 带p的,可以使用环境变量PATH,无需写全路径
execlp("ps", "ps", "-ef", NULL);
// 带e的,需要自己组装环境变量
execle("ps", "ps", "-ef", NULL, envp);
execv("/bin/ps", argv);
// 带p的,可以使用环境变量PATH,无需写全路径
execvp("ps", argv);
// 带e的,需要自己组装环境变量
execve("/bin/ps", argv, envp);
exit(0);
}
事实上,只有execve是真正的系统调用,其它五个函数最终都调用 execve