07 突破512字节的限制 中
https://www.cnblogs.com/wanmeishenghuo/tag/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/
https://blog.51cto.com/13475106/category6.html
及狄泰软件相关课程
上一节我们写了字符串打印的函数和软盘读取函数,在软盘读取函数中,我们是直接给定了要读的逻辑扇区号,这一节我们来实现一个查找文件的功能,也就是根据给定的文件名,在根目录区中查找指定的文件是否存在,涉及到文件名的查找,就会涉及到内存的比较,因此,我们需要实现两个函数,分别为内存比较函数和根目录区查找函数。
整体的流程如下:

首先将根目录区加载到内存中的指定位置上,这里面包含了一定数目的根目录项,而根目录项的前11个字节为文件名,因此,查找文件的工作就可以进行了,我们只需要将目标文件名和每一个根目录项的前11个字节进行比较即可,如果文件存在,必定会在某一个目录项中找到,只需将目录项的偏移位置通过寄存器返回即可。
内存比较的示意图如下:

需要用到的两个指令如下:
比较指令:cmp cx, 0 ; 比较cx的值是否为零
跳转:jz equal ; 如果比较的结果为真,则跳转到equal处
用于比较的汇编程序片段如下:

org 0x7c00
jmp short start
nop
define:
BaseOfStack equ 0x7c00
RootEntryOffset equ 19
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 si, MsgStr
mov di, DEST
mov cx, MsgLen
call MemCmp
cmp cx, 0
jz label
jmp last
label:
mov bp, MsgStr
mov cx, MsgLen
call Print
output:
mov bp, MsgStr
mov cx, MsgLen
call Print
last:
hlt
jmp last
; ds:si --> source
; es:di --> destination
; cx --> length
;
; return:
; (cx == 0) ? equal : noequal
MemCmp:
push si
push di
push ax
compare:
cmp cx, 0
jz equal
mov al, [si]
cmp al, byte [di]
jz goon
jmp noequal
goon:
inc si
inc di
dec cx
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 "Hello World"
MsgLen equ ($-MsgStr)
DEST db "Hello World"
Buf:
times 510-($-$$) db 0x00
db 0x55, 0xaa
运行结果如下:

上图的程序中,我们直接比较的字符串“Hello World”,如果比较成功,就将字符串打印出来。
下面我们进行文件的查找,具体流程如下图:

首先加载根目录区,将根目录区加载到指定的缓冲区中,程序片段如下:

访问栈顶数据时,不能通过sp直接访问,而要经过其他寄存器间接访问,如下:

有了以上的思路后,我们直接给出查找文件的汇编程序:
org 0x7c00
jmp short start
nop
define:
BaseOfStack equ 0x7c00
RootEntryOffset equ 19
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
push cx
mov dx, [BPB_RootEntCnt]
mov bp, sp
find:
cmp dx, 0
jz noexist
mov di, bx
mov cx, [bp]
call MemCmp
cmp cx, 0
jz exist
add bx, 32
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:
push si
push di
push ax
compare:
cmp cx, 0
jz equal
mov al, [si]
cmp al, byte [di]
jz goon
jmp noequal
goon:
inc si
inc di
dec cx
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
如果找不到文件会打印出“No LOADER...”,如果能找到,则不打印任何字符。不打印字符的话却无法证明我们的程序是正确的,我们下面进行断点调试,看一下寄存器内容,首先使用ndisasm -o 0x7c00 boot.bin > boot.txt进行反编译,找到适合的断点。
我们应该在第51行cmp dx, 0处对应的地方打断点,根据boot.txt文件中的内容,我们来确定断点地址,如下:

可以看到,断点地址应该为0x7c61,接下来,启动bochs,进行调试,结果如下:

根据上图可以看出,dx寄存器的值为219,dx为输出寄存器,也就是文件所在的目录项的位置,如果dx为0,说明文件不存在,dx不为0,则说明文件找到了,到此为止,我们查找文件的实验成功了。
总结:

posted on 2020-11-17 13:36 lh03061238 阅读(147) 评论(0) 收藏 举报
浙公网安备 33010602011771号