在文件系统的根目录区查找目标文件

学习自狄泰软件

1 cmp比较、相等的话jz跳转
2 不能使用sp直接访问栈顶数据,需要通过其它寄存器间接访问栈顶数据

回忆前面的知识,我们知道 文件系统中存在根目录区,根目录区由目录项组成,每个目录项代表根目录中的一个文件索引

在这里插入图片描述

所以我们可以根据目录项的前 11 个字节判断文件属性(名字等等),具体方法就是逐个比较这11个字节的空间,内存比较

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

[si] 将si 寄存器中存储的 地址所代表的空间出 取一个字节数据
[di] 同理

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

实验代码:

org 0x7c00

jmp short start
nop

define:
    BaseOfStack      equ 0x7c00
	;根目录区起始扇区位置 第19扇区
    RootEntryOffset  equ 19
	;根目录区占用14个扇区
    RootEntryLength  equ 14

header:
    BS_OEMName     db "D.T.Soft"
    BPB_BytsPerSec dw 512
    BPB_SecPerClus db 1
    BPB_RsvdSecCnt dw 1
    BPB_NumFATs    db 2
    BPB_RootEntCnt dw 224
    BPB_TotSec16   dw 2880
    BPB_Media      db 0xF0
    BPB_FATSz16    dw 9
    BPB_SecPerTrk  dw 18
    BPB_NumHeads   dw 2
    BPB_HiddSec    dd 0
    BPB_TotSec32   dd 0
    BS_DrvNum      db 0
    BS_Reserved1   db 0
    BS_BootSig     db 0x29
    BS_VolID       dd 0
    BS_VolLab      db "D.T.OS-0.01"
    BS_FileSysType db "FAT12   "

start:
    mov ax, cs
    mov ss, ax
    mov ds, ax
    mov es, ax
    mov sp, BaseOfStack
    
    mov ax, RootEntryOffset
    mov cx, RootEntryLength
    mov bx, Buf
    
    call ReadSector
    
    mov si, Target
    mov cx, TarLen
    mov dx, 0
    
    call FindEntry
    
    cmp dx, 0
    jz output
    jmp last
    
output:    
    mov bp, MsgStr
    mov cx, MsgLen
    call Print
    
last:
    hlt
    jmp last    

; es:bx --> root entry offset address  根目录区的起始地址
; ds:si --> target string  目标字符串
; cx    --> target length  字符串长度
;
; return:
;     (dx != 0) ? exist : noexist
;        exist --> bx is the target entry
FindEntry:
    push di
    push bp
	;由于需要反复调用 MemCmp() 所以先将 cx寄存器值入栈保存
    push cx
    ;根目录区最大查找次数 即 多少个目录项 224
    mov dx, [BPB_RootEntCnt]
	;此时 cx寄存器值在栈顶,所以此时是获取 cx寄存器的值,即获取目标字符串长度
    mov bp, sp
    
find:
    cmp dx, 0
    jz noexist
	;bx 根目录区中每一项的入口地址
    mov di, bx
    mov cx, [bp]
    call MemCmp
	;注意 查找结果放在cx寄存器中,这个查看查找结果
    cmp cx, 0
	;如果cx寄存器值是0  则查找成功 直接跳转到 exit 退出
    jz exist
	;如果查找不成功 则继续查找下一项。改变bx 寄存器值(每一项占用32字节,移动32字节到下一项入口)
    add bx, 32
	;dx减1
    dec dx
    jmp find

exist:
noexist:
    pop cx
    pop bp
    pop di
       
    ret

; ds:si --> source
; es:di --> destination
; cx    --> length
;
; return:
;        (cx == 0) ? equal : noequal
MemCmp:
	;备份寄存器 进栈保存, 这里没有保存cx寄存器值 是因为 cx寄存器是作为返回值使用的,没必要保存
    push si
    push di
    push ax
   
;循环   
compare:
	;比较cx寄存器值是否为0 如果是的话 比较相等,则跳转到 equal标签
    cmp cx, 0
    jz equal
	;如果不相等 则继续字节比较,将si 寄存器中存储的 地址所代表的空间出 取一个字节数据,给al 寄存器
    mov al, [si]
    ;用 al 寄存器中的值 和 di 寄存器中存储的 地址所代表的空间的一个字节 比较
	cmp al, byte [di]
	;比较相等 则继续比较下一个字节,即跳转到 goon标签处继续比较
    jz goon
	;如果不相等 则跳转到 noequal 标签
    jmp noequal
goon:	
	; == si++  理解为指针移位
    inc si
    inc di
	; cx 自减 cx--
    dec cx
	;继续比较 跳转到compare标签
    jmp compare
    
equal:
noequal:   
	;还原寄存器 出栈还原
    pop ax
    pop di
    pop si
    
    ret

; es:bp --> string address
; cx    --> string length
Print:
    mov ax, 0x1301
    mov bx, 0x0007
    int 0x10
    ret

; no parameter
ResetFloppy:
    push ax
    push dx
    
    mov ah, 0x00
    mov dl, [BS_DrvNum]
    int 0x13
    
    pop dx
    pop ax
    
    ret

; ax    --> logic sector number
; cx    --> number of sector
; es:bx --> target address
ReadSector:
    push bx
    push cx
    push dx
    push ax
    
    call ResetFloppy
    
    push bx
    push cx
    
    mov bl, [BPB_SecPerTrk]
    div bl
    mov cl, ah
    add cl, 1
    mov ch, al
    shr ch, 1
    mov dh, al
    and dh, 1
    mov dl, [BS_DrvNum]
    
    pop ax
    pop bx
    
    mov ah, 0x02

read:    
    int 0x13
    jc read
    
    pop ax
    pop dx
    pop cx
    pop bx
    
    ret

MsgStr db  "No LOADER ..."    
MsgLen equ ($-MsgStr)
Target db  "LOADER     "
TarLen equ ($-Target)
Buf:
    times 510-($-$$) db 0x00
    db 0x55, 0xaa

猜你喜欢

转载自blog.csdn.net/LinuxArmbiggod/article/details/120538810