突破512

上一节我们写了字符串打印的函数和软盘读取函数,在软盘读取函数中,我们是直接给定了要读的逻辑扇区号,这一节我们来实现一个查找文件的功能,也就是根据给定的文件名,在根目录区中查找指定的文件是否存在,涉及到文件名的查找,就会涉及到内存的比较,因此,我们需要实现两个函数,分别为内存比较函数和根目录区查找函数。

  整体的流程如下:

 

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

  内存比较的示意图如下:

 

  需要用到的两个指令如下:

  比较指令:cmp cx, 0    ;  比较cx的值是否为零

  跳转:jz equal  ; 如果比较的结果为真,则跳转到equal处

  用于比较的汇编程序片段如下:

 

  

复制代码
  1 org 0x7c00
  2 
  3 jmp short start
  4 nop
  5 
  6 define:
  7     BaseOfStack      equ 0x7c00
  8     RootEntryOffset  equ 19
  9     RootEntryLength  equ 14
 10 
 11 header:
 12     BS_OEMName     db "D.T.Soft"
 13     BPB_BytsPerSec dw 512
 14     BPB_SecPerClus db 1
 15     BPB_RsvdSecCnt dw 1
 16     BPB_NumFATs    db 2
 17     BPB_RootEntCnt dw 224
 18     BPB_TotSec16   dw 2880
 19     BPB_Media      db 0xF0
 20     BPB_FATSz16    dw 9
 21     BPB_SecPerTrk  dw 18
 22     BPB_NumHeads   dw 2
 23     BPB_HiddSec    dd 0
 24     BPB_TotSec32   dd 0
 25     BS_DrvNum      db 0
 26     BS_Reserved1   db 0
 27     BS_BootSig     db 0x29
 28     BS_VolID       dd 0
 29     BS_VolLab      db "D.T.OS-0.01"
 30     BS_FileSysType db "FAT12   "
 31 
 32 start:
 33     mov ax, cs
 34     mov ss, ax
 35     mov ds, ax
 36     mov es, ax
 37     mov sp, BaseOfStack
 38     
 39     mov si, MsgStr
 40     mov di, DEST
 41     mov cx, MsgLen
 42     
 43     call MemCmp
 44     
 45     cmp cx, 0
 46     jz label
 47     jmp last
 48     
 49     
 50 label:
 51     mov bp, MsgStr
 52     mov cx, MsgLen
 53     
 54     call Print
 55     
 56 output:    
 57     mov bp, MsgStr
 58     mov cx, MsgLen
 59     call Print
 60     
 61 last:
 62     hlt
 63     jmp last    
 64 
 65 
 66 ; ds:si --> source
 67 ; es:di --> destination
 68 ; cx    --> length
 69 ;
 70 ; return:
 71 ;        (cx == 0) ? equal : noequal
 72 MemCmp:
 73     push si
 74     push di
 75     push ax
 76     
 77 compare:
 78     cmp cx, 0
 79     jz equal
 80     mov al, [si]
 81     cmp al, byte [di]
 82     jz goon
 83     jmp noequal
 84 goon:
 85     inc si
 86     inc di
 87     dec cx
 88     jmp compare
 89     
 90 equal:
 91 noequal:   
 92     pop ax
 93     pop di
 94     pop si
 95     
 96     ret
 97 
 98 ; es:bp --> string address
 99 ; cx    --> string length
100 Print:
101     mov ax, 0x1301
102     mov bx, 0x0007
103     int 0x10
104     ret
105 
106 ; no parameter
107 ResetFloppy:
108     push ax
109     push dx
110     
111     mov ah, 0x00
112     mov dl, [BS_DrvNum]
113     int 0x13
114     
115     pop dx
116     pop ax
117     
118     ret
119 
120 ; ax    --> logic sector number
121 ; cx    --> number of sector
122 ; es:bx --> target address
123 ReadSector:
124     push bx
125     push cx
126     push dx
127     push ax
128     
129     call ResetFloppy
130     
131     push bx
132     push cx
133     
134     mov bl, [BPB_SecPerTrk]
135     div bl
136     mov cl, ah
137     add cl, 1
138     mov ch, al
139     shr ch, 1
140     mov dh, al
141     and dh, 1
142     mov dl, [BS_DrvNum]
143     
144     pop ax
145     pop bx
146     
147     mov ah, 0x02
148 
149 read:    
150     int 0x13
151     jc read
152     
153     pop ax
154     pop dx
155     pop cx
156     pop bx
157     
158     ret
159 
160 MsgStr db  "Hello World"    
161 MsgLen equ ($-MsgStr)
162 DEST db  "Hello World" 
163 
164 Buf:
165     times 510-($-$$) db 0x00
166     db 0x55, 0xaa
复制代码

 

  运行结果如下:

 

  上图的程序中,我们直接比较的字符串“Hello World”,如果比较成功,就将字符串打印出来。

  下面我们进行文件的查找,具体流程如下图:

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

 

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

 

  有了以上的思路后,我们直接给出查找文件的汇编程序:

