第八课 突破512字节的限制--下

  上一节我们进行了文件的查找实验,文件查找成功了,这一节,我们将文件的内容加载进内存,再一次将整体的流程给出如下:

  读取文件的内容时,我们需要根据FAT表找到存储文件内容的每一个扇区,然后进行内容的读取,在上一节中,我们将整个目录区的内容加载到了内存并根据文件名找到了所在的目录项,为了节省内存,我们将找到的目录项拷贝到另一片内存区域中,因为这个目录项中还有我们需要的内容,比如文件的起始扇区号等。而原来加载目录区的那一部分内存便可以另作他用,比如可以将FAT表加载到该区域。

  目标文件的目录信息如下:

  内存拷贝时,为了防止已经拷贝的内容将原来还没有拷贝的内容覆盖,我们需要考虑一下拷贝的方向,示意图如下:

  当源地址小于等于目标地址时,要从后向前拷贝,如上图中左半部,当源地址大于目标地址时,要从头部向尾部拷贝,如上图右半部。

  用到的汇编指令如下所示:

  

  下面直接给出内存拷贝的汇编代码:

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

  以上程序将Target处的字符串拷贝到了MsgStr处,然后将MsgStr处的内容打印出来,结果如下:

  下一步,我们进行FAT表项的读取,并根据表项的内容加载文件数据,FAT表项中每个表项占用1.5个字节,即使用3个字节表示两个表项,如下图所示:

  以前读取a.img的实验中,我们是将FAT表项完全读取后做了一次转换,生成了一个向量,向量中的每一项占用2个字节,那是一次性将所有FAT表项转换好的,而在我们的汇编程序中,我们使用动态组装的方法,即每用到一个表项就进行临时组装,组装后的FAT表项的下标和起始字节的关系图如下:

  

  组装时用到的关系式如下所示:

  需要用到的乘法汇编指令如下:

   

  我们先打开之前写的读取a.img的Qt程序,添加一行,如下所示:

 

  我们新添加了224行,将数据所在的扇区号分别打印出来,运行程序,得到如下结果:

  上图中只打印出了4,说明数据只存在第4扇区,也就是222行的循环只循环了一次,第二次循环是vec[j]已经不再小于0xFF7,也就是FAT表项不再是一个有效项,而是一个结束项。

  下面给出汇编程序:

  1 org 0x7c00
  2 
  3 jmp short start
  4 nop
  5 
  6 define:
  7     BaseOfStack      equ 0x7c00
  8     BaseOfLoader     equ 0x9000
  9     RootEntryOffset  equ 19
 10     RootEntryLength  equ 14
 11     EntryItemLength  equ 32
 12     FatEntryOffset   equ 1
 13     FatEntryLength   equ 9
 14 
 15 header:
 16     BS_OEMName     db "D.T.Soft"
 17     BPB_BytsPerSec dw 512
 18     BPB_SecPerClus db 1
 19     BPB_RsvdSecCnt dw 1
 20     BPB_NumFATs    db 2
 21     BPB_RootEntCnt dw 224
 22     BPB_TotSec16   dw 2880
 23     BPB_Media      db 0xF0
 24     BPB_FATSz16    dw 9
 25     BPB_SecPerTrk  dw 18
 26     BPB_NumHeads   dw 2
 27     BPB_HiddSec    dd 0
 28     BPB_TotSec32   dd 0
 29     BS_DrvNum      db 0
 30     BS_Reserved1   db 0
 31     BS_BootSig     db 0x29
 32     BS_VolID       dd 0
 33     BS_VolLab      db "D.T.OS-0.01"
 34     BS_FileSysType db "FAT12   "
 35 
 36 start:
 37     mov ax, cs
 38     mov ss, ax
 39     mov ds, ax
 40     mov es, ax
 41     mov sp, BaseOfStack
 42     
 43     mov ax, RootEntryOffset
 44     mov cx, RootEntryLength
 45     mov bx, Buf
 46     
 47     call ReadSector
 48     
 49     mov si, Target
 50     mov cx, TarLen
 51     mov dx, 0
 52     
 53     call FindEntry
 54     
 55     cmp dx, 0
 56     jz output
 57     
 58     mov si, bx
 59     mov di, EntryItem
 60     mov cx, EntryItemLength
 61     
 62     call MemCpy
 63     
 64     mov ax, FatEntryLength      ; FAT zhan yong 9 ge Sector
 65     mov cx, [BPB_BytsPerSec]    ; mei ge Sector de da xiao
 66     mul cx                      ; xiang cheng hou de dao FAT biao de zong zi jie da xiao,cun                                     ; zai ax zhong
 67     mov bx, BaseOfLoader        ; jia zai FAT biao de qi shi di zhi
 68     sub bx, ax
 69     
 70     mov ax, FatEntryOffset
 71     mov cx, FatEntryLength
 72     
 73     call ReadSector
 74     
 75     mov cx, [EntryItem + 0x1A]  ;huo qu qi shi cu hao
 76     
 77     call FatVec
 78     
 79     jmp last
 80     
 81 output:    
 82     mov bp, MsgStr
 83     mov cx, MsgLen
 84     call Print
 85     
 86 last:
 87     hlt
 88     jmp last    
 89 
 90 
 91 ; cx --> index
 92 ; bx --> fat table address
 93 ;
 94 ; return:
 95 ;     dx --> fat[index]
 96 FatVec:
 97     mov ax, cx
 98     mov cl, 2
 99     div cl
