Chinaunix首页 | 论坛 | 博客
  • 博客访问: 363000
  • 博文数量: 38
  • 博客积分: 1935
  • 博客等级: 上尉
  • 技术积分: 724
  • 用 户 组: 普通用户
  • 注册时间: 2005-11-23 16:34
文章存档

2010年(4)

2009年(33)

2008年(1)

分类:

2009-05-03 21:16:22

使用 bochs 可以很容易很直观地观察调试系统。下面选取一个 xp 启动的实际片断,如下:

sreg
cs:s=0x001b, dl=0x0000ffff, dh=0x00cffa00, valid=1
ds:s=0x0023, dl=0x0000ffff, dl=0x00cff300, valid=31
ss:s=0x0023, dl=0x0000ffff, dl=0x00cff300, valid=31
ss:s=0x0023, dl=0x0000ffff, dl=0x00cff300, valid=31
fs:s=0x003b, dl=0xe000ffff, dl=0x7f40f3fd, valid=7
gs:s=0x0000, dl=0x00000000, dl=0x00000000, valid=0
ldtr:s=0x0000, dl=0x00000000, dh=0x00000000, valid=0
tr:s=0x0028, dl=0x200020ab, dh=800008b04, valid=1
gdtr:base=0x8003f000, limit=0x3ff
idtr:base=0x8003f400, limit=0x7ff



1、GDTR.base 是 0x8003f000, GDTR.limit 是 0x3ff
2、IDTR.base 是 0x8003f400, IDTR.limit 是 0x7ff
3、LDTR.selector  为 0x0000

这里没有建立 LDT,它的 selector 是 0x0000,也就是 NULL descriptor。



5.6.1、  观察 cs register

观察 cs 的信息:
1、cs 使用的 selector 正是前面提到的 0x1b
2、接下来的 dl=0x0000ffff, dh=0x00cffa00 其实就是 descriptor 信息。

来看一看 cs 的 descriptor 的什么:

x/2 0x8003f000+3*8
0x8003f018 :  0x0000ffff   0x00cffa00


  cs 使用的 selector 是 0x1b,因此:selector.RPL = 3  使用的权限 3   selector.TI = 0,使用 GDT,selector.SI = 3

  descriptor 的地址在:gdtr.base + 3 * 8 = 0X8003f018。

  它的值按 64 位显示是:0x00cffa00_0000ffff。


那么,descriptor 的信息:
1、 base = 0x00000000,这是 32 位值。
2、 limit = 0xffffff,这是一个 20 位的值。
3、 DPL = 11b,也就是 3 级。
4、 S 位是 1,它是一个非系统的 descriptor,也就是属于 segment descriptor。
5、 type 是 1010b,显示它是一个 execute/readable  non-conforming 类型的 code segment descriptor。
6、 limit 的粒度位 G 位是 1,显示它是 4K 粒度的。
7、 最后缺省位 D 位是 1, 表明目标 code segment 的 32 位代码。

  对这个 descriptor 描述的信息,归纳一下为:segment 是 32 位的代码段,基地址是 0x00000000,访问权限是 3 级,limit 是 0xFFFFF * 0x1000 + 0xFFF = 4G。
  物理上这个 descriptor 被加载到 cs register 里。




5.6.2、 观察 ds register

  我们看看 ds 加载的 descriptor 的又是怎样的。
  ds 使用的 selector 是 0x23:TI = 0,SI = 4 以及 RPL = 3。

获取 descirptor :
x/2 0x8003f000+4*8
0x8003f020 :  0x0000ffff   0x00cff300


这个 descriptor 的值是:0x00cff300_0000ffff  (64 位值)


1、 base = 0x00000000,这是 32 位值。
2、 limit = 0xffffff,这是一个 20 位的值。
3、 DPL = 11b,也就是 3 级。
4、 S 位是 1,它是一个非系统的 descriptor,也就是属于 segment descriptor。
5、 type 是 0011b,显示它是一个具有 R/W 权限的 data segment descriptor。
6、 limit 的粒度位 G 位是 1,显示它是 4K 粒度的。
7、 最后缺省位 D 位是 1, 同 code segment descriptor 意义一致

---------------------------

这个 descriptor 与上面 cs 的 descriptor 不同之处仅是 type 不同。这个 descriptor 是个 data segment descriptor。



5.6.3、 平坦的内存模式

  现在的操作系统绝大部分使用平坦的内存模式,这种模式下,所有 segment 的基址是 0x00000000,但是 windows 使用了 FS 来定义非零基址的段。 FS 描述的段的基地址是:0x7f3de000,使用 FS 来管理一些系统信息。
  使用了平坦模式,导致可以使用 ds 读取 cs 的数据,或者可以执行 cs 以外的如:ds 或 ss 的代码。在 segmentation 这个阶段里 processor 无法阻止 stack 里的代码可以执行这一情况。直至在 paging 保护措施上才得到解决。

  既然使用了平坦模式,逻辑地址与线性地址是一致的。导致现代操作系统已经弱化逻辑地址这个概念,虚拟地址一般就指线性地址

因此:对于两条指令
  mov eax, dword ptr cs:[0x8012100]
      mov eax, dword ptr ds:[0x8012100]
      -------------------------------------
      结果是完全一致的。当然这是有提前的。提前是:cs 装的这个 code segment 是可读的。



但是,对于这两条指令,情况就不同了:

  mov dword ptr cs:[0x8012100],eax
      mov dword ptr ds:[0x8012100],eax
     -------------------------------------
     第 1 条是会出错的。这里 cs 装的 code segment 是不可写的。
 
 
 
 
 
:)
阅读(1061) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~