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

可执行文件的装载

http://blog.csdn.net/sergeycao/article/details/8228613

可执行文件只有被装载进内存以后才能被CPU执行。

接下来我们看一下可执行文件装载的本质到底是什么。

 

1. 首先来了解一下进程虚拟地址空间。

程序和进程的区别:程序是一个静态的概念,他就是一些预先编译好的指令和数据的集合;而进程则是一个动态的概念,它是程序运行时的一个过程,很多时候吧动态库叫做运行时(Runtime)也是有一定的含义的。

每个程序被运行起来以后它将拥有自己的独立的虚拟地址空间 (Virtual Address Space),这个虚拟地址空间的大小由计算机的硬件平台决定,具体来说就是由CPU的位数来决定的。如:32位:0~232 - 1,即我们所说的4GB的虚拟空间大小;64位:0~264 - 1,即17179869184GB。以32位的CPU为例,4GB的虚拟地址空间,那么我们的程序是否可以任意使用呢?很遗憾,不行!

因为程序运行的时候处于操作系统的监管下,操作系统为了达到监控程序运行等一系列目的,进程的虚拟空间都在操作系统的掌握之中。进程只能使用那些操作系统分配给进程的地址,如果访问未经允许的空间,操作系统就会捕获这些访问,将进程的这些访问当做非法操作,强制进程结束。

那么这4GB的进程虚拟地址空间到底是怎样的分配状态呢?以Linux OS为例,它将整个4GB化为两个部分:

a. 从0XC0000000到0XFFFFFFFF,共1GB,被OS本身用去了

b. 从0X00000000到0XBFFFFFFF,共3GB,留给进程使用的。

即使是上面的“3GB”,也只是“原则上”可以给进程使用的,事实上进程并不能完全使用这3GB的虚拟空间,其中一部分是预留给其他用途的。(稍后会提到)

32位的CPU下,程序使用的空间能不能超过4GB呢?这个问题应该从两个角度来看,首先,问题里面的“空间”如果指的是虚拟地址空间,那么答案是“否”,因为32位的CPU只能使用32位的指针,它最大的寻址范围是0到4GB。如果“空间”指的是计算机的内存空间,那么答案是“是”。Intel自从1995年代Pentium Pro CPU开始采用了36位的物理地址,也就是可以访问高达64GB的物理内存。扩展至36位地址线之后,Intel修改了页映射的方式,使得新的映射方式可以访问到更多的物理内存。扩展的物理地址空间对于普通应用程序来说是感觉不到它的存在的,因为这主要是OS的事,在应用程序里,只有32位的虚拟地址空间。那么应用程序如何使用这些大于常规的内存空间呢?一个很常见的方法就是OS提供一个窗口映射的方法,吧这些额外的内存映射到进程地址空间来。像Linux OS采用mmap()系统调用来实现。

 

2. 装载的方式

程序执行时所需要的指令和数据必须在内存中才能够正常运行。当然,最简单的办法就是将程序运行所需要的全部资源全部装入内存。但是这样会造成内存的浪费。研究发现程序运行是有局部性原理的,所以比较好的解决方法就是将程序最常用的部分驻留在内存中,而将一些不太常用的数据存放在磁盘里,这就是动态装入 的基本原理。

覆盖装入 (Overlay)和页映射 (Paging)是两种典型的动态装载方法,它们都利用了程序的局部性原理。动态装入的基本思想就是用到哪个模块就将哪个模块装入内存,如果用不到则暂时不装入,存放到磁盘。

a. 覆盖装入(Overlay)

利用时间换取空间,此处不多涉及。

b. 页映射(Paging)

页映射是将内存和所有磁盘中的数据和指令按照“页”为单位划分成若干个页,以后所有的装载和操作的单位就是页。利用换入换出机制(如FIFO,LUR等)即可完成。

 

3.  从OS角度看可执行文件的装载

a. 进程的建立

从OS的角度来看,一个进程最关键的特征是它拥有独立的虚拟地址空间,这使得它有别于其他进程。很多时候一个程序被执行的同时都伴随着一个新的进程的创建,那么我们就来看看这种最通常的情形:创建一个进程,然后装载相应的可执行文件并且执行。在有虚存储的情况下,上述过程最开始需要做三件事情:

  • 创建一个独立的虚拟地址空间
  • 读取可执行文件头,并且建立虚拟空间与可执行文件的映射关系
  • 将CPU的指令寄存器设置成可执行文件的入口地址,启动运行

