Linux的进程创建

news2024/9/22 7:28:24

在Linux下面,对二进制程序有着严格的格式要求,这就是ELF,这个格式可以根据编译的结果不同,分为不同的格式。

ELF的三种类型

一:可重定位文件

在编译的时候,先做预处理工作,例如将头文件嵌入到正文中,将定义的宏展开,然后就是真正 的编译过程,最终编译成为.o文件,这就是ELF的第一种类型,可重定位文件,长这样:

 二、可执行文件:

要想让函数作为库文件被重用,不能以.o的形式存在,而是要形成库文件,最简单的类型是静态链接库.a文件(Archives),仅仅将一系列对象文件(.o)归档为一个文 件,使用命令ar创建

ar cr libstaticprocess.a process.o

虽然这里libstaticprocess.a里面只有一个.o,但是实际情况可以有多个.o。当有程序要使用这个静态连接库的时候,会将.o文件提取出来,链接到程序中。在这个命令里,-L表示在当前目录下找.a文件,-lstaticprocess会自动补全文件名,比如加前缀 lib,后缀.a,变成libstaticprocess.a,找到这个.a文件后,将里面的process.o取出来,和 createprocess.o做一个链接,形成二进制执行文件staticcreateprocess。这个链接的过程,重定位就起作用了,原来createprocess.o里面调用了create_process函数,但是不能确定位置,现在将process.o合并了进来,就知道位置了,形成的二进制文件叫可执行文件,是ELF的第二种格式

这个格式和.o文件大致相似,还是分成一个个的section,并且被节头表描述。只不过这些section是多个.o文件合并过的。但是这个时候,这个文件已经是马上就可以加载到内存里面执行的文件了,因而这些section被分成了需要加载到内存里面的代码段、数据段和不需要加载到内存里面的部分,将小的section合成了大的段segment,并且在最前面加一个段头表 (Segment Header Table)。在代码里面的定义为struct elf32_phdr和struct elf64_phdr,这里面除了有对于段的描述之外,最重要的是p_vaddr,这个是这个段加载到内存的虚拟地址。

三、共享对象文件

静态链接库有个缺点,就是一旦链接进去,代码和变量的section都合并了,因而程序运行的时候,就不依赖于这个库是否存在,是相同的代码段,如果被多个程序使用的话,在内存里面就有多份,而且一旦静态链接库更新了,如果二进制执行文件不重新编译,也不随着更新。因为出现了另外一种——动态链接库,不仅是一组对象文件的简单归档,而是多个对象文件的重新组合,可被多个程序共享。

gcc -shared -fPIC -o libdynamicprocess.so process.o

当一个动态链接库被链接到一个程序文件中的时候,最后的程序文件并不包括动态链接库中的代 码,而仅仅包括对动态链接库的引用,并且不保存动态链接库的全路径,仅仅保存动态链接库的 名称。动态链接库就是第三种类型,共享对象文件

基于动态连接库创建出来的二进制文件格式还是ELF,但是稍有不同。首先,多了一个.interp的Segment,这里面是ld-linux.so,这是动态链接器,也就是说,运行时的链接动作都是它做的。另外,ELF文件中还多了两个section,一个是.plt,过程链接表(Procedure Linkage Table, PLT),一个是.got.plt,全局偏移量表(Global Offset Table,GOT)

比如对于dynamiccreateprocess这个程序要调用libdynamicprocess.so里的create_process函数。由于是运行时才去找,编译的时候,压根不知道这个函数在哪里,所以就在PLT里面建立一项 PLT[x]。这一项也是一些代码,有点像一个本地的代理,在二进制程序里面,不直接调用 create_process函数,而是调用PLT[x]里面的代理代码,这个代理代码会在运行的时候找真正的 create_process函数。而代理代码就是用到了GOT这里面也会为create_process函数创建一项GOT[y]。这一项是运行时create_process函数在内存中真正的地址。

对于GOT怎么直到create_process函数在内存中真正的地址?一开始创建了GOT[y]里面是空的,他调用plt[0],PLT[0]转而调用GOT[2],这里面是是ld-linux.so的 入口函数,这个函数会找到加载到内存中的libdynamicprocess.so里面的create_process函数的地址,然后把这个地址放在GOT[y]里面。

运行程序为进程

