程序员的自我修养六可执行文件的装载与进程
可执行文件只有装载到内存以后才能被CPU执行
6.1进程虚拟地址空间
程序和进程的区别:
程序:是一个静态概念,它就是一些预先编译好的指令和数据集合的一个文件。
进程:是一个动态概念,它是程序运行时的一个过程,很多时候把动态库叫做运行时。
程序被运行起来以后,它就拥有了独立的虚拟地址空间。虚拟地址空间大小由CPU的位数决定。
下面使用的CUP都是以32位为主。程序运行的时候,进程只能使用那些操作系统分配给进程的地址。
Linux操作系统将进程的虚拟地址做了如下分配:
6.2 装载的方式
程序执行时所需要的指令和数据必须在内存中才能够运行。
最简单的就是静态装入:将程序运行所需要的指令和数据全都装入内存中。
当当程序所需要内存大于物理内存时,这个时候就要使用动态装入了:因为程序运行时是有局部性原理的,所以我们将程序最常用的部分驻留在内存中,不太常用的数据存放在磁盘里面。
动态装入的两种方法:
- 覆盖装入
- 页映射
6.2.1 覆盖装入
覆盖装入在没有发明虚拟存储之前使用比较广泛,现在已经几乎被淘汰。
覆盖装入的方法就是程序员在编写程序的时候必须手工将程序分割成若干块,然后编写一个小的辅助代码来管理这些模块何时应该驻留内存何时应该被替换掉。
如果程序有多个模块,程序员需要手工将模块按照它们之间的调用依赖关系组织成树状结构。
6.2.2 页映射
页映射是虚拟存储机制的一部分,它随着虚拟存储的发明而诞生。
页映射就是将内存和所有磁盘中的数据和指令按照页为单位划分成若干个页,以后所有的转载和操作的单位就是页。硬件规定页的大小有4096字节、8192字节、2MB、4MB等。
6.3 从操作系统的角度看可执行文件的装载
在动态装载中,可执行文件中的页可能被装入内存中的任意页。
6.3.1 进程的建立
从操作系统的角度看,一个进程最关键的特征是它拥有独立的虚拟地址空间,这使得它有别于其他进程。
程序创建的最通常情况:创建一个进程,然后装载相应的可执行文件并且执行。
在有虚拟存储的情况下,上述过程只需要要做三件事:
- 创建一个独立的虚拟地址空间
- 读取可执行文件头,并且建立虚拟空间与可执行文件的映射关系
- 将CPU的指令寄存器设置成可执行文件的入口地址,启动运行
首先创建虚拟地址空间:创建一个虚拟地址空间并不是创建空间而是创建映射函数所需要的数据结构。
读取可执行文件头,并且建立虚拟空间与可执行文件的映射关系:当程序发生页错误的时候,操作系统将从物理内存中分配一个物理页,然后将该”缺页”从磁盘中读取到内存中,再设置缺页的虚拟页和物理页的映射关系。当操作系统捕获到缺页错误时,它应知道程序当前所需要的页在可执行文件中的哪一个位置。这就是虚拟空间与可执行文件之间的映射关系。Linux中将进程虚拟空间中的一个段叫做虚拟内存区域,在Windows中将这个叫做”虚拟段”。
将CPU指令寄存器设置成可执行文件入口,启动运行:操作系统通过设置CPU的指令寄存器将控制权交给进程,由此进程开始执行。
6.3.2 页错误
当CPU开始打算执行一个地址指令时,发现页面是空页面,于是它认为这是一个页错误。CPU将控制权交给操作系统,操作系统将查询第二步建立的数据结构,然后找到VMA,计算出相应的页面在可执行文件中的偏移,然后在物理内存中分配一个物理页面,将进程中该虚拟页与分配的物理页之间建立映射关系,然后把控制权交回给进程,进程从刚才错误页位置重新开始执行。
6.4 进程虚存空间分布
6.4.1 ELF文件链接视图和执行视图
前面的例子的可执行文件只有一个代码段,所有它被操作系统转载至进程地址空间之后,相对应的只有一个VMA。
当段的数量增多时,就会产生空间浪费问题。为了避免这种问题,可以把相同的段合并。
操作系统至关心段的权限(可读,可写,可执行)。
ELF文件中,段的权限基本是三种:
- 以代码段为代表的权限可读可执行的段
- 以数据段和BSS段为代码的权限为可读可写的段
- 以只读数据为代表的权限为只读的段
一个简单的方案:对于相同权限的段,把它们合并到一起当作一个段进行映射。
一个”Segment”包含一个或多个属性类似的”Section”。
从链接的角度看,ELF文件是按”Section”存储的,从装载的角度看ELF文件又可以按照”Segment”划分。
“Section”和”Segment”是从不同角度来划分同一个ELF文件的。这个在ELF种被称为视图,从”Section”的角度来看ELF文件就是链接视图,从”Segment”的角度来看就是执行视图。
ELF可执行文件中有一个专门的数据结构叫做程序头表用来保存”Segment”信息。
数据段和BSS段唯一区别就是:数据段从文件中初始化内容,而BSS段的内容全都初始化为0。
6.4.2 堆和栈
操作系统通过使用VMA来对进程的地址空间进行管理。进程在执行的时候它还需要用到栈、堆等空间。一个进程中的栈和堆分别对应一个VMA。
进程虚拟地址空间的概念:操作系统通过给进程空间划分一个个VMA来管理进程的虚拟空间;基本原则就是将相同权限属性的、有相同映像文件的映射成一个VMA;一个进程基本上可以分为几种VMA区域:
- 代码VMA,权限只读、可执行;有映像文件。
- 数据VMA,权限可读写、可执行;有映像文件。
- 堆VMA,权限可读写、可执行;无映像文件,匿名,可向上扩展。
- 栈VMA,权限可读写、不可执行;无映像文件,匿名,可向下扩展。
6.4.3 堆的最大申请数量
理论上Linum下虚拟地址空间分给进程本身的是3GB,win是2GB,但实际上,Linux分配的程序的最大内存是2.9GB,win分配的为1.5GB。
有些操作系统使用了一种叫做随机地址空间分布技术,使得进程的堆空间变小。
6.4.4 段地址对齐
可执行文件最终是要被操作系统装载运行的,这个装载的过程一般是通过虚拟内存页映射机制完成。在映射过程中,页是映射的最小单位。
6.4.5 进程栈初始化
进程刚开始启动的时候,须知道一些进程运行的环境,最基本的就是系统环境变量和进程的运行参数,很常见的一种做法是操作系统在进程启动前将这些信息提前保存到进程的虚拟空间的栈中。
6.5 Linux内核装载ELF过程简介
首先在用户层面,bash进程会调用fork()系统调用创建一个新的进程,然后新的进程调用execve()系统调用执行指定的ELF文件,原先的bash进程继续返回等待刚才启动的新进程结束,然后继续等待用户输入命令。
6.6 Windows PE的装载
RVA:它表示一个相对虚拟地址,相当于文件中的偏移量的东西。它是相对于PE文件的装载基地址的一个偏移地址。每个PE文件在装载时都会有一个装载目标地址,这个地址就是基地址。
装载一个PE可执行文件的过程:
- 先读取文件的第一个页,这个页包含了DOS头、PE文件头、段表
- 检查进程地址空间中,目标地址是否可用,如果不可用,则另外选一个转载地址
- 使用段表中提供的信息,将PE文件中所有段一一映射到地址空间中相应的位置
- 如果装载地址不是目标地址,则进行Rebasing
- 装载所有PE文件所需要的DLL文件
- 对PE文件中所有导入符号进行解析
- 根据PE头中指定的参数,建立初始化栈和堆
- 建立主线程并且启动进程
PE文件中,与装载相关的主要信息都包含在PE扩展头和段表中。
转载于:https://www.cnblogs.com/Tan-sir/p/7488796.html
程序员的自我修养六可执行文件的装载与进程相关推荐
- 腾讯朋友力荐书籍:程序员的自我修养:链接、装载与库
后台开发需要学习底层知识,只有底层知识掌握了,学一些中间件是信手捏来,中间件也是跑在底层的操作系统上.<<程序员的自我修养:链接.装载与库>>对学习底层知识非常有帮助,腾讯的朋 ...
- 好教程推荐系列:《程序员的自我修养》和《程序员修炼之道:通向务实的最高境界(第2版)》
1.<程序员的自我修养-链接.装载与库> <程序员的自我修养:链接.装载与库>网易云风力荐:莫到用时再读书!主要介绍系统软件的运行机制和原理,涉及在Windows和Linux两 ...
- 【《程序员的自我修养---链接装载于库》读书笔记】可执行文件的装载与进程
系列文章目录 [<程序员的自我修养-链接装载于库>读书笔记]初探ELF [<程序员的自我修养-链接装载于库>读书笔记]windows PE/COFF [<程序员的自我修养 ...
- 《程序员的自我修养》导读
大家好,我是Cone,一名毕业于双非本科的抖音全栈程序猿. 今天来和大家分享<程序员的自我修养----链接.装载与库>这本书的全书导读经验,它在去年我拿下微信.抖音.百度等大厂sp及以上o ...
- 《程序员的自我修养》读书笔记
本读书笔记从第六章开始,之前的内容会陆续补上.内容上主要对认为重要的内容进行记录,<程序员的自我修养>确实是一本好书,欢迎大家一起对书中的内容进行讨论.第六章的6.1-6.3节的内容总结如 ...
- 《程序员的自我修养》
<程序员的自我修养>这本书偏底层,来来回回读了有三四遍了,每一次都有新的收获,不过很快又会忘记,所以写下了这本书从17年12月份至今的全书的笔记,留作以后自己复习. 第二章:编译和链接 源 ...
- 【读书笔记】程序员的自我修养总结(七)
[读书笔记]程序员的自我修养总结(七) 标签: [编程开发] 声明:引用请注明出处http://blog.csdn.net/lg1259156776/ 说明:这是程序员的自我修养一书的读书总结,随着阅 ...
- 程序员的自我修养(序)-量子
本人为什么会最终想到要写这一<程序员的自我修养>以及<我的IT生活>,首先周星驰是本人很喜欢的一位演员,<喜剧之王>里的那本<演员的自我修养>,他用他特 ...
- 程序员的自我修养阅读笔记
编译和链接 将编译和链接合并到一起的过程称为构建(Build). 从源文件生成最终可执行目标文件共有4个步骤: 预处理(Prepressing) 编译(Compilation) 汇编(Assembly ...
最新文章
- 动态修改迅雷的下载地址
- det--求矩阵的行列式
- 登录验证---过滤器(Fileter)
- 用putty中的pscp命令拷贝文件
- 浅谈Redis五种数据结构的底层原理
- 【Linux系统编程学习】 动态库的制作与使用
- 写让别人能读懂的代码
- java webview 对象_Android – 将JSON对象从webview javascript传递给java
- java编写猫抓老鼠程序_Java抓鱼程序
- ❤️ Spring相关配置
- 除法运算、商、余数与取模
- 如何修复“ DNS_PROBE_FINISHED_NXDOMAIN”错误
- css 标签上 title 和 alt 的区别
- Origin 2017安装教程(附有下载链接)
- ***能篡改WiFi密码,源于存在漏洞
- 旷视科技(Face++)面经
- 小米无线AR眼镜探索版细节汇总
- 2022年G2电站锅炉司炉操作证考试题库及答案
- IntelliJ IDEA快速入门 | 第三十篇:如何来自定义模板呢?
- Scala 令人着迷的类设计
热门文章
- 关于批量启动微服务的jar包_分布式任务抢占及系统监控服务 Radish
- sql2016是否支持linux,微软 SQL Server 支持 Linux 了,2017年 中将正式推出
- 第五章 PX4-Pixhawk-GPS解析
- float与double类型区别比较
- 机器学习入门:机器学习概论
- 2019牛客暑期多校训练营(第六场)C - Palindrome Mouse (回文树dfs)
- MySQL中变量的定义和变量的赋值使用(转)
- windows的常用快捷键(实用篇)
- ios::app与ios::ate打开方式有什么不同??
- linux 下 LibreOffice Writer 使用说明