Windows内存之程序装载


装载过程

程序执行时所需要的指令和数据必须在内存中(指的是物理内存)才能正常运行。程序装载指的就是把这些东西加载到内存中。最简单的装载方式就是把所需的指令和数据全部装入内存,称为静态装载。但是这样会比较消耗内存。动态装载的思想是程序用到哪个模块就装入内存。下面介绍动态加载的过程:

1.创建一个独立的虚拟内存空间

创建的是映射表的数据结构,使用二级表的话,分配一个4K的页目录就可以了,后面的映射关系等到发生页错误的时候再进行设置。

2.读取可执行文件头,建立虚拟空间和可执行文件之间的映射

第一步的映射表是虚拟空间到物理空间的映射关系。这一步需要建立的是可执行文件到虚拟空间的映射关系——是通过可执行文件头部的信息建立,保存在操作系统内部的一个数据结构。

当操作系统创建进程以后,会在进程相应的数据结构中设置一个段在虚拟空间中的位置和在可执行文件中的偏移。通过这种映射关系,就可以定位错误页在可执行文件中的位置。

3.将cpu的指令寄存器设置成可执行文件的入口地址,启动运行。

操作系统设置cpu的指令寄存器,设置为可执行文件的入口地址(设置的是虚拟空间地址可执行文件头部保存着入口地址信息),将控制权转交给进程,由此进程开始执行。(操作系统其实执行了一系列操作:内核堆栈和进程堆栈的切换,cpu运行权限的切换)

4.程序开始执行,发生页错误。

当cpu执行入口地址(比如是0x08048000)的指令的时候,发现这是个空页面(加载一页,0x08048000-0x08049000)(因为此时,还有没有把可执行文件的真正指令和数据装入到内存中),发生页错误,操作系统接手处理。在第2步中,操作系统建立了虚拟空间和可执行文件之间的映射关系,所以通过查询第2步中建立的数据结构,先得到这个页面在可执行文件中的偏移,然后再物理内存中分配一个页面进行加载,并且对该虚拟页和物理页建立映射关系(第1步中的页表),然后再交由进程,重新从发生页错误的地方进行执行,现在执行就没有页错误了。

 

5.随着程序的执行,不停的发生页错误,当物理内存不够用的时候

涉及到操作系统的虚拟内存管理,把硬盘空间中的一部分当成RAM使用,根据一些规则把已经分配出去的物理内存暂时回收,置换到硬盘空间中。


可执行文件PE

一个可执行文件 (PE 文件 全称是Portable Executable,意为可移植的可执行的文件,常见的EXE、DLL、OCX、SYS、COM,可能是间接被执行,如DLL) 就是一些编译链接好的数据和指令的集合。(比如一个编译链接好的exe是4MB,那么这个4MB应该就会被分成了几个页,都在磁盘上。)

在PE文件中,链接器在生成可执行文件时,会将段尽可能的合并,最后只有代码段、数据段、只读数据段、BSS等为数不多的几个段。

在PE文件中,所有段的起始地址都是页的整数倍,如果段的长度不是页的整数倍,在映射的时候向上补齐到页的整数倍,所以可以简单的认为,在32位PE文件中,段的起始地址和长度都是4096字节的整数倍。

每个PE文件在装载的时候都会有一个装载目标地址TargetAddress,也就是所谓的基地址,BaseAddress。PE文件被设计成可以装载到任何地址,所以这个基地址并不固定,每次装载都有可能不同。RVA RelativeVirtualAddress,相对虚拟地址,表示文件中的偏移量,这个值肯定是不会变化的。

PE文件的第一个页包含DOS头(用来兼容DOS操作系统),PE文件头(包含各种说明数据:文件入口,堆栈位置、重定位表),段表信息(各个段的描述,后续用于装载各个段)。

硬盘中(装载前)

虚拟内存空间(装载后)

称为

可执行文件

映像文件

各个段

连续存放

按页对齐


参考:

https://blog.csdn.net/evileagle/article/details/11693499

《程序员的自我修养》

《window内核原理与实验》看不下去啊

发布了104 篇原创文章 · 获赞 44 · 访问量 12万+

猜你喜欢

转载自blog.csdn.net/u012138730/article/details/90377865
今日推荐