zoukankan      html  css  js  c++  java
  • Win32基础知识3 Win32汇编语言004

    Win32基础知识3

     

    让编程改变世界

    Change the world by program


     

    Windows的内存管理机制

     

    在这一节中,我们需要通过学习解决两大疑问:

    Win32汇编中,每个程序都可以用4GB的内存吗? Win32汇编源代码中为什么看不到CS, DS, ES 和 SS 等段寄存器的使用?  

    DOS操作系统的内存安排

    Win32编程相对于 DOS编程最大的区别之一就是内存的使用问题。 先来回顾一下DOS操作系统的内存使用,DOS操作系统运行于实模式中,内存安排如图: [caption id="attachment_529" align="aligncenter" width="276"] DOS 操作系统的内存安排[/caption]   我们看到,由于8086处理器的寻址范围只有可怜的1 MB 大小,当时系统硬件使用的存储器地址被安排在高端。 地址是从A0000h(即640 KB)开始的384 KB中,其中有用于显示的视频缓冲区和BIOS的地址空间。   而在内存低端,安排了中断向量表和BIOS数据区。 剩下从500h开始到A0000h总共不到640KB的内存是操作系统和应用程序所能够使用的。 应用程序不可能使用这640 KB以外的内存。 这就是著名的“640KB限制”。   而即使在这640KB中,DOS操作系统又占领了低端的一部分内存,最后剩下600KB左右的内存才是应用程序真正可以用的。 如果系统中有内存驻留程序存在,那么应用程序还要和这些TSR程序共同分享这段内存空间。 注释:TSR 即(Terminate and Stay Resident)原意是停止并驻留,指的是内存驻留程序。  

    80386的内存寻址机制

      Windows的内存管理和DOS的内存管理有很大的不同,在了解Windows的内存管理模式之前,需要对80386保护模式下内存分页机制有所了解。 为了做个对比,先来看实模式下的内存寻址方式:在实模式下,一个完整的地址由段地址和偏移地址两部分组成。 处理器换算时先将段地址乘以10h,得到段在物理内存中的起始地址,然后加上16位的偏移地址得到实际的物理地址。  

    现在我们谈回到80386处理器的工作模式:

    当80386处理器工作在保护模式和虚拟8086模式的时候,可以使用全部32根地址线访问4 GB大的内存。段地址加偏移地址的计算方法显然无法覆盖这么大的范围。 但计算一下就可以发现,实际上和8086同样的限制已经不复存在,因为80386所有的通用寄存器都是32位的,2^32 == 4G,所以用任何一个通用寄存器来间接寻址,不必分段就已经可以访问到所有的内存地址。    

    这是不是说,在保护模式下,段寄存器就不再有用了呢?

    答案是否定的!实际上段寄存器更有用了,虽然在寻址上不再有分段的限制问题,但在保护模式下,一个地址空间是否可以被写入,可以被多少优先级的代码写入,是不是允许执行等涉及保护的问题就出来了。 要解决这些问题,必须对一个地址空间定义一些安全上的属性。段寄存器这时就派上了用途,不妨将这些属性存放在段寄存器中! 但是问题来了,涉及属性和保护模式下段的其他参数,要表示的信息太多了,要用64位长的数据才能表示。我们把这64位的属性数据叫做段描述符(Segment Descriptor)。  

    80386的段寄存器仍然是16位的,无法放下保护模式下64位的段描述符。如何解决这个新的问题呢?

    解决办法是把所有段的段描述符顺序放在内存中的指定位置,组成一个段描述符表(Descriptor Table) 而段寄存器中的16位用来做索引信息,指定这个段的属性用段描述符表中的第几个描述符来表示。 这时,段寄存器中的信息不再是段地址了,而是段选择器(Segment Selector)。可以通过它在段描述符表中“选择”一个项目以得到段的全部信息。  

    既然这样,段描述符表放在哪里呢?

    80386中引入了两个新的寄存器来管理段描述符表。一个是48位的全局描述符表寄存器GDTR,一个是16位的局部描述符表寄存器LDTR。  

    那么,为什么有两个描述符表寄存器呢?

    GDTR指向的描述符表为全局描述符表GDT(Global Descriptor Table)。 它包含系统中所有任务都可用的段描述符,通常包含描述操作系统所使用的代码段、数据段和堆栈段的描述符及各任务的LDT段等;全局描述符表只有一个。   LDTR则指向局部描述符表LDT(Local Descriptor Table)。 80386处理器设计成每个任务都有一个独立的LDT。 它包含有每个任务私有的代码段、数据段和堆栈段的描述符,也包含该任务所使用的一些门描述符,如任务门和调用门描述符等。 不同任务的局部描述符表分别组成不同的内存段,描述这些内存段的描述符当做系统描述符放在全局描述符表中。   和GDTR直接指向内存地址不同,LDTR和CS,DS等段选择器一样只存放索引值,指向局部描述符表内存段对应的描述符在全局描述符表中的位置。 随着任务的切换,只要改变LDTR的值,系统当前的局部描述符表LDT也随之切换,这样便于各任务之间数据的隔离。但GDT并不随着任务的切换而切换。   看到这里,读者可能会提出一个问题,既然有全局描述符表和局部描述符表两个表,那么段选择器中的索引值对应哪个表中的描述符呢? 实际上,16位的段选择器中只有高13位表示索引值。 剩下的3个数据位中,第0,1位表示程序的当前优先级RPL;第2位TI位用来表示在段描述符的位置;TI=0表示在GDT中,TI=1表示在LDT中。  

    图说寻址路线:

    在保护模式下,同样以xxxx:yyyyyyyy格式表示一个虚拟地址。 注意,xxxx(16位,相当于8086时代的段地址) 保存在段寄存器,yyyyyyyy(32位,相当于8086时代的偏移地址)保存在通用寄存器。 下边,小甲鱼从图片来给大家做演示! [caption id="attachment_530" align="aligncenter" width="300"] 图说寻址路线[/caption] [buy] 获得所有教学视频、课件、源代码等资源打包 [/buy] [Downlink href='http://urlxf.qq.com/?fiEbymI']视频下载[/Downlink]
  • 相关阅读:
    IDEA常用快捷指令整理
    Python dict 字典
    内联函数
    【MFC】编辑框 CEdit Ctrl控件自动换行设置
    mysql 多sql文件恢复方案
    Linux: 用64位的系统,能编译32位的程序吗?
    C++ 遍历数组
    工业现场传感器传感器为什么采用电流形式输出?
    【转】电磁阀、电磁铁的工作原理说明
    PCB板强弱电隔离距离不够导致损坏和问题检查记录
  • 原文地址:https://www.cnblogs.com/LoveFishC/p/3846115.html
Copyright © 2011-2022 走看看