Linux程序替换

前言

上一期对进程的创建、终止、以及等待做了详细的介绍,对于进程控制的内容基本介绍的差不多了,本期来介绍进程控制的最后一个内容即进程的程序替换!

本期内容介绍

• 什么是进程的程序替换

• 单进程的程序替换

• 程序替换的基本原理

• 多进程的程序替换

• exec系列函数的参数含义

• exec系列函数的使用

● 什么是进程的程序替换?

以前我们所有创建的子进程执行的代码,都是父进程代码的一部分;现在,我们想要让子进程执行全新的任务,即执行全新的程序(全新的代码和数据),该如何实现呢?其实这就是我们要介绍的进程的程序替换!

程序替换是指让一个已经存在的进程加载并执行一个全新的程序,同时替换掉原来进程加载的代码和数据的技术!

注意:

1、程序替换会保留原来进程的PCB等内核数据结构

2、新加载的代码和数据会与原来的内核数据结构重新构成映射关系

● 单进程程序替换

程序替换其实上是学习一些接口,这些接口就是exec*系列的程序替换函数!由于我们还没有对程序替换的函数介绍,我们这里用一个最简单的先来看看现象:

我们发现,当前进程果然执行了ls指令(本质就是2进制的程序)!OK,也就是成功的进行了程序替换,但是有一个细节就是:为什么execl后面的代码不见了?要解释这个问题我们就得先介绍一下程序替换的基本原理!

● 程序替换的基本原理

使用exec*系列程序替换函数会将要替换的程序的代码和数据,加载到内存直接替换掉原来进程地址空间中的的代码和数据,然后新的代码和数据与原来进程的PCB等内核数据节后重新建立映射关系!注意:调用exec*系列函数并不会创建新的进程!

介绍到这里我们就可以回答上面栗子的问题了:为什么exec*后的代码不见了?原因是,exec*函数已经替换了原来进程的代码和数据,该进程原来的exec*后面的代码被覆盖了所以就无法被执行了!

• 扩展:站在替换程序的角度讲,就是该程序被OS加载到内存了!其实我们平时的进程加载本质都是OS内核去调用exec*的系统调用了!exec*类似于Linux的加载器函数!

● 多进程程序替换

上面是单进程直接执行程序的替换,但是我们的想法性不是这样的,我们想要的是让父子进程执行不一样程序;即让子进程执行新的代码和数据!所以我们下面来让子进程替换:

这里我们发现程序替换前后的进程的pid都是一样的,这也验证了前面的exec*系列函数替换不会创建新的进程!

介绍到这里就有出现了一个新的问题:

• 问题

当前进程怎么知道要从替换的新程序的最开始执行?最开始的地方在哪里?

首先,在我们编译形成可执行程序的时候,它的代码和数据不是杂乱无章的随便放的,而是有自己的存放规则即有自己的存放格式!Linux中可执行程序是以EFL格式的文件存放的,该文件中有一个表头的字段entry,这个字段就是存放的可执行程序的入口地址!所以我们在调用exec*后会直接获取该程序的头部信息entry!而我们每一个进程中,都有一个程序计数器eip(当前执行指令的下一条指令),本质就是寄存器!eip寄存器的内容每个进程都会私有一份,当进程切换时把自己的eip属性给eip寄存器,该进程就会知道从哪一行开始执行了。当程序替换的时候,子进程获取entry,将这个字段的地址填入到eip中,当前进程就知道新程序的入口了!

OK,本来我们是接着演示用我们当前的进程调用其他语言的程序,但是由于我们当前由于还没有系统的介绍exec*系列的函数,所以我们无法将替换ls指令变成替换其他的程序,例如C++等!我们下面来系统的介绍一下exec*系列的函数,然后再来做当前进程替换其他程序的演示!

● exec系列函数的参数含义

exec*系列的函数一共是有7个,其中一个是系统调用,其他六个是库函数!

系统调用

库函数

其实下面的这六个库函数的底层都是去调用execve这个系统调用的

上面的六个库函数主要分为两类:l类型和v类型;两个类型又都包含带p不带p和带e不带e;OK,要搞清楚他们是什么意思,就要先介绍exec*系列的参数了!

第一个参数是指要替换程序的路径(path)或替换的程序名(file)

第二个参数是指如何执行新程序(arg)

带e的有第三个参数(envp)是指环境变量!

l(list)是指第二个参数是连续的参数列表的形式

v(vector)是指第二个参数是数组的形式

p(path)是指有自动搜索的环境变量PATH

e(env)表示自己维护环境变量

上面的exec*函数的参数主要解决以下问题:

• 如何找到新替换的程序(第一个参数)?

如果不带p,此时第一个参数path表示替换程序的路径;如果带p说明该替换的程序有全局的环境变量PATH此时第一个参数表示替换程序的名称!

• 如何执行新替换的程序(第二个参数)?

