第7课 - 突破512字节的限制(中)
Posted dua677
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第7课 - 突破512字节的限制(中)相关的知识,希望对你有一定的参考价值。
突破限制的预备工作
整体思路
如何在根目录区中查找目标文件?
通过根目录项的前11个字节进行判断
内存比较
指定源起始地址(DS:SI)
指定目标起始地址(ES:DI)
判断在期望长度(CX)内每一个字节是否相等
汇编小贴士
汇编中的比较与跳转
比较:
cmp cx, 0 ;比较cx的值是否为0,并把结果记录到标志寄存器
跳转:
jz equal ; 如果比较为真(根据标志寄存器的值)就跳转到equal
访问栈空间中的栈顶数据
不能使用sp直接访问栈顶数据
通过其它通用寄存器间接访问栈顶数据
查找根目录区是否存在目标文件
加载根目录区
小结
可通过查找根目录区判断是否存在目标文件
加载根目录区至内存中(ReadSector)
遍历根目录区中的每一项(FindEntry)
通过每一项的前11个字节进行判断(MemCmp)
当目标不存在时,打印错误信息(print)
代码
1 org 0x7c00 ; 从0x7c00处开始存储代码 2 3 jmp short start ; BS_JmpBoot;短跳指令,jmp指令占用1字节,地址占用1字节;下面的nop空指令占用1字节;共3字节 4 nop 5 6 define: 7 BaseOfStack equ 0x7c00 ; 定义栈的起始地址,注意栈是从高到低增长的,先加后入栈,先出后减 8 RootEntryOffset equ 19 ; 文件数据从19逻辑扇区开始 9 RootEntryLenght equ 14 ; 目录文件项共14扇区 10 11 ; ############################################################################## 12 header: 13 BS_OEMName db "D.T.Soft" ; OEM字符,8个,不足以空格填充 14 BPB_BytsPerSec dw 512 ; 每扇区字节数 15 BPB_SecPerClus db 1 ; 每簇占用扇区数 16 BPB_RsvdSecCnt dw 1 ; Boot占用的扇区数 17 BPB_NumFATs db 2 ; FAT表的记录数 18 BPB_RootEntCnt dw 224 ; 最大根目录文件数 19 BPB_TotSec16 dw 2880 ; 逻辑扇区总数 20 BPB_Media db 0xF0 ; 媒体描述符 21 BPB_FATSz16 dw 9 ; 每个FAT占用扇区数 22 BPB_SecPerTrk dw 18 ; 每个磁道扇区数 23 BPB_NumHeads dw 2 ; 磁头数 24 BPB_HiddSec dd 0 ; 隐藏扇区数 25 BPB_TotSec32 dd 0 ; 如果BPB_TotSec16是0,则在这里记录扇区总数 26 BS_DrvNum db 0 ; 中断13的驱动器号 27 BS_Reserved1 db 0 ; 未使用 28 BS_BootSig db 0x29 ; 扩展引导标志 29 BS_VolID dd 0 ; 卷序列号 30 BS_VolLab db "D.T.OS-0.01"; 卷标,必须11个字符,不足以空格填充 31 BS_FileSysType db "FAT12 " ; 文件系统类型,必须使8个字符,不足填充空格 32 33 ; ############################################################################## 34 start: ; 汇编起始标号,类似于main()函数 35 mov ax, cs ; 设置相关的段寄存器 36 mov ss, ax 37 mov ds, ax 38 mov es, ax 39 mov sp, BaseOfStack ; 设置函数调用栈 40 41 ;mov ax, 59 ; 文件数据起始于59扇区 42 ;mov cx, 1 ; 读取1个扇区 43 ;mov bx, Buf ; 数据写入的地址 44 45 ;call ReadSector ; 调用读扇区函数(数据保存到ES:BX) 46 47 ;mov si, MsgStr 48 ;mov di, DEST 49 ;mov cx, MsgLen 50 mov ax, RootEntryOffset ; 记录数据起始扇区 51 mov cx, RootEntryLenght ; 记录数据占用扇区数 52 mov bx, Buf ; 读取的数据存放处 53 54 call ReadSector ; 读取指定扇区数据到Buf缓存 55 mov si, Target ; 要查找的文件名 56 mov cx, TarLen ; 文件名长度 57 mov dx, 0 ; 设置默认返回值 58 59 call FindEntry ; 查找文件 60 61 cmp dx, 0 ; 如果没有找到文件就输出提示,否則跳到last死循環 62 jz output 63 jmp last 64 65 ;call MemCmp 66 67 ;cmp cx, 0 68 ;jz output 69 ;jmp last 70 71 ;mov bp, Buf ; 字符串段的偏移地址,相对于ES; mov bp, MsgStr ; 输出Hello, DTOS! 72 ;mov cx, 29 ; 字符串长度 ; mov cx, MsgLen ; Test file for virtual floppy. 73 output: 74 mov bp, MsgStr 75 mov cx, MsgLen 76 call Print ; 调用字符串打印函数 77 78 last: ; 死循环 79 hlt 80 jmp last 81 82 ; ############################################################################## 83 ; es:bx --> root entry offset address 84 ; ds:si --> target string 85 ; cx --> target length 86 ; 87 ; return: 88 ; (dx != 0) ? exist : noexist 89 ; exist --> bx is the target entry 90 FindEntry: ; 查找根目录文件 91 push di 92 push bp 93 push cx 94 95 mov dx, [BPB_RootEntCnt] ; 最大根目录文件数 96 mov bp, sp ; 栈地址,不能直接将sp栈顶指针赋值给通用寄存器 97 98 find: 99 cmp dx, 0 ; 如果没有文件就跳转到noexist结束 100 jz noexist 101 mov di, bx ; bx==Buf缓存;ReadSector()已经读取数据到Buf缓存 102 mov cx, [bp] ; 借助中间寄存器获取栈顶指针,此时的bp栈顶指针指向最后入栈的cx寄存器 103 call MemCmp ; 内存匹配查找(文件查找) 104 cmp cx, 0 ; 如果还有文件就继续,否则匹配失败跳转到exist结束 105 jz exist 106 add bx, 32 ; Buf缓存地址加32,每个目录项占用32字节 107 dec dx ; dx-1,文件数减1 108 jmp find 109 110 exist: 111 noexist: 112 pop cx 113 pop bp 114 pop di 115 116 ret 117 118 ; ############################################################################## 119 ; ds:si --> source 120 ; es:di --> destination 121 ; cx --> length 122 ; 123 ; return: 124 ; (cx == 0) ? equal : noequeal 125 MemCmp: ; 内存数据对比 126 push si 127 push di 128 push ax 129 130 compare: 131 cmp cx, 0 ; 到末尾(文件名结束符)就跳转到equal 132 jz equal 133 mov al, [si] ; si源(要查找的文件名) 134 cmp al, byte [di] ; di目标(根目录区的文件名) 135 jz goon ; 匹配一个字节就跳转到goon继续循环判断 136 jmp noequal ; 不匹配就跳转到noequal,函数返回以便查找下一个文件 137 goon: 138 inc si ; 源和目标+1递增 139 inc di 140 dec cx ; 剩余次数-1递减 141 jmp compare ; 跳转到compare继续循环 142 143 equal: 144 noequal: 145 pop ax 146 pop di 147 pop si 148 149 ret 150 151 ; ############################################################################## 152 ; es:bp --> string address 153 ; cx --> string length 154 Print: ; 字符串打印函数 155 mov ax, 0x1301 ; ah=13,在Teletype电传打字机模式下输出;al=01,字符串只含字符,启用BL属性,改变光标 156 mov bx, 0x0007 ; bh页码,bl前景色;bl=07,80×25字符的2色文本 157 int 0x10 ; 打印中断 158 ret ; 函数返回 159 160 ; ############################################################################## 161 ; no parameter 162 ResetFloppy: ; 重置软盘段 163 push ax 164 push dx 165 166 mov ah, 0x00 ; 磁盘系统复位 167 mov dl, [BS_DrvNum] ; 驱动器号(0x00~0x7F软盘,0x80~0x0FF硬盘) 168 int 0x13 ; 读取磁盘的中断 169 170 pop dx 171 pop ax 172 173 ret 174 175 ; ax --> logic sector number 176 ; cx --> number of sector 177 ; es:bx --> target address 178 ReadSector: ; 读扇区段(函数) 179 push bx ; 保存相关寄存器 180 push cx 181 push dx 182 push ax 183 184 call ResetFloppy ; 重置软盘 185 186 push bx 187 push cx 188 189 mov bl, [BPB_SecPerTrk] ; 每柱面(磁道)扇区数;本段代码用于计算柱面、磁头和扇区号以及设置驱动器号 190 div bl ; 除法,被除数在AX(或者DX高位+AX地位),商在AL,余数在AH 191 mov cl, ah ; 余数,cl记录起始扇区;FAT的扇区从0开始,软盘的扇区从1开始,所以下面+1 192 add cl, 1 193 mov ch, al ; 商(逻辑柱面或磁道数),ch记录起始柱面(磁道) 194 shr ch, 1 ; 右移一位表示除以2(当前软盘只有2个磁头),因为扇区编号是由两面的柱面(磁道)组合的,然后再从外往内增大;shr移位大于1时需要借助cl寄存器; 195 mov dh, al ; 商,dh记录起始磁头 196 and dh, 1 ; 如果逻辑柱面(磁道)号是偶数就在0磁头,否则就是1磁头(目前只有2个磁头) 197 mov dl, [BS_DrvNum] ; 设置驱动器号 198 199 pop ax ; 还原要读取的扇区数,相当于原来的cx,因为cx是最后入栈的,这里是最先出栈 200 pop bx ; bx已设置为指向Buf 201 202 mov ah, 0x02 ; 0x02读扇区 203 204 read: 205 int 0x13 ; 读取磁盘的中断 206 jc read ; 若进位位(CF)被置位,表示调用失败,需要重新读取 207 208 pop ax 209 pop dx 210 pop cx 211 pop bx 212 213 ret 214 215 ; ############################################################################## 216 ;MsgStr db "Hello, DTOS!" ; 定义字符串,上面43行注释使用 217 MsgStr db "No LOADER " ; 定义字符串,上面43行注释使用 218 MsgLen equ ($-MsgStr) ; 定义上面字符串长度标号 219 ;DEST db "Hello, DTOS!" ; 測試目標文件 220 Target db "LOADER" ; 要查栈的文件名 221 TarLen equ ($-Target) ; 要查找的文件名长度 222 Buf: ; Buf缓存,数据的读取和写入空间;下面两行代码是为mbr准备的,其它读写无用无害 223 times 510-($-$$) db 0x00 224 db 0x55, 0xaa
输出
找到了文件(LOADER)
没有找到文件(LiOADER)
以上是关于第7课 - 突破512字节的限制(中)的主要内容,如果未能解决你的问题,请参考以下文章