【Linux】:程序替换

 朋友们、伙计们,我们又见面了,本期来给大家解读一下有关Linux程序替换的相关知识点,如果看完之后对你有一定的启发,那么请留下你的三连,祝大家心想事成!

C 语 言 专 栏:C语言:从入门到精通

数据结构专栏:数据结构

个  人  主  页 :stackY、

C + + 专 栏   :C++

Linux 专 栏  :Linux

目录

1. 程序替换

2. 单进程的程序替换

2.1 单进程程序替换的原理

3. 多进程的程序替换

3.1 多进程程序替换原理

4. 剩余接口的介绍以及使用 

4.1 execl函数介绍

4.2 execlp函数介绍

4.3 execv函数介绍 

4.4 execvp函数介绍

4.5 替换别的程序 

5. 环境变量和程序替换

5.1 从bash开始继承 

5.2 从父进程开始继承 

5.3 环境变量默认继承

5.4 execle函数介绍 

5.5 execve系统调用 


1. 程序替换

我们创建的所有子进程,执行的代码都是父进程代码的一部分!那么如果我们想让子进程执行新的程序呢?执行全新的代码和访问全新的数据,不再和父进程有所瓜葛,那么就需要用到程序替换。

这么多程序替换的函数调用,到底该怎么样用呢?我们直接开始使用:

2. 单进程的程序替换

为了便于理解,我们先从单进程的程序替换开始:

int execl(const char *path, const char *arg, ...);

先来看最简单的程序替换接口,其中里面的三个点表示的意思就是可变参数,使用的方法和我们的printf函数中的可变参数一样;

我们程序要能运行起来,第一步先要找到这个程序,第二部如何运行。

  • const char* path表示:新程序的文件路径 + 文件名;
  • const char *arg表示:这个程序怎么运行(简单的说我们在命令行怎么输就怎么写,最终以NULL结尾)。

返回值:成功没有返回值,失败返回-1。

我们先来演示一遍:让ls命令替换掉我们写的可执行

#include <stdio.h>
#include <unistd.h>

int main()
{
    printf("pid: %d, exec command begin\n", getpid());
    sleep(3);
    // 程序替换
    execl("/usr/bin/ls", "ls", "-a", "-l", NULL);
    printf("pid: %d, exec command begin\n", getpid());

    return 0;
}

通过结果可以发现,我们通过execl成功完成了程序替换,但是代码中的最后一行代码为什么没有打印出来呢?这个到后续再解释!

2.1 单进程程序替换的原理

我们已经完成了单进程的程序替换,那么它的原理是什么呢?

当一个进程运行起来时,OS会为它创建PCB、虚拟地址空间、页表,将它的代码、数据加载到物理内存中,并且然后通过页表建立起虚拟到物理的映射关系;当进行程序替换时,execl就将要替换的程序代码和数据直接在物理内存中替换覆盖掉,此时原来的代码和数据就会被新替换的代码和数据覆盖掉,继续向后执行也就执行的新程序的代码和数据,这个过程中并没有创建新的进程。

3. 多进程的程序替换

见识过单进程的程序替换以及程序替换的原理,接下来替换一下多进程:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

int main()
{
    pid_t id = fork();
    if(id == 0)
    {
        // child
        printf("pid: %d, exec command begin\n", getpid());
        sleep(3);
        // 程序替换
        execl("/usr/bin/ls", "ls", "-a", "-l", NULL);
        printf("pid: %d, exec command begin\n", getpid());
    }
    // parent
    pid_t rid = waitpid(id, NULL, 0);
    if(rid == id)
    {
        printf("wait success, rid: %d\n", rid);
    }

    return 0;
}

3.1 多进程程序替换原理

首先,进程具有独立性,其次我们都知道,父子进程代码共享,数据以写时拷贝的方式各自私有一份,那么在程序替换的时候,把子进程的数据替换这没问题,因为父子数据各自私有,但是将代码替换,这就有点不能忍了,父子进程代码共享,既然子进程都执行的是替换后的代码,为什么父进程在程序替换的时候还是继续执行他自己代码呢?

是因为在多进程的程序替换时,当子进程启动程序替换覆盖它们的共享代码时,也会发生写时拷贝的方式,重新开辟一块空间,然后进行替换写入,这样父子进程的代码就不共享,子进程继续执行它替换后的代码,父进程继续执行自己的代码。

在替换完之后,子进程怎么知道从新程序的哪里开始执行呢?

我们的代码在编译形成可执行程序的时候会有一个程序入口地址--entry地址;

CPU内部的eip寄存器可以记录我们程序当前运行到哪里了,所以当程序替换之后,新程序的eip程序计数器就被修改为entry地址,所以就可以重新开始运行了。 

接下来解决上面遗留的问题: 代码中的最后一行代码为什么没有打印出来呢?

是因为在程序替换以后,代码和数据都被覆盖了,所以execl函数替换成功后,后续的代码没有机会执行了,因为已经被替换掉了!

所以我们不用判断它的返回值,如果继续执行了后续代码,说明程序替换出错了。</

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

stackY、

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值