标签:
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