上面讲完了ELF格式,生成ELF文件之后还是个程序,那怎么把这个文件加载到内存里面呢?在内核中,有这么一个数据结构用来定义加载二进制文件的方法

struct linux_binfmt {
 struct list_head lh;
 struct module *module;
 int (*load_binary)(struct linux_binprm *);
 int (*load_shlib)(struct file *);
 int (*core_dump)(struct coredump_params *cprm);
 unsigned long min_coredump; /* minimal dump size */
} __randomize_layout;

对于ELF文件,有对应的实现:

static struct linux_binfmt elf_format = {
 .module = THIS_MODULE,
 .load_binary = load_elf_binary,
 .load_shlib = load_elf_library,
 .core_dump = elf_core_dump,
 .min_coredump = ELF_EXEC_PAGESIZE,
};

 原理exec这个系统调用最终调用的load_elf_binary

 进程树

既然所有的进程都是从父进程fork过来的,那总归有一个祖宗进程,这就是咱们系统启动的init进程。在解析Linux的启动过程的时候,1号进程是/sbin/init。如果在centOS 7里面,我们ls一下,可 以看到,这个进程是被软链接到systemd的。PID 1的进程就是我们的init进程systemd,PID 2的进程是内核线程kthreadd,这两 个我们在内核启动的时候都见过。其中用户态的不带中括号,内核态的带中括号。

总结

对高级编程语言,比如对C语言:

1、我们先将文件编译成so文件和可执行文件,放在硬盘上。

2、用户态的进程A执行fork(),创建进程B。

3、在进程B的处理逻辑中,执行exec系列系统调用,这个系统调用会通过load_elf_binary方法,将刚才生成的可执行文件,加载到进程B的内存中执行。 

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

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

相关文章

VueX简单又详细的解读,看了就会用

一、VueX是什么 Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式 库。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。 二、为什么要用VueX “单向数据流”理念的简单示意: 当我们的应用遇到多个组…

Redis缓存

一.简介 缓存就是数据交换的缓冲区(称作Cache [ kʃ ] ),是存贮数据的临时地方,一般读写性能较高 二.添加Redis缓存 三.缓存更新策略 1.主动更新策略 Cache Aside Pattern(推荐) 需要调用者自己编码,但可控性高 Re…

SimSiam-Exploring Simple Siamese Pepresentation Learning

SimSiam Abstract 模型坍塌,在siamese中主要是输入数据经过卷积激活后收敛到同一个常数上,导致无论输入什么图像,输出结果都能相同。 而He提出的simple Siamese networks在没有采用之前的避免模型坍塌那些方法: 使用负样本lar…

K_A08_003 基于 STM32等单片机驱动L9110模块按键控制直流电机正反转加减速启停

目录 一、资源说明 二、基本参数 1、参数 2、引脚说明 三、驱动说明 L9110模块驱动时序 对应程序: PWM信号 四、部分代码说明 接线说明 1、STC89C52RCL9110模块 2、STM32F103C8T6L9110模块 五、基础知识学习与相关资料下载 六、视频效果展示与程序资料获取 七、项目主要…

【Android工具】群晖安卓客户端基础套件:Drive、video、Photos和DS video安卓TV客户端...

微信关注公众号 “DLGG创客DIY”设为“星标”,重磅干货,第一时间送达。最近终于把all in one搞起来了,all in one就是把一堆功能一堆软件装一台主机里。。all in one(以后简称AIO)相关内容回头慢慢聊。今天先聊聊群晖&…

从一个demo说elf文件

本文的demo是在linux环境下编译解析的,cpu是x86-64 首先我们先写一个功能简单的demo-SimpleSection.c。这个demo中有一个func1函数用来打印数据,一个已经初始化的全局变量global_init_var和未初始化的全局变量global_uninit_var,一个已初始化…

使用TS 封装 自定义hooks,实现不一样的 CRUD

文章目录使用TS 封装 自定义hooks,实现不一样的 CRUD自定义 hooks文件结构type.tsuseDelData.ts使用useFetchList.ts使用useInsert.ts使用部分的接口方法使用TS 封装 自定义hooks,实现不一样的 CRUD 这一篇主要是记录 查缺补漏,提升自己的 强…

三、内存管理 (一)存储器管理

