详细注释GetFATEntry(转载)

转载与http://daikof622.wordpress.com/2009/12/18/%E6%B3%A8%E9%87%8Agetfatentry/

花了将近两天的时间,反复比对书上的概念和网上前辈们的总结,总算把这段代码给搞清楚了。(这里使用的是FAT12软盘结构)

函数GetFATEntry。参数存放在ax寄存器中,表示一个簇号。输出结果是该簇号在FAT表中的FATENTRY,它的内容仍然是一个簇号,表示文件下一部分所在簇的簇号。这里要仔细地体会“簇号”和“簇”之间的差别,否则在看代码的时候,很容易就会迷失。“簇”表示一个或多个扇区的集合。FAT12中,一个簇就是一个扇区,512字节。簇号,从软盘的数据区开始,从2开始编号(0,1为系统使用),本质上是一个基于FAT表的索引。

GetFATEntry:
    push    es
    push    bx

;函数中使用到了es和bx所以要进行保存,保存在栈上。

;es:bx会被函数ReadSector所使用,是int 13h所要求的,指向了一个缓冲区,保存从软盘读进来的数据。
    push    ax
    mov    ax, BaseOfLoader
    sub    ax, 0100h   

;以上在BaseOfLoader之后留出4KB空间。为什么明明是0100h(256),怎么说是4K?

;因为这是个段基址,0100h还要乘上个16。
    mov    es, ax       
    pop    ax
    mov    byte [bOdd], 0
    mov    bx, 3
    mul    bx
    mov    bx, 2
    div    bx   
    cmp    dx, 0
    jz    LABEL_EVEN
    mov    byte [bOdd], 1

;以上部分是整个函数的难点所在,用户计算簇号在FAT表中所对应的FATENTRY相对于FAT首地址的偏移。

;从书上可以得知,FAT12中每个FATENTRY是12位的。所以如下:

7654 | 3210(byte1)    7654|3210(byte2)    7654|3210(byte3)

byte1和byte2的低4位表示一个Entry;根据Big-Endian,Entry内容为:3210(byte2)76543210(byte1)

byte3和byte2的高4位表示一个Entry;根据Big-Endian,Entry内容为:76543210(byte3)7654(byte2)

所以这里存在一个奇偶数的问题,以字节为单位。以上为例,Entry0偏移为0,Entry1偏移为1,Entry2偏移为3。

以INT[“簇号”*1.5]的方式增加。这也就是为什么上面先乘3再除2来计算。

根据DIV指令规定,商保存在ax中,余数在dx中。所以此时ax就是FATENTRY在FAT中以字节为边界的偏移量。

——————————————————————————————–
LABEL_EVEN:
    xor    dx, dx   
    mov    bx, [BPB_BytsPerSec]
    div    bx   

;dx:ax/BPB_BytsPerSec,所以ax现在是扇区的个数,dx是在最后一个扇区中的偏移。
    push    dx
    mov    bx, 0   

;es:bx指向了目标空间的首地址,就是函数开始在BaseOfLoader之后留出的4KB空间。
    add    ax, SectorNoOfFAT1   

;SectorNoOfFAT1是FAT1的相对扇区号,物理上就是0面0道1扇区。FAT12有两个完全一样的FAT表,FAT1和FAT2。
    mov    cl, 2

;cl总保存ReadSector函数的参数,表示要连续读入2个扇区。另一个参数ax在前面已经给出。
    call    ReadSector   
    pop    dx
    add    bx, dx

;在add之前,bx为目标空间的首地址,其中内容是包含FATEntry的扇区。bx+dx就定位到了该FATEntry。
    mov    ax, [es:bx]

;ax中为es:bx指向的空间的内容。
    cmp    byte [bOdd], 1

;是奇数的簇号还是偶数的簇号??
    jnz    LABEL_EVEN_2
    shr    ax, 4

;7654 | 3210(byte1)    7654|3210(byte2)    7654|3210(byte3)

根据上面这个例子,奇数的簇号,1,偏移为1,所以读要ax中的时候,因为ax是16位,所以根据Big-Endian,ax的内容为7654|3210(byte3)|7654|3210(byte2),所以右移4位就可以了。

偶数簇号,0,偏移为0,读入ax后,ax的内容为7654|3210(byte2)7654 | 3210(byte1),我们只需要低12位即可,

所以and ax,0FFFh。

——————————————————————————————–
LABEL_EVEN_2:
    and    ax, 0FFFh

LABEL_GET_FAT_ENRY_OK:

    pop    bx
    pop    es
    ret

posted on 2011-05-12 14:55  wanghj_dz  阅读(660)  评论(0编辑  收藏  举报

导航