如果带l表示执行方式采用参数列表,可以将替换的程序的执行以可变参数的形式传进去(命令行怎么执行,这里怎么传)最后以NULL结尾!如果不带l带的是v,说明将替换程序的执行以数组(指针数组)的形式传过去,最后以NULL结尾!其实这个参数会传递以明命令行参数的形式传递给新替换的程序!

• 是否维护自己的环境变量(第三个参数)?

如果exec*函数带了e且需要维护自己的环境变量,就需要第三个参数envp了,这个参数也是一个字符串指针数组,替换之后envp这个参数会完全替换掉原来的环境变量!

• 新替换的程序(带p)是如何知道自己的替换程序的位置的呢?

在程序地址空间那里介绍过,在程序的地址空间中有一部分存的就是命令行参数和环境变量:

而每个进程在创建的时候都会继承父进程的虚拟地址空间的内容(拷贝一份),如果当前进程替换了新的代码和数据,但是当前进程的PCB等内核数据结构没有变所以依然有PATH等环境变量(在替换过程中,环境变量不会替换)!所以就可以找到,不带p的其实也是继承了PATH等内容,但是它的接口应该是特殊设计过的所以得必须带路径!其实,不带p的exec*也可以和带p的一样指定绝对会相对路径!

• exec*的返回值

你肯定注意到了exec*系列的函数是有返回值的,它的返回值是啥意思呢?

exec*系列函数如果调用成功了,从执行位置开始执行不在返回!如果调用出错了,返回-1,继续执行替换以前exec*以后的代码!所以exec*只有失败的时候才返回,成功不会返回!

所以,我们不用关心exec*的返回值,如果失败了就不会替换且继续执行原来进程的exec*后面的代码!

● exec系列函数的使用

• execl

第一个使用过了,这里就简单的介绍一下!

• execlp

OK,这里我们可以在验证一下,程序替换不会修改环境变量的内容

先给bash导一个环境变量:

export CPDD=123456

我们下面就用带p的去验证:

我们可以使用makefile生成,但是我们目前的makefile只能生成一套依赖关系(以前在make和makefile那一期介绍过)如何生成两套生成关系呢?

可以加一个伪目标all生成两套关系:

OK,看结果:

这里我们不光验证了程序替换不会修改环境变量的值,还验证了当前进程替换我们自己写的程序!

• 注意:这里的process是要带路径的,因为他不是环境变量!!!

• 补充:如果要在当前进程中新增环境变量可以调用putenc接口

• execle

前两个和前面的一样不在介绍了,最后一个是替换程序的环境变量数组,可以是全新的自己的环境变量;也可以是纯老的环境变量:envrion

先验证,给替换的进程原来老的环境变量envrion

果然继承过来了!这也验证了子进程是可以看到父进程的环境变量表的!OK,现在我们想用我们自己的换将变量该怎么办呢??下面是,导入自己想到的环境变量的代码:

• execv

这个和上面的execl唯一的差别是上面的是将替换程序的执行以列表的形式传递,而以v结尾的exec系列函数是以数组的形式传递的:

当然也可以像上面的多进程程序的替换!

• execvp

• execvpe

后面的这两个由于和前面的l系列的只是如何执行的传参不一样其他都一样,这里就不在一一的演示了!

OK,好兄弟,本期分享就到这里,我们下期再见!

结束语:知不足而奋进,望远山而前行!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/45566.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

在 IVS 2024 加密盛会上开拓创新:CESS 引领去中心化云存储和 CD²N 之发展

作为基于区块链的去中心化云存储网络和 CDN 基础设施网络,CESS 在日本年度加密创业大会 IVS 2024 上成为焦点!此次活动在历史悠久的京都举办,围绕“跨越边界”这一主题,吸引了超过15,000 名参会者,其中包括 3,000 创始…

SpringCloudAlibaba基础五 Nacos配置中心

一 Nacos配置中心介绍 官方文档:https://github.com/alibaba/spring-cloud-alibaba/wiki/Nacos-config Nacos 提供用于存储配置和其他元数据的 key/value 存储,为分布式系统中的外部化配置提供服务器端和客户端支持。使用 Spring Cloud Alibaba Nacos C…

2024 福州市延安中学“拿云杯”复赛试题

回忆版(持续更新) 目录 答案 答案

风光摄影:相机设置和镜头选择

写在前面 博文内容为《斯科特凯尔比的风光摄影手册》读书笔记整理涉及在风景拍摄中一些相机设置,镜头选择的建议对小白来讲很实用,避免拍摄一些过曝或者过暗的风景照片理解不足小伙伴帮忙指正 😃,生活加油 99%的焦虑都来自于虚度时间和没有好…

【matlab】周期性信号分析

目录 信号预处理 周期性特征提取方法 频谱分析 傅里叶变换 快速傅里叶变换(FFT) 周期图法 Welch法 自相关分析 时频分析 基于模型的方法 时间序列分解 应用实例 提取信号的周期性特征是一个在信号处理领域广泛应用的技术,特别是在…

每日一练:奇怪的TTL字段(python实现图片操作实战)

