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

进程地址空间二讲:程序是如何加载的?动态库又是如何加载的?

文章目录

    • 动态库加载原理
      • 再谈进程地址空间
        • 程序没有加载前的地址
          • ELF文件
        • 程序加载后的地址
        • 动态库的地址
          • fPIC的原理


动态库加载原理

动态库在进程运行的时候是要被加载的(静态库不用)
动态库可以被多个进程加载使用,因此动态库又被称为共享库。

所以,动态库在系统中被加载后,会被所有进程共享。
怎么做到的呢?

实际上,动态库加载到系统中后,一般会被保存在所有进程的进程地址空间的共享区中。

看图:
在这里插入图片描述
得出结论:动态库在虚拟地址的地址在对应的物理内存是通过页表建立映射的,也就是说,我们执行的任何代码都是在进程地址空间中执行的

事实上,在系统·运行中,一定会存在多个动态库,那么OS就需要将他们管理起来:先描述,再组织
如此,系统对所有库的加载情况,是非常清楚的。

一个小细节:对于共享库中的全局变量,如果进程对该变量进行修改,会影响其他进程的该变量吗??

当然不会,共享库的数据和我们父子进程的数据是一样的,任意一个进程对其进行修改,会发生写时拷贝

再谈进程地址空间

我们换个角度再来谈谈,什么是虚拟地址?什么是物理地址?

程序没有加载前的地址

程序在编译后,内部有地址的概念吗?

其实是有的


ELF文件

要理解编译链接的细节,我们不得不了解⼀下ELF⽂件。
有以下四种⽂件都是ELF⽂件:

  • 可重定位⽂件(Relocatable File) :即xxx.o目标文件。
  • 可执行文件(Executable File) :即可执行程序。
  • 共享⽬标⽂件(Shared Object File) :即xxx.so动态库⽂件。
  • 内核转储(core dumps) :存放当前进程的执⾏上下⽂,⽤于dump信号触发。

⼀个ELF文件由以下四部分组成:

  • ELF头(ELF header) :描述⽂件的主要特性。其位于⽂件的开始位置,它的主要⽬的是定位⽂件的其他部分。
  • 程序头表(Program header table) :列举了所有有效的段(segments)和他们的属性。表⾥记着每个段的开始的位置和位移(offset)、⻓度,毕竟这些段,都是紧密的放在⼆进制⽂件中,需要段表的描述信息,才能把他们每个段分割开。
  • 节头表(Section header table) :包含对节(sections)的描述。
  • 节(Section ):ELF⽂件中的基本组成单位,包含了特定类型的数据。ELF⽂件的各种信息和数据都存储在不同的节中,如代码节存储了可执⾏代码,数据节存储了全局变量和静态数据等。
    最常⻅的节:
    • 代码节(.text):⽤于保存机器指令,是程序的主要执⾏部分。
    • 数据节(.data):保存已初始化的全局变量和局部静态变量。
      在这里插入图片描述

程序编译后就是一个ELF文件了(XXX.o),ELF程序在没有被加载到内存的时候,本来就有地址,当代计算机⼯作的时候,都采⽤"平坦模式"进⾏⼯作。所以也要求ELF对⾃⼰的代码和数据进⾏统⼀编址。

“平坦模式”
由低到高顺序编址

以下是一个程序的反汇编:
在这里插入图片描述

左侧的就是虚拟地址,右侧对应的是指令。

CPU中有着对应的指令集,我们复杂的程序操作,对于CPU来说就是大量的一个一个简单的指令,然后快速的执行它们。

结论:可执行程序在加载到内存之前,它的代码、数据、指令、函数调用,就已经按我们的ELF的格式(地址+二进制指令集)编好了,当调用函数需要跳转时,会提供跳转地址,因为每一条代码都有自己的地址,这个地址就是虚拟地址,又称逻辑地址。

程序加载后的地址

当我们把可执行程序加载到内存中后,我们可执行程序的每条指令都天然的有了各自的物理地址。
所以,可执行程序加载到内存后,里面的指令将会有两套地址:虚拟地址和物理地址,并且它们两是一一对应的!
在这里插入图片描述