目录 1.1程序运行的基本过程 1.1.1 编辑、编译、链接、装入 1.1.2链接的三种方式 1.1.3装入的三种方式 1.2内存管理基本概念 1.2.1内存保护 1.2.2内存空间扩充 1.2.3地址转换功能 1.2.4内存空间的分配与回收 1.2.4.1连续分配管理方式 1.2.4.1.1单一连续分配 1.2.4.1…

Http协议和Https协议

Http是不安全的,你的数据容易被黑客拦截,篡改,攻击 https要求对数据加密(不能明文传输), 用抓包工具抓http请求,抓出来的都是明文的,你能看得懂的,抓https请求,抓出来的…

网站域名被QQ拦截提示:当前网页非官方页面拦截的解决办法

今天网友提醒,星空站长网的链接被QQ屏蔽拦截了。提示:当前页面非官方页面,请复制到浏览器打开。 如图: 原因:这是因为QQ方面的诈骗信息特别多,所以腾讯官方索性就直接屏蔽了所有的外部链接。让站长们通过申…

Python源码剖析笔记1-整数对象PyIntObject

1、PyIntObject 对象 [intobject.h] typedef struct {PyObject_HEADlong ob_ival; } PyIntObjectPyIntObject是一个不可变(immutable)对象。Python内部也大量的使用整数对象,我们在自己的代码中也会有大量的创建销毁整型对象的操作&#xff…

SVM 用于将数据分类为两分类或多分类(Matlab代码实现)

👨‍🎓个人主页:研学社的博客 💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜…

CMake中install的使用

CMake中的install命令用于指定安装时要运行的规则&#xff0c;其格式如下&#xff1a; install(TARGETS targets... [EXPORT <export-name>][RUNTIME_DEPENDENCIES args...|RUNTIME_DEPENDENCY_SET <set-name>][[ARCHIVE|LIBRARY|RUNTIME|OBJECTS|FRAMEWORK|BUNDL…

基于单片机的电压电流表设计

原理图&#xff1a; 部分程序&#xff1a; #include "stc15.h" #include "delay.h" #include "timer.h" #include "TM7707.h" #include "LCD1602.h" #include "eeprom.h" #include "stdio.h" #include…

【数学】双根号求值域问题

∣双根号求值域问题NightguardSeries.∣\begin{vmatrix}\Huge{\textsf{ 双根号求值域问题 }}\\\texttt{ Nightguard Series. }\end{vmatrix}∣∣∣∣∣​ 双根号求值域问题 Nightguard Series. ​∣∣∣∣∣​ 求 f(x)3x−63−xf(x)\sqrt{3x-6}\sqrt{3-x}f(x)3x−6​3−x​ 的…

开发工具——gdb

开发工具gdb gdb在Linux下负责程序的调试。 gdb相较于vs2019的调试&#xff0c;是不方便的。图形化界面调试确实是一种进步的现象。 先编写一个简单的程序&#xff0c;如果不支持在for循环中定义变量&#xff0c;要在编译指令后面加上-stdc99选项。 要编译的文件和要生成的文…

Spring 源码编译

Spring 源码编译&#xff0c;一定要选好版本&#xff01;&#xff01;&#xff01; Spring 源码编译&#xff0c;一定要选好版本&#xff01;&#xff01;&#xff01; Spring 源码编译&#xff0c;一定要选好版本&#xff01;&#xff01;&#xff01; 重要的事说三遍。 Spri…

MYSQL用函数请三思

背景&#xff1a;最近公司有个同事遇到个需求需要用到mysql sleep函数&#xff0c;但结果却大出意料. 测试如下&#xff1a; 表&#xff1a; CREATE TABLE test_sleep ( id int NOT NULL AUTO_INCREMENT, a int NOT NULL, b int NOT NULL, PRIMARY KEY (id), KEY a (a) ) ENGIN…

电子学会2021年3月青少年软件编程(图形化)等级考试试卷(一级)答案解析

青少年软件编程&#xff08;图形化&#xff09;等级考试试卷&#xff08;一级&#xff09; 分数&#xff1a;100.00 题数&#xff1a;37 一、单选题&#xff08;共25题&#xff0c;每题2分&#xff0c;共50分&#xff09; 1. 花花幼儿园有三个班。根据下面三句话&…

CentosLinux 7 字符安装教程

打开VMware虚拟机,点击文件 — 新建虚拟机选项。在弹出的对话框中选择自定义(高级)选项。单机下一步。 以下步骤根据自己的所需自行配置