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

【Linux】进程程序替换——exec函数簇

进程程序替换


为什么进程替换:

子进程被创建出来,运行和父进程一样的代码,但是往往我们把子进程创建出来并不是想让子进程去和父进程执行相同的代码,而是想让子进程去执行另外一个程序;最常见例子就是我们使用的Linux下的命令语言解释器Bash了;

我们在Bash下时输入的命令,Bash收到后会常见子进程去执行我们输入的命令然后将结果输出;因为Bash也是一个程序,如果Bash直接自己去执行输入的命令那么结束后退出,不是直接就关闭了难道一条命令要启动异常这是不合常理也是不对滴,所以Bash就要创建子进程去完成命令,而自身就一直等待命令处理就行了;而子进程就要进行程序替换去执行用户输入的命令了;

进程替换原理:子进程往往要调用一种exec函数以执行另一个程序。当进程调用一种exec函数时,该进程的用户空间代码和数据完全被新程序替换,从新程序的启动例程开始执行。调用exec并不创建新进程,所以调用exec前后该进程的id并未改变。
在这里插入图片描述
注意:这里的替换原理就是将子进程中映射页表中映射数据段和代码段的的位置进行初始化,然后让页表重新映射到要替换的程序的代码段和数据段;更通俗易懂的就是在页表上动手脚,修改页表映射让其映射到新的程序;而不是在页表映射的那一块物理内存上动手脚;

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[]);
注意:以上的六个函数都可以完成函数替换,根据场景不同使用合适的函数;
所以前五个可以在手册man 3中找到,而最后可以在手册man 2中找到;
这六个函数中只有execve()函数时系统调用,其他都是在execve()函数上根据不同的场景不同封装而成;

在这里插入图片描述

函数解释

  • 如果函数调用成功则函数就会去执行没有返回值
  • 如果函数调用失败,返回-1
  • 函数只有失败时才返回,成功了就没有返回值

命名理解

  • l(list) : 表示参数采用列表,必须以NULL结尾
  • v(vector) : 参数用数组,必须以NULL结尾
  • p(path) : 有p自动搜索环境变量PATH
  • e(env) : 表示自己维护环境变量,表示想给新的程序传入一些新的环境变量

在这里插入图片描述

//这个demo体会exec函数簇进行函数替换原理
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>

int main()
{
 //基础函数exec,根据后面添加的不同函数的参数也是不相同的
 // execl("/usr/bin/ls","ls","-ll",NULL); //l代表:参数采用列表的方式,参数类表最后一定要以NULL结尾
 //execlp("ls","ls",NULL);//p代表:参数采用数组的方式,同样数组最后一定要以NULL结尾
 
 char* argv[]={"ls","-l",NULL};
 //execv("/usr/bin/ls",argv);
 //execvp("ls",argv);

 char *const envp[] ={"PATH=/bin:/usr/bin", NULL};
 //execle(/usr/bin/ls","ls","-ll",NULL,)
 execve("/usr/bin/ls",argv,envp);
  return 0;

注意:一般在调用exec函数后,直接就有exit()进行验证;
如果执行后获取到子进程的退出码是自己写的exit(函数内面的退出状态码),
那就说明替换就失败了(上述代码未注明);
}

在这里插入图片描述

总结

1、问什么exec函数簇没有返回值?

因为exec函数进行函数替换,替换的就是数据段和代码段,exec本身是有返回值的,但是这个返回值存在替换前的数据段,如果替换成功那么数据段已经被替换为新的数据段原先的的数据段已经被丢弃,那么exec的返回值也就被丢弃了所以就造成了替换成功没有返回值的现象了;但是相反替换失败了返回值存在替换前的数据段,而失败了该数据段没有被替换所以就会将返回值返回了;其实我们没有必要去关注这个返回值是什么,因为成功了没有返回值,相反失败了一个失败了那么就更没有必要去关注这个返回值是什么了;

2、在命令行输入的命令其实就是一个个进程,那么bash怎么样将这些程序跑起来?

bash先读取命令行输入的参数,进行命令解析。然后fork()创建一个子进程,bash开始wait()等待子进程;子进程开始进程替换然后将命令参数传入,去执行;

3、全局变量具有全局性,那么子进程怎样继承父进程的全局变量呢?

所有的程序都是从main函数开始的,而main函数有几个参数argc、argv、env等:其实就是在子进程函数替换时bash通过main函数的参数把环境变量给了要执行的进程

相关文章:

  • 【Linux】入门基础命令(2)
  • 【Linux】权限管理和粘滞位理解
  • linux下inode节点理解
  • C语言函数
  • C语言数组
  • C语言表达式
  • C语言初识指针
  • C语言结构体
  • C语言深度剖析数据在内存中的存储
  • 深入了解指针
  • 字符串函数(认识 + 实现)
  • C语言内存函数(认识 + 实现)
  • 内存对齐和位段
  • 枚举和联合
  • 线性表,顺序表,链表,数组的区别与联系
  • [NodeJS] 关于Buffer
  • 【从零开始安装kubernetes-1.7.3】2.flannel、docker以及Harbor的配置以及作用
  • CentOS从零开始部署Nodejs项目
  • Fastjson的基本使用方法大全
  • JSDuck 与 AngularJS 融合技巧
  • Node项目之评分系统(二)- 数据库设计
  • Odoo domain写法及运用
  • Travix是如何部署应用程序到Kubernetes上的
  • 对话 CTO〡听神策数据 CTO 曹犟描绘数据分析行业的无限可能
  • 仿天猫超市收藏抛物线动画工具库
  • 关于使用markdown的方法(引自CSDN教程)
  • 前端 CSS : 5# 纯 CSS 实现24小时超市
  • 前嗅ForeSpider中数据浏览界面介绍
  • 使用 @font-face
  • 写给高年级小学生看的《Bash 指南》
  • 最近的计划
  • hi-nginx-1.3.4编译安装
  • Play Store发现SimBad恶意软件,1.5亿Android用户成受害者 ...
  • 阿里云重庆大学大数据训练营落地分享
  • ​ 轻量应用服务器:亚马逊云科技打造全球领先的云计算解决方案
  • ​RecSys 2022 | 面向人岗匹配的双向选择偏好建模
  • ​ubuntu下安装kvm虚拟机
  • # 深度解析 Socket 与 WebSocket:原理、区别与应用
  • $(function(){})与(function($){....})(jQuery)的区别
  • (2)nginx 安装、启停
  • (TipsTricks)用客户端模板精简JavaScript代码
  • (第二周)效能测试
  • (附源码)springboot车辆管理系统 毕业设计 031034
  • (七)c52学习之旅-中断
  • (三维重建学习)已有位姿放入colmap和3D Gaussian Splatting训练
  • (原創) 人會胖會瘦,都是自我要求的結果 (日記)
  • (转)总结使用Unity 3D优化游戏运行性能的经验
  • *1 计算机基础和操作系统基础及几大协议
  • .Net(C#)自定义WinForm控件之小结篇
  • .NET关于 跳过SSL中遇到的问题
  • .NET设计模式(11):组合模式(Composite Pattern)
  • .NET与java的MVC模式(2):struts2核心工作流程与原理
  • .NET中使用Redis (二)
  • /etc/shadow字段详解
  • @hook扩展分析