存储器的保护

存储器的保护,第1张

        利用存储器的保护功能,可实现有些有价值的功能,比如虚拟内存管理。当处理器访问一个实际上不存在的段时,会引发异常中断。 *** 作系统可利用这一点,通过接管异常处理过程,并用硬盘来进行段的换入和换出。实现较小内存空间运行尽可能大,尽可能多的程序。本章目标:

        1.通过实例认识处理器如何进行存储器保护

        2.了解别名段意义和作用

        3.以字符串排序过程为例子,演示保护模式下内存数据访问,体验它们与在实模式下访问数据段不同。

12.1.代码清单12-1 12.2.进入32位保护模式 12.2.1.话说mov ds, ax和mov ds, eax

        我们知道,段寄存器【选择器】的值只能用内存单元或通用寄存器来传送,一般指令格式为:

mov sreg, r/m16

        这里有一个常见例子:

mov ds, ax

        在16位模式和32位模式下,一些老式的编译器会生成不同的机器代码。

[bits 16]
mov ds, ax ; 8E D8

[bits 32]
mov ds, ax ; 66 8E D8

        由于在16位模式下,默认的 *** 作数大小是字【2字节】,故生成8E D8。在32位模式下,默认的 *** 作数大小是双字【4字节】。由于指令中的源 *** 作数是16位的AX,故编译后的机器码前面应添加前缀0x66以反转默认的 *** 作数大小,即66 8E D8。

        它们在16位模式和32位模式下的机器指令被设计为相同,即都是8E D8,不需要指令前缀。

        很多编译器认为,32位模式下,源 *** 作数是16位的寄存器AX时,应添加指令前缀。

mov ds, eax

        对NASM编译器,不管处理器模式如何,不管指令形式如何,以下代码编译后的结果都一样。

[bits 16]
mov ds, ax ; 8E D8
mov ds, eax; 8E D8

[bits 32]
mov ds, ax ; 8E D8
mov ds, eax; 8E D8

12.2.2.创建GDT并安装段描述符

        在32位处理器上,即使在实模式下,也可用32位寄存器。

        32位处理器可执行以下除法 *** 作:

div r/m32

         其中,64位的被除数在EDX:EAX中,32位被除数可以在32位通用寄存器中,也可在32位内存单元中。指令执行后,EAX中的商是段地址,仅低16位有效;EDX中的余数是段内偏移地址,仅低16位有效。

        对段的粒度为4KB的段,描述符中的界限值加1,就是该段有多少个4KB。因此,实际使用的段界限为:

(描述符中的段界限值+1) * 0x1000 - 1

        对向上扩展的段,段界限数值上等于段的长度减去1。

        32位代码,16位代码。

        如果需访问代码段内的数据,只能重新为该段安装一个新的描述符,并将其定义为可读可写的数据段。需写时,通过新的描述符来进行。

        当两个以上的描述符都描述和指向同一个段时,把另外的描述符称为别名。如果两个程序想共享同一个内存区域,可分别为每个程序都创建一个描述符,且它们都指向同一个内存段,这也是别名应用的例子。

        GDT界限值为总尺寸-1。

        需要对代码段做修改时。只能重新针对此段定义一个新的有写权限描述符,通过此描述符来写。别名技术除了用于读写代码段。如果两个程序共享一个内存区域,可分别为每个程序都创建一个描述符,且都指向同一个内存段,这也是别名应用例子。

 12.3.修改段寄存器时的保护

        进行段描述符设置时,处理器会进行范围合法性检查,类别检查【代码段不可加载到除CS外的其他段寄存器中】。

        描述符的类别是否和段寄存器的用途匹配。

        还要检查描述符的P位。如P=0,表面虽然描述符已被定义,但该段实际上并不存在物理内存中。此时,处理器中止处理,引发异常中断11。一般,应定义一个中断处理程序,把该描述符所对应的段从硬盘等外部存储器调入内存,然后置P位。中断返回时,再次尝试刚才 *** 作。

        如P=1,则处理器将描述符加载到段寄存器的描述符高速缓存器,同时置A位【仅限当前讨论的存储器的段描述符】。

        一旦 上述规则验证通过,处理器就将选择子加载到段寄存器的选择器。只有可写入的数据段才能加载到SS,CS只允许加载代码段描述符。对DS,ES,FS和GS,可向其加载数值为0的选择子。

12.4.地址变换时的保护 12.4.1.代码段执行时的保护

0 <= (EIP+指令长度-1) <= 实际使用的段界限

实际使用段界限计算:

描述符的G=0,实际使用的段界限就是描述符中记载的段界限

描述符的G=1,实际使用的段界限=描述符中的段界限值*0x1000+0xFFF

        代码段不可写入。只有在代码段可读下,才能由指令读取其内容。

12.4.2.栈 *** 作时的保护

        现在只讨论向下扩展的段。后续会遇到向上扩展的段。

实际使用段界限计算:

描述符的G=0,实际使用的段界限就是描述符中记载的段界限

描述符的G=1,实际使用的段界限=描述符中的段界限值*0x1000+0xFFF

        实际使用的段界限就是段内不允许访问的最低端偏移地址。最高端地址,没有限制。最大可以是0xFFFFFFFF。

实际使用的段界限+1 <= (ESP的内容 - 操作数的长度) <= 0xFFFFFFFF

12.4.3.数据访问时的保护

         这里的数据段,特指向上扩展的数据段,有别于栈和向下扩展的数据段。

0 <= (EA+操作数大小-1) <= 实际使用的段界限。EA是内存单元有效地址,可以通过立即数,寄存器,或符合方式给出。

12.5.使用别名访问代码段对字符排序 

        32位模式下,如指令的 *** 作数是16位的,要加前缀0x66。相似地,在32位模式下,如要在指令中使用16位的有效地址,需为该指令添加前缀0x67。因此,当指令:

mov eax, [bx]

        用bits 32编译后,有指令前缀0x67

        xchg是交换指令,用于交换两个 *** 作数的内容,源 *** 作数和目的 *** 作数都可是8/16/32位的寄存器,或指向8/16/32位实际 *** 作数的内存单元地址,但不允许两者同时为内存地址。格式为:

xchg r/m8, r8
xchg r/m16, r16
xchg r/m32,r32
xchg r8, m8
xchg r16, m16
xchg r32, m32

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/1352539.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-14
下一篇 2022-06-14

发表评论

登录后才能评论

评论列表(0条)

保存