复制代码
  1 org 0x7c00
  2 
  3 jmp short start
  4 nop
  5 
  6 define:
  7     BaseOfStack      equ 0x7c00
  8     RootEntryOffset  equ 19
  9     RootEntryLength  equ 14
 10 
 11 header:
 12     BS_OEMName     db "D.T.Soft"
 13     BPB_BytsPerSec dw 512
 14     BPB_SecPerClus db 1
 15     BPB_RsvdSecCnt dw 1
 16     BPB_NumFATs    db 2
 17     BPB_RootEntCnt dw 224
 18     BPB_TotSec16   dw 2880
 19     BPB_Media      db 0xF0
 20     BPB_FATSz16    dw 9
 21     BPB_SecPerTrk  dw 18
 22     BPB_NumHeads   dw 2
 23     BPB_HiddSec    dd 0
 24     BPB_TotSec32   dd 0
 25     BS_DrvNum      db 0
 26     BS_Reserved1   db 0
 27     BS_BootSig     db 0x29
 28     BS_VolID       dd 0
 29     BS_VolLab      db "D.T.OS-0.01"
 30     BS_FileSysType db "FAT12   "
 31 
 32 start:
 33     mov ax, cs
 34     mov ss, ax
 35     mov ds, ax
 36     mov es, ax
 37     mov sp, BaseOfStack
 38     
 39     mov ax, RootEntryOffset
 40     mov cx, RootEntryLength
 41     mov bx, Buf
 42     
 43     call ReadSector
 44     
 45     mov si, Target
 46     mov cx, TarLen
 47     mov dx, 0
 48     
 49     call FindEntry
 50     
 51     cmp dx, 0
 52     jz output
 53     jmp last
 54     
 55 output:    
 56     mov bp, MsgStr
 57     mov cx, MsgLen
 58     call Print
 59     
 60 last:
 61     hlt
 62     jmp last    
 63 
 64 ; es:bx --> root entry offset address
 65 ; ds:si --> target string
 66 ; cx    --> target length
 67 ;
 68 ; return:
 69 ;     (dx != 0) ? exist : noexist
 70 ;        exist --> bx is the target entry
 71 FindEntry:
 72     push di
 73     push bp
 74     push cx
 75     
 76     mov dx, [BPB_RootEntCnt]
 77     mov bp, sp
 78     
 79 find:
 80     cmp dx, 0
 81     jz noexist
 82     mov di, bx
 83     mov cx, [bp]
 84     call MemCmp
 85     cmp cx, 0
 86     jz exist
 87     add bx, 32
 88     dec dx
 89     jmp find
 90 
 91 exist:
 92 noexist:
 93     pop cx
 94     pop bp
 95     pop di
 96        
 97     ret
 98 
 99 ; ds:si --> source
100 ; es:di --> destination
101 ; cx    --> length
102 ;
103 ; return:
104 ;        (cx == 0) ? equal : noequal
105 MemCmp:
106     push si
107     push di
108     push ax
109     
110 compare:
111     cmp cx, 0
112     jz equal
113     mov al, [si]
114     cmp al, byte [di]
115     jz goon
116     jmp noequal
117 goon:
118     inc si
119     inc di
120     dec cx
121     jmp compare
122     
123 equal:
124 noequal:   
125     pop ax
126     pop di
127     pop si
128     
129     ret
130 
131 ; es:bp --> string address
132 ; cx    --> string length
133 Print:
134     mov ax, 0x1301
135     mov bx, 0x0007
136     int 0x10
137     ret
138 
139 ; no parameter
140 ResetFloppy:
141     push ax
142     push dx
143     
144     mov ah, 0x00
145     mov dl, [BS_DrvNum]
146     int 0x13
147     
148     pop dx
149     pop ax
150     
151     ret
152 
153 ; ax    --> logic sector number
154 ; cx    --> number of sector
155 ; es:bx --> target address
156 ReadSector:
157     push bx
158     push cx
159     push dx
160     push ax
161     
162     call ResetFloppy
163     
164     push bx
165     push cx
166     
167     mov bl, [BPB_SecPerTrk]
168     div bl
169     mov cl, ah
170     add cl, 1
171     mov ch, al
172     shr ch, 1
173     mov dh, al
174     and dh, 1
175     mov dl, [BS_DrvNum]
176     
177     pop ax
178     pop bx
179     
180     mov ah, 0x02
181 
182 read:    
183     int 0x13
184     jc read
185     
186     pop ax
187     pop dx
188     pop cx
189     pop bx
190     
191     ret
192 
193 MsgStr db  "No START ..."    
194 MsgLen equ ($-MsgStr)
195 Target db  "START      "
196 TarLen equ ($-Target)
197 Buf:
198     times 510-($-$$) db 0x00
199     db 0x55, 0xaa
复制代码

  如果找不到文件会打印出“No START”,如果能找到,则不打印任何字符。不打印字符的话却无法证明我们的程序是正确的,我们下面进行断点调试,看一下寄存器内容,首先使用ndisasm -o 0x7c00 boot.bin > boot.txt进行反编译,找到适合的断点。

  我们应该在第51行cmp dx, 0处对应的地方打断点,根据boot.txt文件中的内容,我们来确定断点地址,如下:

 

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

 

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

posted @ 2018-12-30 20:59  lemaden  阅读(131)  评论(0编辑  收藏  举报