100     
101     push ax
102     
103     mov ah, 0
104     mov cx, 3
105     mul cx
106     mov cx, ax
107     
108     pop ax
109     
110     cmp ah, 0
111     jz even
112     jmp odd
113 
114 even:    ; FatVec[j] = ( (Fat[i+1] & 0x0F) << 8 ) | Fat[i];
115     mov dx, cx
116     add dx, 1
117     add dx, bx
118     mov bp, dx
119     mov dl, byte [bp]
120     and dl, 0x0F
121     shl dx, 8
122     add cx, bx
123     mov bp, cx
124     or  dl, byte [bp]
125     jmp return
126     
127 odd:     ; FatVec[j+1] = (Fat[i+2] << 4) | ( (Fat[i+1] >> 4) & 0x0F );
128     mov dx, cx
129     add dx, 2
130     add dx, bx
131     mov bp, dx
132     mov dl, byte [bp]
133     mov dh, 0
134     shl dx, 4
135     add cx, 1
136     add cx, bx
137     mov bp, cx
138     mov cl, byte [bp]
139     shr cl, 4
140     and cl, 0x0F
141     mov ch, 0
142     or  dx, cx
143 
144 return: 
145     ret
146 
147 ; ds:si --> source
148 ; es:di --> destination
149 ; cx    --> length
150 MemCpy:
151     push si
152     push di
153     push cx
154     push ax
155     
156     cmp si, di
157     
158     ja btoe
159     
160     add si, cx
161     add di, cx
162     dec si
163     dec di
164     
165     jmp etob
166     
167 btoe:
168     cmp cx, 0
169     jz done
170     mov al, [si]
171     mov byte [di], al
172     inc si
173     inc di
174     dec cx
175     jmp btoe
176     
177 etob: 
178     cmp cx, 0
179     jz done
180     mov al, [si]
181     mov byte [di], al
182     dec si
183     dec di
184     dec cx
185     jmp etob
186 
187 done:   
188     pop ax
189     pop cx
190     pop di
191     pop si
192     ret
193 
194 ; es:bx --> root entry offset address
195 ; ds:si --> target string
196 ; cx    --> target length
197 ;
198 ; return:
199 ;     (dx !=0 ) ? exist : noexist
200 ;        exist --> bx is the target entry
201 FindEntry:
202     push di
203     push bp
204     push cx
205     
206     mov dx, [BPB_RootEntCnt]
207     mov bp, sp
208     
209 find:
210     cmp dx, 0
211     jz noexist
212     mov di, bx
213     mov cx, [bp]
214     call MemCmp
215     cmp cx, 0
216     jz exist
217     add bx, 32
218     dec dx
219     jmp find
220 
221 exist:
222 noexist: 
223     pop cx
224     pop bp
225     pop di
226        
227     ret
228 
229 ; ds:si --> source
230 ; es:di --> destination
231 ; cx    --> length
232 ;
233 ; return:
234 ;        (cx == 0) ? equal : noequal
235 MemCmp:
236     push si
237     push di
238     push ax
239     
240 compare:
241     cmp cx, 0
242     jz equal
243     mov al, [si]
244     cmp al, byte [di]
245     jz goon
246     jmp noequal
247 goon:
248     inc si
249     inc di
250     dec cx
251     jmp compare
252     
253 equal: 
254 noequal:   
255     pop ax
256     pop di
257     pop si
258     
259     ret
260 
261 ; es:bp --> string address
262 ; cx    --> string length
263 Print:
264     mov dx, 0
265     mov ax, 0x1301
266     mov bx, 0x0007
267     int 0x10
268     ret
269 
270 ; no parameter
271 ResetFloppy:
272     push ax
273     push dx
274     
275     mov ah, 0x00
276     mov dl, [BS_DrvNum]
277     int 0x13
278     
279     pop dx
280     pop ax
281     
282     ret
283 
284 ; ax    --> logic sector number
285 ; cx    --> number of sector
286 ; es:bx --> target address
287 ReadSector:
288     push bx
289     push cx
290     push dx
291     push ax
292     
293     call ResetFloppy
294     
295     push bx
296     push cx
297     
298     mov bl, [BPB_SecPerTrk]
299     div bl
300     mov cl, ah
301     add cl, 1
302     mov ch, al
303     shr ch, 1
304     mov dh, al
305     and dh, 1
306     mov dl, [BS_DrvNum]
307     
308     pop ax
309     pop bx
310     
311     mov ah, 0x02
312 
313 read:    
314     int 0x13
315     jc read
316     
317     pop ax
318     pop dx
319     pop cx
320     pop bx
321     
322     ret
323 
324 MsgStr db  "No LOADER ..."    
325 MsgLen equ ($-MsgStr)
326 Target db  "START      "
327 TarLen equ ($-Target)
328 EntryItem times EntryItemLength db 0x00
329 Buf:
330     times 510-($-$$) db 0x00
331     db 0x55, 0xaa

  运行bochs,在程序的第77,79行打断点(具体方法见上节反汇编ndisasm使用方法),然后运行到第一个断点处,打印寄存器内容如下:

  可以看到ecx中的后两个字节(bochs为16字节操作)确实为4,这就是文件数据起始扇区号,edx此时还为0,继续运行到下一个断点处,打印寄存器如下:

  寄存器edx的内容为0xfff,这就是FAT表项中的内容,说明文件结束了,文件的内容只存在了一个扇区中。本节中的FatVec函数并没有完善,本节还没有进行文件内容的读取,只是根据文件数据起始扇区号,读取了下一个FAT表项的内容,下一节继续。。。

 

参考狄泰软件学院操作系统教程   

原文地址:https://www.cnblogs.com/wanmeishenghuo/p/9245070.html