可执行程序的第一条指令是如何执行的呢?

我们知道,ELF文件格式是有表头的,在可执行程序中表头是entry:入口地址,这个入口地址是什么地址?毫无疑问,是虚拟地址。
起初,可执行程序是没有加载到内存的,我们进程通过cwd和exe找到自己的可执行程序,然后将可执行程序的entry地址喂给CPU的寄存器EIP(又称pc指针),然后系统会从页表通过entry的虚拟地址试图去获取其物理地址,但此时可执行程序并没有加载到内存,所有entry没有物理地址,发生缺页中断,此时系统就会立马将可执行程序加载到内存,并将其指令一一对应的物理地址和虚拟地址去初始化页表,建立好映射关系。

所以,CPU内部读取到的指令,内部可能是数据,也可能是地址(都是是虚拟地址)。

一图胜千言:
在这里插入图片描述

动态库的地址

动态库的地址其实还是别具一格的,它采用的并非常规地址(绝对地址,以0地址为参照),而是采用逻辑地址(相对地址,以库头的地址为参照)

注意:库头的地址是绝对地址。

为什么要这样设计呢??

我们知道,动态库一般是加载到共享区的,但是具体映射到哪呢?每次加载都是固定位置吗?这是不可能的!

可执行程序编译后,其中调用库函数的call指令对应的共享库中的库函数地址却是固定不变的,也就是说,如果采用绝对地址,动态库每次加载到固定位置是不可避免的。

解决方案:
但是动态库内部采用相对地址完美解决了这个问题:我们只需要知道库头的地址(随便库头存在哪个位置),我们调用库时,只需根据库头地址定位库头,然后根据相对地址这个偏移量找到目标位置即可。

所以,动态库需要让自己内部函数不要采用绝对编址,只表示每个函数在库中的偏移量即可。

fPIC的原理

以上这就是动态库链接时fPIC选项的内部原理

现在我们就知道“fPIC:产生位置无关码”是什么意思了,就是自己用偏移量对库中函数进行编址。

至于静态库:它无需加载,更无需产生位置无关码了。


http://www.dtcms.com/a/499956.html

相关文章:

  • Go语言数据验证库详解:asaskevich/govalidator入门与实践
  • 营销型网站建设电话江苏省住房和建设厅网站
  • 有关做能源的网站泰宁县建设局网站
  • 英文网站建设cmswordpress 外部链接跳转
  • USB --SETUP --STATUS阶段
  • 盲盒APP源码开发实战:从0到1构建高可用系统
  • JS | 改变 this 指向 | this 指向 null 为什么不影响原型链?
  • 操作系统概述
  • 【计算机网络】初识HTTP(超文本传输协议)
  • 软件下载网站 知乎宁波seo网站建设费用
  • AI编程实战:用 TRAE 开发一个写作助手
  • 方法论:从社会契约到公司流程制度
  • 高效率小尺寸全集成同步降压电源模块替代MPM3630/MPM3620/MPM3610/MPM3606
  • 帮别人做网站赚钱阿凡达网站建设
  • 广告营销的好处如何做网站优化关键词优化
  • 长春网站制作长春万网wordpress论坛模板下载
  • 徐州模板开发建站移动端设计规范
  • 网站建设拍金手指排名贰贰女生大专学什么专业好
  • 外贸门户网站东莞东城万达
  • 柬埔寨网站建设运营维护金华东阳网站建设
  • 盐城网站开发怎么样大连工业大学研究生院官网
  • STM32G474单片机开发入门(十五)CAN通信功能详解及实战
  • 金仓多模数据库平替 MongoDB:电子证照国产化的技术实操与价值突破
  • Unity:UGUI笔记(二)——UI事件监听接口
  • CSRF 漏洞全解析:从原理到实战
  • 建设项目备案网站管理系统一般网站建设流程有哪些步骤
  • 深圳AI搜索优化:助力企业精准获客新趋势
  • 免费搭建个人网站河北省建设厅网站老版
  • 菏泽市建设职工培训中心网站重庆seo结算
  • dedecms 网站模板网络营销推广技术