• 存储器的保护


    修改段寄存器时的保护

      GDT的基地址和界限,都在寄存器 GDTR 中。描述符在内存中的地址,是用索引号乘以 8,再和描述符表的线性基地址相加得到的,而这个地址必须在描述符表的地址范围内。换句话说,索引号乘以 8 得到的数值,必须位于描述符表的边界范围之内。换句话说,处理器从 GDT 中取某个描述符时,就要求描述符的 8 个字节都在 GDT 边界之内,也就是索引号×8+7 小于等于边界。
    在这里插入图片描述
      除了按进行段的类别检查外,还要检查描述符中的 P 位。如果 P=0,表明虽然描述符已被定义,但该段实际上并不存在于物理内存中。此时,处理器中止处理,引发异常中断 11。一般来说,应当定义一个中断处理程序,把该描述符所对应的段从硬盘等外部存储器调入内存,然后置 P 位。中断返回时,处理器将再次尝试刚才的操作。
    在这里插入图片描述

    地址变换时的保护

      所谓地址变换的保护,其实就是对于偏移地址的限制,保护模式下,偏移地址不允许超过段界限。
    段界限的计算方式:

    • G=0:则实际段界限就是描述符记载的段界限

    • G=1,:实际段界限是描述符的界限值*0x1000+0xFFF

      对于代码段,因为代码段是向上拓展的,所以偏移地址只能是从0到段界限值,也就是:

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

      上面这个限制对于向上拓展的数据段也是适用的,在向上拓展的代码段中:

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

      对于向下拓展的数据段,特别是栈段,实际使用的段内偏移地址不允许访问最低的段界限,而对于最高端地址没有限制,最大可以是0xFFFFFFFF(32位保护模式下),也就是:

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

      对于向下拓展的数据段,假设段的描述符高速缓存器里的线性基地址位0x00007c00,段的界限为0Xffffe,粒度为4KB,则实际的有效物理地址范围是

    • 0x00007c00+0Xfffff000~0x00007c00+0xffffffff

    • 即0x00006c00~0x00007bff(回绕回来了)

      有时候数据在代码段上,但是代码段是不可以读的,也不可以写,如果想对代码段做一些修改(比如调试程序加入断点int3),那只能是通过另外找一个数据段指向这个段来了(一般不推荐这么做,因为一般来说数据段和代码段要分开,不然会出现不可预料的错误。)当然别名技术并非仅仅可以用于读写代码段,如果两个程序想共享一个内存区域,可以为每个程序都创建一个描述符,使他们都指向同一个内存段

    代码清单

             ;代码清单12-1
             ;文件名:c12_mbr.asm
             ;文件说明:硬盘主引导扇区代码 
    
             ;设置堆栈段和栈指针 
             mov eax,cs      
    
             mov ss,eax
    
             mov sp,0x7c00      
    
             ;计算GDT所在的逻辑段地址
    
             mov eax,[cs:pgdt+0x7c00+0x02]      ;GDT的32位线性基地址 
    
             xor edx,edx
    
             mov ebx,16
    
             div ebx                            ;分解成16位逻辑地址 
    
             mov ds,eax                         ;令DS指向该段以进行操作
    
             mov ebx,edx                        ;段内起始偏移地址 
    
             ;创建0#描述符,它是空描述符,这是处理器的要求
    
             mov dword [ebx+0x00],0x00000000
    
             mov dword [ebx+0x04],0x00000000  
    
             ;创建1#描述符,这是一个数据段,对应0~4GB的线性地址空间
    
             mov dword [ebx+0x08],0x0000ffff    ;基地址为0,段界限为0xfffff
    
             mov dword [ebx+0x0c],0x00cf9200    ;粒度为4KB,存储器段描述符 
             ;创建保护模式下初始代码段描述符
    
             mov dword [ebx+0x10],0x7c0001ff    ;基地址为0x00007c00,512字节 
             mov dword [ebx+0x14],0x00409800    ;粒度为1个字节,代码段描述符 
             ;创建以上代码段的别名描述符
    
             mov dword [ebx+0x18],0x7c0001ff    ;基地址为0x00007c00,512字节
    
             mov dword [ebx+0x1c],0x00409200    ;粒度为1个字节,数据段描述符
    
             mov dword [ebx+0x20],0x7c00fffe
    
             mov dword [ebx+0x24],0x00cf9600
    
             ;初始化描述符表寄存器GDTR
    
             mov word [cs: pgdt+0x7c00],39      ;描述符表的界限   
    
             lgdt [cs: pgdt+0x7c00]
             in al,0x92                         ;南桥芯片内的端口 
    
             or al,0000_0010B
    
             out 0x92,al                        ;打开A20
    
             cli                                ;中断机制尚未工作
    
             mov eax,cr0
    
             or eax,1
    
             mov cr0,eax                        ;设置PE位
    
             ;以下进入保护模式... ...
    
             jmp dword 0x0010:flush             ;16位的描述符选择子:32位偏移                                             
    
             [bits 32]                          
      flush:                                     
    
             mov eax,0x0018                      
    
             mov ds,eax      
    
             mov eax,0x0008                     ;加载数据段(0..4GB)选择子
    
             mov es,eax
    
             mov fs,eax
    
             mov gs,eax
    
             mov eax,0x0020                     ;0000 0000 0010 0000
    
             mov ss,eax
    
             xor esp,esp                        ;ESP <- 0      
    
             mov dword [es:0x0b8000],0x072e0750 ;字符'P'、'.'及其显示属性
    
             mov dword [es:0x0b8004],0x072e074d ;字符'M'、'.'及其显示属性
    
             mov dword [es:0x0b8008],0x07200720 ;两个空白字符及其显示属性
    
             mov dword [es:0x0b800c],0x076b076f ;字符'o'、'k'及其显示属性
             ;开始冒泡排序 
             mov ecx,pgdt-string-1              ;遍历次数=串长度-1 
      @@1:
             push ecx                           ;32位模式下的loop使用ecx 
    
             xor bx,bx                          ;32位模式下,偏移量可以是16位,也可以 
    
      @@2:                                      ;是后面的32位 
    
             mov ax,[string+bx] 
    
             cmp ah,al                          ;ah中存放的是源字的高字节 
    
             jge @@3 
    
             xchg al,ah 
    
             mov [string+bx],ax 
      @@3:
    
             inc bx 
    
             loop @@2 
    
             pop ecx 
    
             loop @@1      
    
             mov ecx,pgdt-string
             xor ebx,ebx                        ;偏移地址是32位的情况 
      @@4:                                      ;32位的偏移具有更大的灵活性
    
             mov ah,0x07
    
             mov al,[string+ebx]
    
             mov [es:0xb80a0+ebx*2],ax          ;演示0~4GB寻址。
    
             inc ebx
    
             loop @@4
             hlt 
    ;-------------------------------------------------------------------------------
         string           db 's0ke4or92xap3fv8giuzjcy5l1m7hd6bnqtw.'
    ;-------------------------------------------------------------------------------
         pgdt             dw 0
                          dd 0x00007e00      ;GDT的物理地址
    ;-------------------------------------------------------------------------------                             
         times 510-($-$$) db 0
    
                          db 0x55,0xaa
    
  • 相关阅读:
    盲山有感
    一个用Regex的完成sql语句中字段替换的demo
    月夜奔跑
    乱弹
    《勇敢抉择》摘录一
    梦想高歌
    从今天起
    php性能优化
    unity3d shader中RenderType的所有类型
    Unity打包ipa图文教程
  • 原文地址:https://www.cnblogs.com/chengmf/p/12597972.html
Copyright © 2020-2023  润新知