zoukankan      html  css  js  c++  java
  • 存储器的保护(二)——《x86汇编语言:从实模式到保护模式》读书笔记19

    接着上一篇博文说。

    5.代码段执行时的保护

    每个代码段都有自己的段界限。同栈段一个道理,有效界限和G位相关。

    G=0:有效界限 = 描述符中的段界限

    G=1:有效界限 = 描述符中的段界限值 * 0x1000 + 0xFFF

    当处理器取指令的时候,偏移地址由EIP提供,EIP的范围应该在 [0,有效界限] 之间(为了说明问题,我就用数学上的闭区间表示了)。否则会引发异常。

    对于本代码,代码段描述符中的界限值是0x1FF,G=0,那么有效界限=0x1FF,也就是说这个值就是段内最后一个允许访问的偏移地址。

    再举一个例子,源文件中

    71         mov dword [es:0x0b8000],0x072e0750 ;字符'P'、'.'及其显示属性
    72         mov dword [es:0x0b8004],0x072e074d ;字符'M'、'.'及其显示属性
    73         mov dword [es:0x0b8008],0x07200720 ;两个空白字符及其显示属性
    74         mov dword [es:0x0b800c],0x076b076f ;字符'o'、'k'及其显示属性

    这四行对应的.list文件如下

    eip的有效值

    可以看到,第71行,mov dword [es:0x0b8000],0x072e0750 这条指令,其偏移地址为 0xB8~0xC2; 那么,要想这条指令顺利执行,定义代码段时,有效界限就要大于等于0xC2.当等于0xC2的时候,这条指令可以顺利执行,但是下一条指令的执行会引发异常。

    也就是说,如果某条指令的偏移地址为M~N,那么这条指令被顺利执行的必要条件是集合[M,N]属于集合[0,代码段的有效界限]。(请原谅我借用集合来描述,可是我再也想不出什么简明的表达了眨眼

    6.数据访问时的保护

    这里所说的数据段,特指向上扩展的数据段,有别于栈段和向下扩展的数据段。

    访问数据段时,是否越界与操作数的长度有关。

    对于向上扩展的数据段,有效界限的计算方法依然是:

    G=0:有效界限 = 描述符中的段界限

    G=1:有效界限 = 描述符中的段界限值 * 0x1000 + 0xFFF

    举例来说,第74行

    74         mov dword [es:0x0b800c],0x076b076f ;字符'o'、'k'及其显示属性

    这条指令的目的是把0x076b076f写入偏移地址为0x0b800c~0x0b800f的4个存储单元。如果要成功写入,那么0x0b800c~0x0b800f必须在数据段的有效界限内。也就是要求:

    [0xb800c, 0xb800f] 属于 [0, 上扩数据段的有效界限]

    本代码中,数据段的有效界限值是0xFFFF_FFFF,也就是说可以访问4GB空间内的任何一个单元。

    7.使用别名段访问代码段对字符排序

    104;-------------------------------------------------------------------------------
    105     string           db 's0ke4or92xap3fv8giuzjcy5l1m7hd6bnqtw.'
    106;-------------------------------------------------------------------------------

    第105行,定义了一串字符。作者要对这串字符进行升序排序,其实“醉翁之意不在酒”——排序是假,使用别名段是真。因为代码段是不允许写入的,所以要修改代码段,就需要为之创建一个别名描述符。第33、34行,程序为代码段创建了一个可读写的数据段描述符。也就是说,我们可以把代码段当成数据段来用。

    33         mov dword [ebx+0x18],0x7c0001ff    ;基地址为0x00007c00,512字节
    34         mov dword [ebx+0x1c],0x00409200    ;粒度为1个字节,数据段描述符,可读写

    第59、60行,把这个别名段的选择子加载到DS

    59         mov eax,0x0018                      
    60         mov ds,eax

    这里我们用冒泡排序法,虽然这个方法效率低,但是很适合初学者入门。关于冒泡排序的知识,请参考其他资料。

    为了说明问题,我绘制了一张图,假如一共有5个数,要把它们从左至右按照升序排列,示意图如下。

    冒泡排序示意图

    每比较一次,就把较大的数放在右边。那么第一次外循环后,最大的数就冒到了最右边;第二次外循环后,第二大的数冒到了从右边数第二个位置;……

    如果N个数参加排序,那么外循环需要(N-1)次。第1次需要(N-1)次比较,第2次需要(N-2)次比较,……第(N-1)次需要一次比较。

    说了这么多,我就是想说清楚代码。

    76         ;开始冒泡排序 
    77         mov ecx,pgdt-string-1              ;遍历次数=串长度-1 
    78  @@1:
    79         push ecx                           ;32位模式下的loop使用ecx 
    80         xor bx,bx                          ;32位模式下,偏移量可以是16位,也可以 
    81  @@2:                                      ;是后面的32位 
    82         mov ax,[string+bx] 
    83         cmp ah,al                          ;ah中存放的是源字的高字节 
    84         jge @@3 
    85         xchg al,ah 
    86         mov [string+bx],ax 
    87  @@3:
    88         inc bx 
    89         loop @@2 
    90         pop ecx 
    91         loop @@1

    第77行,刚开始,ECX保存着外循环的次数(字符数-1)。

    79行把ECX压栈是因为内循环也要用这个值(这个值就是本循环比较的次数),而且在内循环中,这个次数会变化。为了不破坏外循环的次数,所以要压栈保存。

    第81~89行,是内循环,完成字符对比的工作。首先一次性读入2个字符到AX中,AL中存放的是前一个(低地址处的)字符,AH中存放的是后一个(高地址处的)字符,如果前者大,则交换AL和AH的内容,然后把AX重写入原来的存储单元。接下来,BX加1,以指向下一个字符。

    93         mov ecx,pgdt-string
    94         xor ebx,ebx                        ;偏移地址是32位的情况 
    95  @@4:                                      ;32位的偏移具有更大的灵活性
    96         mov ah,0x07
    97         mov al,[string+ebx]
    98         mov [es:0xb80a0+ebx*2],ax          ;演示0~4GB寻址。
    99         inc ebx
    100        loop @@4
    101      
    102        hlt

    排序完毕后,第93~100,用于显示最终的排序结果。

    第98行表示从显存的第2行第1列(0xb8000 + 0xa0(=160D) = 0xb80a0)开始显示字符串。当EBX=0、1、2……时,对应的地址是0xb80a0、0xb80a2、0xb80a4……(使用比例因子就是这么方便大笑),注意,“0xb80a0 + ebx * 2”,这个表达式的值是在指令执行时,由处理器计算出来的。

    (12章完)

  • 相关阅读:
    Linux 日志管理
    Linux 备份与恢复
    Linux 启动管理
    Linux 用户和用户组管理
    产生指定时间区间序列、按指定单位变化时间 python实现
    python上数据存储 .h5格式或者h5py
    数据预处理之独热编码(One-Hot Encoding)
    残差网络
    GBDT为什么不能并行,XGBoost却可以
    百融金服、趣店、中航信面试总结
  • 原文地址:https://www.cnblogs.com/longintchar/p/5224395.html
Copyright © 2011-2022 走看看