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的值都没有。

  • 相关阅读:
    UVALive 5983 MAGRID DP
    2015暑假训练(UVALive 5983
    poj 1426 Find The Multiple (BFS)
    poj 3126 Prime Path (BFS)
    poj 2251 Dungeon Master 3维bfs(水水)
    poj 3278 catch that cow BFS(基础水)
    poj3083 Children of the Candy Corn BFS&&DFS
    BZOJ1878: [SDOI2009]HH的项链 (离线查询+树状数组)
    洛谷P3178 [HAOI2015]树上操作(dfs序+线段树)
    洛谷P3065 [USACO12DEC]第一!First!(Trie树+拓扑排序)
  • 原文地址:https://www.cnblogs.com/Philip-Tell-Truth/p/5218262.html
Copyright © 2011-2022 走看看