当前位置: 首页 > news >正文

【Linux】进程程序替换

目录

一.什么是进程程序替换

二.怎样实现

execl函数

单进程程序替换完整代码

 父子进程程序替换完整代码

基于execl谈程序替换原理

1.单进程

2.多进程

 三.其他程序替换类函数(除execl)

​编辑

 1.execlp

 ​编辑

2.execv

3.execle

4.execvp和execvpe

5.总结

四.如何利用程序替换函数调用自己写的程序


hello,各位大佬!Linux进程程序替换也是Linux进程中非常重要的部分。我们将从什么是Linux进程程序替换,为什么要有Linux进程程序替换,以及如何实现Linux进程程序替换(原理)三个方面展开讲解。闲话少叙,我们正式开始!!

想要弄明白为什么要有进程程序替换,我们首先要知道父进程创建子进程的目的是什么?想要子进程完成什么样的任务?

  • 想让子进程执行父进程代码的一部分。
  • 让子进程想办法,加载磁盘上的指定程序,然后执行新程序对应的代码和数据。(这就是我们所讲的进程程序替换

一.什么是进程程序替换

进程程序替换顾名思义,就是将其他程序替换过来继续执行,主要是通过exec* 这类函数来帮助我们替换,直接来学这类函数。

二.怎样实现

进程程序替换函数其实不止一个函数,而是由六个以execl开头的函数构成的函数族,如下图:

其中,最常用的就是execl,我们就用execl为例讲解。我们理解了一个函数的使用方法和原理,对其他相关函数的学习就会起到事半功倍的效果。

execl函数

      int execl(const char *path, const char *arg, ...);后边的“...”是可变参数列表,意为可以传入多个参数。

 要完成进程替换需要哪些工作?

  1. 我们要找到要替换的程序所在路径,即找到。execl的第一个参数的作用就是传入替换程序的具体路径。
  2. 然后,我们要找到程序的执行方法,就是在命令行中如何执行,就要如何传入。除第一个外,其他参数都是用来传入执行方法的。执行方法传入完毕后,以null结尾。

实例:

   execl("/usr/bin/ls","ls","-a","-l","--color=auto",NULL); 

单进程程序替换完整代码

#include<stdio.h>
#include<unistd.h>
int main()
{printf("start.......\n");execl("/usr/bin/ls","ls","-a","-l","--color=auto",NULL);printf("end.......\n");}

 执行:

 父子进程程序替换完整代码

代码:

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
int main()
{pid_t id=fork();if(id==0){printf("start.......\n");execl("/usr/bin/ls","ls","-a","-l","--color=auto",NULL);printf("end.......\n");}else{int status=0;pid_t fd=waitpid(id,&status,0);if(fd==id){printf("pid:%d,exist code:%d,sig code:%d\n",fd,(status>>8)&0xFF,status&0x7F);}}
}

运行结果: 

基于execl谈程序替换原理

1.单进程

我知道,此刻的大家心里一定有诸多的问题,比着急,我们一一探讨。

首先来看这张我们非常熟悉的图:

想必大家学到现在,这张图都不陌生了。

程序替换的原理就是:把物理内存中原来的代码和数据替换成目标程序的代码和数据,也就是说:调用execl之后的代码和数据都被替换掉了,有可能还要发生映射关系的改变。

程序替换的本质就是:将指定的代码和数据,加载到指定的位置,然后覆盖自己的代码和数据。

为什么在单进程的运行结果中,第一条打印语句执行了,而第二条打印语句没有执行?

因为在execl语句之后的代码和数据,在物理内存中被目标程序的代码和数据替换掉了(也就是覆盖掉了),接下来执行的是目标程序的代码和数据,因为这个原因,第二条print语句没有被执行。

进程替换的时候,有没有创建新的进程?

没有,进程替换仅仅将物理内存中的代码和数据做了替换。虚拟内存和PCB表没有发生任何改变。 

关于返回值问题,为什么程序替换成功,没有返回值;程序替换失败返回值为-1?

 不需要,因为:exec类函数只要返回了,就一定是失败的。

  • 成功的情况下,就和接下来的代码无关了(不会再执行下面关于返回值的判断了),返回值也就变得毫无意义。
  • 失败的情况下,仍然执行接下来的代码,可能仍然需要利用返回值做某些判断,这时的返回值仍然有意义。

2.多进程

 在理解单进程程序替换的基础上,多进程的程序替换就容易理解了。

我们先要达成一个共识:写时拷贝这种机制,不仅仅是对数据,对代码也有写时拷贝策略。

子进程被创建,子进程继承父进程的PCB,虚拟内存,页表,并和父进程共同使用一份代码和数据。一方对代码和数据进行修改时,为该方创建一份新的内存空间,供其修改。这就是写时拷贝。

假如:子进程要对代码进行修改,操作系统为其分配一段新的内存空间,让其存放新的代码和附带数据,依旧保持内存的独立性。

所以,依旧还是两个进程在运行,并未产生新的进程。 

 三.其他程序替换类函数(除execl)

除execl外,其余五个函数的返回值问题,所属头文件,作用等等和execl都是相同的,差异主要体现在参数列表方面。详解如下:

 1.execlp

程序替换类函数的函数名称共同部分为:exec。然后后面再加不同的字母,显然这些字母代表着不同的含义:

l:list。表示将参数逐个传入。

p:path。如何找到程序的功能。带有p字符的函数,不用传入程序所在的具体路径,只要传入程序名,函数会自动在PATH里的路径下,进行可执行程序的查找。

 想必大家都知道execlp函数的使用方法了吧

如下:

#include<stdio.h>
#include<unistd.h>
int main()
{printf("start.......\n");execlp("ls","ls","-a","-l",NULL);printf("end.........\n");}

在execl函数的参数中,有两个“ls”,冲突吗?不冲突,第一个是告诉系统我要执行谁,一个是告诉系统我要如何执行。

运行一下

 

2.execv

v:vector,可以将执行参数放入数组中,进行同一传递。而不用使用可变参数方案。

#include<stdio.h>
#include<unistd.h>
int main()
{char *const argv_[]={"ls","-a","-l","--color=auto"};printf("start.......\n");execv("/usr/bin/ls",argv_);printf("end.........\n");}

运行一下:

 

3.execle

e:传入自定义环境变量,即可以查询系统中的环境变量。

代码实例:这次我们需要创建3个文件,makefile,mybin.c,getenv.cc

makefile:

.PHONY:all
all:my.out mybinmy.out:getenv.ccg++ getenv.cc -o my.out -std=c++11
mybin:mybin.cgcc mybin.c -o mybin -std=c++11
.PHONY:clean 
clean:rm -f my.out mybin

getenv.cc

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
int main()
{printf("start.......\n");putenv("myenv=1111122222");//作用为:向环境变量中导入自定义的环境变量。execl("./mybin","mybin",NULL,environ);}

mybin.c

#include<stdio.h>
#include<stdlib.h>
int main()
{printf("PATH:%s\n",getenv("PATH"));printf("PWD:%s\n",getenv("PWD"));printf("myenv:%s\n",getenv("myenv"));printf("hello world\n");printf("hello world\n");printf("hello world\n");printf("hello world\n");printf("hello world\n");printf("hello world\n");}

4.execvp和execvpe

这两个函数其实就是前面我们所说的几个函数传参方式糅杂在一起而已,所以这里就不在讲了。

5.总结

刚刚好我们一共提到了6个函数,其实这些函数都是C语言封装的函数,这些函数都是由一个叫execve的函数封装而来。execve这个函数是系统调用接口,感兴趣的可以自己查一下。

四.如何利用程序替换函数调用自己写的程序

我们自己写的程序也是可执行程序,理论上也是可以使用程序替换函数进程程序替换的。

接下来,我们验证一下:创建三个文件:makefile,mybin.c getenv.cc

makefile:

.PHONY:all
all:my.out mybinmy.out:getenv.ccg++ getenv.cc -o my.out -std=c++11
mybin:mybin.cgcc mybin.c -o mybin -std=c++11
.PHONY:clean 
clean:rm -f my.out mybin

 mybin.c

#include<stdio.h>
#include<unistd.h>
int main()
{printf("start.......\n");execl("./mybin","mybin",NULL);}

  getenv.cc

#include<stdio.h>
int main()
{printf("hello world\n");printf("hello world\n");printf("hello world\n");printf("hello world\n");printf("hello world\n");printf("hello world\n");}

运行一下:

其实,无论是什么语言写的程序,只要是可执行程序,都可以使用进程替换函数执行。

 写到最后,因水平有限,难免会有错误,请各位指正!!

相关文章:

  • MSP430单片机控制流水灯,Proteus仿真
  • adb shell进入设备后的命令
  • [ZJCTF 2019]NiZhuanSiWei、[HUBUCTF 2022 新生赛]checkin、[SWPUCTF 2021 新生赛]pop
  • 【学习笔记】finalshell上传文件夹、上传文件失败或速度为0
  • 手机连接ESP8266的WIFI,进入内置网页,输入要显示的内容,在OLED显示屏上显示文本
  • 【C++题解】1457 - 子数整除
  • 内存卡执行格式化数据还能恢复吗?
  • qt自适应图片
  • [Vue3:axios]:实现登录跳转页面展示列表(查看教师所承担课程的学生选课情况)
  • 基于springboot实现交通管理在线服务系统项目【项目源码+论文说明】计算机毕业设计
  • [一] 解释自己思维判断与行为 - 《情报分析心理学》读后感
  • Java中如何调用mysql中函数
  • LVGL移植和图片显示
  • 聚焦新版综合编程能力面试考查汇总
  • Vue18-列表渲染
  • [译]Python中的类属性与实例属性的区别
  • Docker容器管理
  • go语言学习初探(一)
  • Java 最常见的 200+ 面试题:面试必备
  • JavaScript函数式编程(一)
  • JAVA之继承和多态
  • LeetCode29.两数相除 JavaScript
  • python大佬养成计划----difflib模块
  • Redux系列x:源码分析
  • Three.js 再探 - 写一个跳一跳极简版游戏
  • tweak 支持第三方库
  • zookeeper系列(七)实战分布式命名服务
  • 工程优化暨babel升级小记
  • 聊聊sentinel的DegradeSlot
  • 再谈express与koa的对比
  • 回归生活:清理微信公众号
  • ​创新驱动,边缘计算领袖:亚马逊云科技海外服务器服务再进化
  • ​字​节​一​面​
  • # Panda3d 碰撞检测系统介绍
  • #pragma 指令
  • #QT 笔记一
  • #Spring-boot高级
  • #stm32驱动外设模块总结w5500模块
  • #中的引用型是什么意识_Java中四种引用有什么区别以及应用场景
  • $refs 、$nextTic、动态组件、name的使用
  • (20)docke容器
  • (Redis使用系列) Springboot 使用Redis+Session实现Session共享 ,简单的单点登录 五
  • (web自动化测试+python)1
  • (带教程)商业版SEO关键词按天计费系统:关键词排名优化、代理服务、手机自适应及搭建教程
  • (二)WCF的Binding模型
  • (二)windows配置JDK环境
  • (附源码)springboot炼糖厂地磅全自动控制系统 毕业设计 341357
  • (小白学Java)Java简介和基本配置
  • (原创) cocos2dx使用Curl连接网络(客户端)
  • (原創) 如何優化ThinkPad X61開機速度? (NB) (ThinkPad) (X61) (OS) (Windows)
  • (最全解法)输入一个整数,输出该数二进制表示中1的个数。
  • ... fatal error LINK1120:1个无法解析的外部命令 的解决办法
  • .bat批处理(一):@echo off
  • .net 4.0 A potentially dangerous Request.Form value was detected from the client 的解决方案
  • .net 4.0发布后不能正常显示图片问题