打开图片,只有四种数字:127,191,63,255 最大数字为255,想到进制转换 将其均转换为二进制: 发现只有前2位不一样 想着把每个数的前俩位提取出来,组成新的二进制,然后每…

做3D渲染,选择什么显卡好?

对于设计行业的小伙伴来说,电脑配置的优劣是个尤为关键的要素,特别是显卡,对于很多人而言,如何选择一张最适合的 3D 渲染显卡确实一大难关! 在目前市场上,主流的显卡分别是 AMD 显卡和 NVIDIA 显卡&#x…

Java基础面试题大全

Java基础 语法基础 aab 和 ab 操作隐式的将操作的结果类型强制转换成持有结果的类型,而不会 比如对byte,short,int类型的操作,会先将他们提升到int类型,然后在执行操作。所以比如我定义了两个byte类型的a和b&#x…

KEIL 5项目中源文件图标带有雪花(四叶草)消除办法

今天在使用KEIL 5写STM32程序的时候,出现了一个错误: Error: L6218E: Undefined symbol test_for_diaodu (referred from main.o). 具体表现为,不管我把自己写的一个my.c里的什么函数或者变量名,即使在main.c中声明、引用了&#…

PCL从理解到应用【04】Octree 原理分析 | 案例分析 | 代码实现

前言 Octree 作为一种高效的空间分割数据结构,具有重要的应用价值。 本文将深入分析 Octree 的原理,通过多个实际案例帮助读者全面理解其功能和应用,包括最近邻搜索、半径搜索、盒子搜索以及点云压缩(体素化)。 特性…

搞懂负载均衡,零基础也可以!

本文作者:程序员鱼皮 免费编程学习 - 编程导航网:https://www.code-nav.cn 大家好,我是鱼皮。 周末在家写代码,无意中跟朋友提了下 LB,还说 LB 好的呱呱叫。 朋友笑了笑,问我 LB 是谁? 我解释…

加密软件|让数据传输更安全

加密软件在当今数字化时代扮演着至关重要的角色,它们通过先进的加密算法和技术,确保数据在存储、传输和分享过程中的安全性,从而保护个人隐私和企业机密。一、加密软件的基本作用数据加密:加密软件通过应用复杂的加密算法&#xf…

Python转换PDF为PowerPoint演示文件

PDF文件以其跨平台兼容性和版面固定性成为了分享和存储文档资料的首选格式。然而,在需要进行生动、互动性强的演示时,PDF的静态特性便难以满足个性化演示需求。将PDF文件转换为PowerPoint演示文稿可以解决这一问题。PowerPoint不仅提供了丰富的动画和过渡…

网关设备BL122实现Modbus RTU/TCP转Profinet协议

Modbus与Profinet是两种广泛应用于工业自动化领域的通信协议:Modbus因其简单性和兼容性,在许多工业设备中得到广泛应用;而Profinet提供了高速、高精度的通信能力,适合于复杂控制系统和实时应用,但两者之间的差异导致了…

uniapp easycom组件冲突

提示信息 ​easycom组件冲突:[/components/uni-icons/uni-icons.vue,/uni_modules/uni-icons/components/uni-icons/uni-icons.vue]​ 问题描述 老项目,在uniapp插件商城导入了一个新的uniapp官方开发的组件》uni-data-picker 数据驱动的picker选择器 …

测试人必会 K8S 操作之 Dashboard

在云计算和微服务架构的时代,Kubernetes (K8S) 已成为管理容器化应用的标准。然而,对于许多新手来说,K8S 的操作和管理常常显得复杂而神秘。特别是,当你第一次接触 K8S Dashboard 时,你是否也感到有些无所适从&#xf…

【Python】一文详细向您介绍 scipy.cluster.vq.kmeans() 的原理、常见用法和使用场景举例等

【Python】一文详细向您介绍 scipy.cluster.vq.kmeans() 的原理、常见用法和使用场景举例等 下滑即可查看博客内容 🌈 欢迎莅临我的个人主页 👈这里是我静心耕耘深度学习领域、真诚分享知识与智慧的小天地!🎇 🎓 …

python简单学习笔记

1. print 输出 print(2024, 年,我要想娘) # sep:设置打印多个内容的分隔符,默认值为空格 print(2024, 年,我要想娘, sep, end\n) # end:设置print执行结束后的操作,默认值为换行格式化输出 print(格式化字符串 % (变量1, 变量…

org.springframework.jdbc.BadSqlGrammarException异常

Bug 记录 概述 在执行定时任务更新电子书统计信息时,遇到了 org.springframework.jdbc.BadSqlGrammarException 异常,具体表现为 SQL 函数 count 被错误地解析为自定义函数 wiki.count,导致数据库更新操作失败。 详细描述 错误信息&#x…

计算机视觉之SSD目标检测

模型简介 SSD是一种单阶段目标检测算法,通过卷积神经网络进行特征提取,并在不同的特征层进行检测输出,实现多尺度检测。它采用了anchor的策略,预设不同长宽比例的anchor,并在每个输出特征层上预测多个检测框。SSD框架…