编辑: LinDa_学友 | 2019-07-09 |
80286 时代,它的地址总线位数增加到了
24 位,因此可以访问到 16MB 的 内存空间.更重要的是从此开始引进了一个全新理念――保护模式.这种模式下内存 段的访问受到了限制.访问内存时不能直接从段寄存器中获得段的起始地址了,而需 要经过额外转换和检查.为了和
8086 兼容,80286 内存寻址可以有两种方式,一种是 先进的保护模式,另一种是老式的
8086 方式,被称为实模式.Intel 选择了在段寄存 器的基础上构筑保护模式,并且保留
16 位的段寄存器.不同的是,在保护模式下, 段范围不再受限于 64K,可以达到 16MB(或者
80386 的4GB) .这一下真正解放了 软件工程师,他们不必再费尽心思去压缩程序规模,软件功能也因此迅速提升. 从8086 的16 位到
80386 的32 位,看起来是处理器位数的变化,但实质上是处 理器体系结构的变化,从寻址方式上说,就是从 实模式 到 保护模式 的变化. 下面,我们详细讨论保护模式的引入带来的寻址方式、中断管理这两个方面的变化, 以及相关的模式切换以及安全性问题. 2. 寻址方式的变化 1) 实模式下段的管理 实模式采用
16 位寻址模式,在该模式中,最大寻址空间为 1MB,最大分段为 64KB. 由于处理器的设计需要考虑到向下兼容的问题, 实模式也是我们今天接触到的大多数计算机 在启动后处于的寻址模式.
8086 处理器地址总线扩展到
20 位,但算术逻辑运算单元(ALU)宽度即数据总线却只 有16 位,也就是说直接参与运算的数值都是
16 位的.为支持 1MB 寻址空间,8086 在实模 式下引入了分段的方法.在处理器中设置了四个
16 位的段寄存器:CS、DS、SS、ES,对 应于地址总线中的高
16 位.寻址时,采用以下公式计算实际访问的物理内存地址: 实际物理地址 = (段寄存器 , 或者我们使用 bochs Cq 命令启动 Bochs 便可以直接开始模拟. 图2-2 Bochs 命令行 从这里开始,我们便可以使用如下的 Bochs 调试命令 ? 执行控制命令 c/continue 表示继续执行 s/step/stepi [count] 表示继续执行 count 条指令, 如果没有设定 count 的值, 则执行一条 指令 Ctrl-C 停止执行,返回命令行 Ctrl-D 如果命令行此时是空的则退出 Bochs 模拟 q/quit/exit 退出调试和执行 图2-3 执行控制命令的使用 从图 3-3 中可以看到我们启动 Bochs 后便开始使用 s 命令单步执行,然后使用 c 命令继续执行打印出 hello world ,最后使用 q 退出模拟. ? 断点设置命令 vb/vbreak seg:off 用虚拟地址来设置断点,其中 seg 表示段基址,而off 是偏移地址 lb/lbreak addr 用线性地址来设置断点,addr 表示线性地址 b/break/pb/pbreak addr 用物理地址来设置断点,addr 表示物理地址 info break 显示当前所有的断点的状况 bpe n 激活第 n 个断点 bpd n 使第 n 个断点无效 d/del/delete 删除第 n 个断点 假如在实模式下我们想要在物理内存 0x7c00 处设置一个断点,我们可以使用这的几种 方式:vb 0x0:0x7c
00、lb 0x7c
00、b 0x7c00 图2-4 用虚拟地址设置断点 图2-5 用线性地址设置断点 图2-6 用物理地址设置断点 从以上的三副图中我们可以看到用三种不同的方式设置断点后程序都会在相同的时间 点在相同的位置停止执行. ? 监视内存命令 watch r/read addr 在物理地址 addr 处插入一个读内存监视符,即默认的情况下,如 果程序执行到某条指令需要在这个位置读取内存的时候便会自动停止 watch w/write addr 在物理地址 addr 处插入一个写内存监视符, 即默认的情况下, 如 果程序执行到某条指令需要在这个位置写内存的时候便会自动停止 watch 显示所有当前的内存监视符 watch stop 设定程序执行到监视符所对应的位置时,若满足读/写的条件则 停止执行(默认设置) watch continue 设定程序执行到监视符所对应的位置时,若满足读/写的条件则 还是继续执行 unwatch addr 去除内存 addr 地址处的监视符 unwatch 去除所有的内存读/写监视符 例如,若要在内存 0x7c00 处设置一个读内存的监视符,我们用如下的方式: watch read 0x7c00 图2-7 插入读内存的监视符 在上图中可以看到我们成功的插入了一个读内存的监视符,则当程序从内存的 0x7c00 的地址处读数据时便会自动的停下来. 又如当我们需要在内存 0x7c00 处设置一个写内存的监视符,我们用如下的方式: watch write 0x7c00 图2-8 插入写内存的监视符 在图 3-8 中可以看到我们设置了一个写内存的监视符,于是当程序执行到 t=194201 时, 由于此时需要向内存的 0x7c00 处写数据,所以程序这个时候停止执行. ? 查看内存命令 x [/nuf] addr 查看当前内存某个地址的内容,其中 addr 代表线性地址 xp [/nuf] addr 查看当前内存某个地址的内容,其中 addr 代表物理地址 我们可以看到在这里/nuf 是可选择的,其中 n、u、f 都有各自的含义: n 表示从所给的首地址开始显示内存多少个单元的内容 u 表示显示内容每个单元的大小, 每个单元的大小分为四种情况: b 表示以字节为单位 h 表示以字为单位(2 字节) w 表示以双字为单位(4 字节) g 表示以长字为单位(8 字节) f 在屏幕上显示的形式 x 以十六进制的形式显示 d 以有符号十进制数的形式显示 u 以无符号十进制数的形式显示 o 以八进制的形式显示 t 以二进制流的形式 在缺省的情况下,n 默认为 1,u 和f都是默认为上次使用的值,如果之前没有被用过 则默认为 w 和x.如果这三个可选参数都没有被使用,则我们不应该打'