zoukankan      html  css  js  c++  java
  • ASM:《X86汇编语言-从实模式到保护模式》第12章:存储器的保护

           12章其实是11章的拓展,代码基本不变,就是在保护模式下展开讨论。

    ★PART1:存储器的保护机制

    1. 修改段寄存器的保护

         当执行把段选择子传到段寄存器的选择器部分的时候,处理器固件在完成传送之前,要检查和确认选择子是正确的,并且该选择子选择的描述符也是正确的。假如索引号是正确的,也就是说明索引号8+7要小于等于边界。如果超过边界,那么处理器就会终止处理,产生异常中断13,同时段寄存器的原值保持不变。

           同时处理器还要对描述符的类别进行检查,如果描述符的类别进行确认,举个例子来说,如果描述符的类型只是只执行的代码段,那么则不允许加载到除了CS之外的其他段寄存器中。首先描述符的类别字段必须是有效的值,比如0000就是个无效的值。然后,处理器会对描述符的类别是否符合段寄存器的用途,规则如图。

         

           除了按照上表进行检查之外,还要检查描述符中的P位,如果P=0,表明虽然描述符已经被定义,但该段实际上并不存在于内存中,此时,处理器应该终止处理,引发异常中断11。一般来说,应当定义一个中断处理程序,把该描述符所对应的段从硬盘等外部存储器调入内存,然后置P位。中断返回时,处理器将再次尝试刚才的操作。如果P=1,则处理器将描述符加载到段寄存器的描述符高速缓存器,同时置A位(仅限于当前讨论的存储器的段描述符。)

           可读的代码段相当于是一个ROM,可以使用段超越前缀来读其中的内容,也可以将他的描述符选择子加载到DS,ES,FS,GS作为数据段进行访问。代码段在任何时候都是不可写的。对于DS,ES,FS和GS的段选择器,可以向其加载数值为0的选择子,即

      

           但是在真正访问内存的时候,就会引发异常中断,但是对于CS和SS来说,不允许传送为0的选择子。

    2. 地址变换的保护

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

           段界限的计算方式:

           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(回绕回来了)

    3. 使用别名访问代码段(alias)

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

    ★PART2:第12章的例程

    1. 插入排序

        书上的例程用的是冒泡排序,自己改了个插入排序,感觉还不错,另外要注意的是,NASM对mov ds,ax和mov ds,eax生成的机器码都是一样的(一般来说,因为ax是16位的源操作数,理论来说应该加前缀0x66,而且有了这个前缀,处理器在执行时会多花一个时钟周期执行,很多编译器都不会区分这个区别。)

      1 ;---------------------主引导扇区程序---------------------
      2     mov eax,[cs:gdt_base+0x7c00]
      3     xor edx,edx
      4     mov ebx,0x10
      5     div ebx                            ;在AX得到线性基地址
      6     
      7     mov ds,ax                         ;把gdt_base线性基地址地址给ds
      8     mov bx,dx                        ;偏移地址
      9     
     10 ;描述符很容易错的地方是:会把高地址的32位和低地址的32位弄反
     11 ;------------------------描述符#0------------------------
     12     mov dword[ebx+0x00],0x00000000    ;NULL
     13     mov dword[ebx+0x04],0x00000000
     14 ;------------------------描述符#1------------------------
     15     mov dword[ebx+0x08],0x7c00fffe    ;栈段
     16     mov dword[ebx+0x0c],0x00cf9600
     17 ;------------------------描述符#2------------------------
     18     mov dword[ebx+0x10],0x7c0001ff    ;数据段
     19     mov dword[ebx+0x14],0x00409200
     20 ;------------------------描述符#3------------------------
     21     mov dword[ebx+0x18],0x7c0001ff    ;代码段
     22     mov dword[ebx+0x1c],0x00409800
     23 ;------------------------描述符#4------------------------
     24     mov dword[ebx+0x20],0x0000ffff    ;数据段
     25     mov dword[ebx+0x24],0x00cf9200
     26 ;--------------------------------------------------------
     27     mov word[cs:gdt_size+0x7c00],39    ;40个字节-1            ;易错:容易漏加载大小
     28     lgdt [cs:gdt_size+0x7c00]        ;加载段描述符
     29 ;--------------------------------------------------------
     30     in al,0x92
     31     or al,0x02
     32     out 0x92,al                        ;快速开启A20
     33     
     34     cli                                ;一定要记得关闭中断!!!!!很容易遗忘
     35 ;--------------------------------------------------------
     36     mov eax,cr0
     37     or eax,0x01
     38     mov cr0,eax                        ;开启保护模式
     39 ;--------------------------------------------------------
     40     jmp 0x0018:flush                ;清空流水线并且串行化
     41     [bits 32]
     42 flush:
     43     mov ax,0x0008
     44     mov ss,ax                        ;加载栈段
     45     mov sp,0
     46     
     47     mov ax,0x0010                    ;加载数据段
     48     mov ds,ax
     49     
     50 ;-----------------------插入排序-------------------------
     51     mov ecx,gdt_size-string            ;易错:字符串有一个,所以大小要减去1
     52     cmp ecx,1 
     53     je print
     54     
     55     mov ebx,1                    ;这个就要求至少要大于等于2
     56     @1:
     57     push ecx
     58     mov al,[ebx+string]
     59     mov [tmp],al
     60     mov ecx,ebx
     61         @2:
     62         mov al,[ecx+string-1]
     63         cmp al,[tmp]
     64         jl @3
     65         mov al,[ecx+string-1]
     66         mov [ecx+string],al
     67         dec ecx
     68         cmp ecx,0
     69         jg @2
     70     @3:
     71     mov al,[tmp]
     72     mov [ecx+string],al
     73     pop ecx
     74     inc bx
     75     loop @1
     76 ;-----------------------打印已序序列------------------------
     77 print:
     78     mov ax,0x0020                        ;4GB大小的段的寻址,其实是一样的
     79     mov es,ax
     80     
     81     mov ecx,gdt_size-string
     82     mov edi,0
     83     mov ebx,0xb8000
     84     @4:
     85     mov ah,0x07
     86     mov al,[edi+string]
     87     mov [es:ebx+edi*2],ax
     88     inc di
     89     loop @4
     90 ;-------------------------停机---------------------------
     91 stop:
     92     hlt
     93 ;--------------------------------------------------------
     94 tmp:      db 0                            ;定义一个临时变量,注意这个东西千万不能在代码区出现!
     95 ;--------------------------------------------------------
     96 string:      db 's0ke4or92xap3fv8giuzjcy5l1m7hd6bnqtw.'
     97 ;--------------------------------------------------------
     98 gdt_size: dw 0x00
     99 gdt_base: dd 0x00007e00
    100 ;--------------------------------------------------------
    101     times 510-($-$$) db 0
    102                      dw 0xaa55

    2. 课后习题第一题

     

      1 ;---------------------------12.1----------------------------
      2     code_start equ 0x7c00
      3     pos1 equ 0x0050
      4     pos2 equ 0x00a0
      5     
      6     mov eax,[cs:gdt_base+code_start]
      7     xor edx,edx
      8     mov ebx,16
      9     div ebx                                    ;基地址在AX上,偏移地址在DX上
     10     
     11     mov ds,eax
     12     mov ebx,edx 
     13 ;--------------------------描述符#0--------------------------
     14     mov dword[ebx+0x00],0x00000000
     15     mov dword[ebx+0x04],0x00000000
     16 ;--------------------------描述符#1--------------------------
     17     mov dword[ebx+0x08],0x7c0001ff            ;代码段
     18     mov dword[ebx+0x0c],0x00409800
     19 ;--------------------------描述符#2--------------------------
     20     mov dword[ebx+0x10],0x00000fff            ;要扫描的数据段,长65536*4个字节
     21     mov dword[ebx+0x14],0x00c09210
     22 ;--------------------------描述符#3--------------------------
     23     mov dword[ebx+0x18],0x80000fff            ;屏幕显示段
     24     mov dword[ebx+0x1c],0x0040920b
     25 ;--------------------------描述符#4--------------------------
     26     mov dword[ebx+0x20],0x7c0001ff            ;代码段别名段
     27     mov dword[ebx+0x24],0x00409200
     28 ;--------------------------描述符#5--------------------------
     29     mov dword[ebx+0x28],0x7c00fffe            ;栈段
     30     mov dword[ebx+0x2c],0x004f9600
     31 ;------------------------------------------------------------
     32     mov word[cs:gdt_size+code_start],47        ;设定选择子界限值
     33     lgdt [cs:gdt_size+code_start]
     34 ;------------------------------------------------------------
     35     in al,0x92
     36     or al,0x02
     37     out 0x92,al                                ;快速开启A20
     38     cli                                        ;关中断
     39 ;------------------------------------------------------------
     40     mov eax,cr0
     41     or eax,0x01                                ;设定PE位
     42     mov cr0,eax
     43 ;------------------------------------------------------------
     44     jmp 0x0008:flush                        ;清空流水线并且串行化处理器,进入保护模式
     45     [bits 32]
     46 flush:
     47     mov eax,0x0028
     48     mov ss,eax                                ;设置栈段
     49     mov sp,0
     50     
     51     mov eax,0x0018
     52     mov es,eax                                ;设定显示段
     53     mov eax,0x0020
     54     mov ds,eax                                ;设定别名段
     55     mov eax,0x0010
     56     mov gs,eax                                ;设定要搜索的段
     57     
     58     mov edi,0x0000
     59     mov esi,string
     60     mov ecx,gdt_size-string
     61     call print_string
     62 
     63     mov esi,nums
     64     mov ecx,0                                ;统计总数
     65 @scan:
     66     ;先显示总数                    
     67     inc dword[tmp]
     68     
     69     mov di,pos1            ;设定显示位置
     70     call cal_nums
     71     
     72     ;再看下能不能找到一个有效块
     73     mov di,pos2            ;设定显示位置
     74     call compare
     75     
     76     inc ecx
     77     cmp ecx,0xfffff
     78     jle @scan
     79 ;-------------------------停机------------------------------
     80     hlt
     81 ;code_end
     82     
     83 
     84 
     85 ;------------------------------------------------------------
     86 ;------------------------------------------------------------
     87 ;------------------------函数部分----------------------------
     88 ;------------------------------------------------------------
     89 print_string:
     90     push eax
     91     push ebx
     92     push ecx
     93     push edx
     94     
     95     mov ebx,edi
     96     mov edx,esi
     97     print_start:    
     98         mov al,[edx]
     99         mov [es:ebx*2],al
    100         mov byte[es:ebx*2+1],0x07
    101         inc ebx
    102         inc edx
    103         loop print_start
    104     
    105     pop edx
    106     pop ecx
    107     pop ebx
    108     pop eax
    109     ret
    110 ;------------------------------------------------------------
    111 cal_nums:
    112     push eax
    113     push ecx
    114     
    115     mov eax,[tmp]
    116     mov ebx,10
    117     mov ecx,0
    118     @1:
    119         xor edx,edx
    120         div ebx
    121         push edx
    122         inc ecx
    123         cmp eax,0
    124         jne @1
    125     mov ebx,ecx
    126     mov edx,0
    127     @2:
    128         pop eax
    129         add al,0x30
    130         mov [edx+nums],al
    131         inc edx
    132         loop @2
    133     mov ecx,ebx                            ;恢复要打印的数量
    134     call print_string
    135     
    136     pop ecx
    137     pop eax
    138     ret
    139 ;------------------------------------------------------------
    140 compare:
    141     push eax
    142 
    143     cmp dword[gs:ecx*4],0x55aa55aa
    144     je Found_a_Block
    145     cmp dword[gs:ecx*4],0xaa55aa55
    146     je Found_a_Block
    147 
    148     out_func:
    149         pop eax
    150         ret
    151     Found_a_Block:
    152         inc dword[found_num]
    153         mov eax,[found_num]
    154         mov [tmp],eax
    155         
    156         call cal_nums
    157         
    158         pop eax
    159         ret
    160 ;function_end    
    161     
    162 ;------------------------------------------------------------
    163 ;-------------------------数据区-----------------------------
    164 ;------------------------------------------------------------
    165     tmp:        dd 0
    166 ;------------------------------------------------------------
    167     found_num    dd 0
    168 ;------------------------------------------------------------
    169     nums: times 12 db 0
    170 ;------------------------------------------------------------
    171     string:     db 'Protect mode has been started'
    172 ;------------------------------------------------------------
    173     gdt_size:     dw 0
    174     gdt_base:     dd 0x00007e00
    175 ;------------------------------------------------------------
    176     times 510-($-$$) db 0
    177                      dw 0xaa55

       结果一个0xaa55aa55或者0x55aa55aa的值都没有。

  • 相关阅读:
    内存分配机制
    typedef struct 和struct的区别
    imshow
    #include<string.h>和#include<string>
    Internal Errors
    TStopWatch 基本知识
    string 新常量 Empty
    System 这四个单元多用用(近期)
    对象释放三种方法对比:Free --> FreeAndNil() --> DisposeOf()
    程序性能优化的3个级别
  • 原文地址:https://www.cnblogs.com/Philip-Tell-Truth/p/5218262.html
Copyright © 2011-2022 走看看