首先是创建虚拟地址空间。我们知道一个虚拟空间由一组页映射函数将虚拟空间的各个页映射至相应的物理空间,那么创建一个虚拟空间实际上并不是创建空间而是创建映射函数所需要的相应的数据结构。

读取可执行文件头,并且建立虚拟空间与可执行文件的映射关系。上面一步的页映射关系是虚拟空间到物理内存的映射关系,这一步所做的是虚拟空间与可执行文件的映射关系。

将CPU的指令寄存器设置成可执行文件的入口地址,启动运行。这步是最简单的一步,OS通过设置CPU的指令寄存器将控制权转交给进程,由此进程开始执行。这一步看似简单,实际上OS层面上比较复杂,它设计内核堆栈和用户堆栈的切换,CPU运行权限的切换。不过从进程的角度看这一步可简单的认为OS执行了一条跳转指令,直接跳转到可执行文件的入口地址。

从OS的角度看,经过上面的步骤,其实可执行文件的真正指令和数据都没有被装入内存中。OS只是通过可执行文件都不的信息建立起可执行文件和进程虚存之间的映射关系而已。

相关文章:

  • 自己定义控件 播放GIF动画
  • WEB服务器-Nginx之虚拟主机、日志、认证及优化
  • day06 tar命令使用,vim简单操作以及linux开机过程
  • 面面观 | 使用dokcer 构建 mariadb 数据库
  • 3 个在 Linux 中永久并安全删除文件和目录的方法
  • 再会Java
  • 自动化运维工具SaltStack详细部署
  • PHP MySQL
  • 算法之选择排序算法
  • 我会采更多的雏菊
  • c语言中字符串函数的使用
  • 利用jquery编写加法运算验证码
  • 更改计算机名称,影响TFS之前映射的工作区 使用。
  • mysql/Java服务端对emoji的支持
  • 教你如何安装 Android L
  • CSS居中完全指南——构建CSS居中决策树
  • Debian下无root权限使用Python访问Oracle
  • ECS应用管理最佳实践
  • Java方法详解
  • js ES6 求数组的交集,并集,还有差集
  • opencv python Meanshift 和 Camshift
  • python 装饰器(一)
  • quasar-framework cnodejs社区
  • Solarized Scheme
  • use Google search engine
  • 从setTimeout-setInterval看JS线程
  • 道格拉斯-普克 抽稀算法 附javascript实现
  • 可能是历史上最全的CC0版权可以免费商用的图片网站
  • 浅谈JavaScript的面向对象和它的封装、继承、多态
  • 如何进阶一名有竞争力的程序员?
  • 用Canvas画一棵二叉树
  • 我们雇佣了一只大猴子...
  • ​linux启动进程的方式
  • # 透过事物看本质的能力怎么培养?
  • #Z2294. 打印树的直径
  • $NOIp2018$劝退记
  • (1)安装hadoop之虚拟机准备(配置IP与主机名)
  • (二) Windows 下 Sublime Text 3 安装离线插件 Anaconda
  • (附源码)springboot 智能停车场系统 毕业设计065415
  • (汇总)os模块以及shutil模块对文件的操作
  • (四) 虚拟摄像头vivi体验
  • (五)大数据实战——使用模板虚拟机实现hadoop集群虚拟机克隆及网络相关配置
  • (一)使用Mybatis实现在student数据库中插入一个学生信息
  • (转)memcache、redis缓存
  • (自适应手机端)响应式新闻博客知识类pbootcms网站模板 自媒体运营博客网站源码下载
  • .NET Framework 3.5中序列化成JSON数据及JSON数据的反序列化,以及jQuery的调用JSON
  • .Net Remoting(分离服务程序实现) - Part.3
  • .net 获取url的方法
  • .NET/C# 使用 SpanT 为字符串处理提升性能
  • .net6使用Sejil可视化日志
  • .Net调用Java编写的WebServices返回值为Null的解决方法(SoapUI工具测试有返回值)
  • [ 常用工具篇 ] POC-bomber 漏洞检测工具安装及使用详解
  • []利用定点式具实现:文件读取,完成不同进制之间的
  • [Arduino学习] ESP8266读取DHT11数字温湿度传感器数据
  • [C#]DataTable常用操作总结【转】