码迷,mamicode.com
首页 > 编程语言 > 详细

ASM:《X86汇编语言-从实模式到保护模式》第12章:存储器的保护

时间:2016-02-25 21:19:29      阅读:342      评论:0      收藏:0      [点我收藏+]

标签:

       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            ;易错:字符串有一个\0,所以大小要减去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的值都没有。

ASM:《X86汇编语言-从实模式到保护模式》第12章:存储器的保护

标签:

原文地址:http://www.cnblogs.com/Philip-Tell-Truth/p/5218262.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!