第7课 - 突破512字节的限制(中)

突破限制的预备工作

整体思路

如何在根目录区中查找目标文件?

通过根目录项的前11个字节进行判断

内存比较

指定源起始地址(DS:SI)

指定目标起始地址(ES:DI)

判断在期望长度(CX)内每一个字节是否相等

汇编小贴士

汇编中的比较与跳转

比较:

cmp cx, 0    ;比较cx的值是否为0,并把结果记录到标志寄存器

跳转:

jz equal          ; 如果比较为真(根据标志寄存器的值)就跳转到equal

  

访问栈空间中的栈顶数据

不能使用sp直接访问栈顶数据

通过其它通用寄存器间接访问栈顶数据

  

查找根目录区是否存在目标文件

  

加载根目录区

小结

可通过查找根目录区判断是否存在目标文件

加载根目录区至内存中(ReadSector

遍历根目录区中的每一项(FindEntry

通过每一项的前11个字节进行判断(MemCmp

当目标不存在时,打印错误信息(print

代码

  boot.asm

  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)

  

原文地址:https://www.cnblogs.com/Dua677/p/9094859.html

时间: 2025-01-17 11:39:00

第7课 - 突破512字节的限制(中)的相关文章

第六课 突破512字节的限制 上

前几节我们介绍了FAT12文件系统,制作了虚拟软盘文件a.img,并在Qt Creater中进行了文件内容的读取实验.那些读取都是使用外部的程序实现的,实际应用中,我们需要用主引导程序来实现文件的读写,主引导程序存在于主引导扇区MBR中,也就是说程序和文件是存在一张盘上的,而且这些主引导程序需要使用汇编语言实现.接下来,我们就来实现具有读取功能的主引导程序. 为了验证文件读取的正确性,我们需要在主引导程序中先实现一个字符串打印函数.BIOS已经将中断向量写到了内存的指定位置处,这其中就有能实现字

第七课 突破512字节限制--中

上一节我们写了字符串打印的函数和软盘读取函数,在软盘读取函数中,我们是直接给定了要读的逻辑扇区号,这一节我们来实现一个查找文件的功能,也就是根据给定的文件名,在根目录区中查找指定的文件是否存在,涉及到文件名的查找,就会涉及到内存的比较,因此,我们需要实现两个函数,分别为内存比较函数和根目录区查找函数. 整体的流程如下: 首先将根目录区加载到内存中的指定位置上,这里面包含了一定数目的根目录项,而根目录项的前11个字节为文件名,因此,查找文件的工作就可以进行了,我们只需要将目标文件名和每一个根目录项

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

上一节我们进行了文件的查找实验,文件查找成功了,这一节,我们将文件的内容加载进内存,再一次将整体的流程给出如下: 读取文件的内容时,我们需要根据FAT表找到存储文件内容的每一个扇区,然后进行内容的读取,在上一节中,我们将整个目录区的内容加载到了内存并根据文件名找到了所在的目录项,为了节省内存,我们将找到的目录项拷贝到另一片内存区域中,因为这个目录项中还有我们需要的内容,比如文件的起始扇区号等.而原来加载目录区的那一部分内存便可以另作他用,比如可以将FAT表加载到该区域. 目标文件的目录信息如下:

操作系统--突破512字节的限制

一.在突破512字节 Q:主引导程序中如何进行字符串打印?--直接打印A.BIOS中的字符串打印1.指定打印参数(AX=0x1301,BX=0x0007)--不借助循环2.指定字符串的内存地址(ES:BP=串地址)--通过段地址与段偏移来确定3.指定字符串的长度(CX=串长度)4.中断调用(int 0x10) B.汇编小贴士1.汇编中可以定义函数--函数名使用标签定义call function;函数体的最后一条指令为ret2.如果代码中定义了函数,那么需要定义栈空间主要用于保存关键寄存器的值:栈

分配粒度和内存页面大小(x86处理器平台的分配粒度是64K,内存页是4K,所以section都是0x1000对齐,硬盘扇区大小是512字节,所以PE文件默认文件对齐是0x200)

分配粒度和内存页面大小 x86处理器平台的分配粒度是64K,32位CPU的内存页面大小是4K,64位是8K,保留内存地址空间总是要和分配粒度对齐.一个分配粒度里包含16个内存页面. 这是个概念,具体不用自己操心,比如用VirtualAllocEx等函数,给lpAddress参数NULL系统就会自动找一个地方分配你要的内存空间.如果需要自己管理这个就累了...... 一个分配粒度是64K,这就是为什么Null指针区域和64K进入区域都是 64K的原因,刚好就是一个分配粒度.一个内存页是4K,这就是

【反射之Method】如何获取字节码对象中的方法

■获取字节码对象的方法有两种 第一种:使用字节码对象获取所有的方法(只能获取公有的方法,而不能获取私有/受保护的方法) 语法: Class.getMethods() 示例: Method[] methods = personClass.getMethods(); 第二种:使用字节码对象获取对象指定的方法,其参数:1.方法名:2.传入方法的参数类型加上".class" 语法: Class.getMethod(String name, Class<?>... parameter

mysql 字节问题,中文和数字

在mysql 5.1.5-alpha下测试得出如下结论 latin1: 1character=1byte, 1汉字=2character, 也就是说一个字段定义成 varchar(200),则它可以存储100个汉字或者200个字母. 这一点要注意,尤其是当字段内容是字母和汉字组成时,尽量假设字段内容都是由汉字组成,据此来设置字段长度 utf8: 1character=3bytes, 1汉字=1character 也就是说一个字段定义成 varchar(200),则它可以存储200个汉字或者200

第53课 被遗弃的多重继承 (中)

多重继承的问题三:多重继承可能产生多个虚函数表 #include <iostream> using namespace std; class BaseA { public: virtual void funcA() { cout << "BaseA::funcA()" << endl; } }; class BaseB { public: virtual void funcB() { cout << "BaseB::funcB(

第十一课 实模式到保护模式 中

为了解决内存访问越界的问题,英特尔发明了80286处理器,这款处理器引入了保护模式,为现代操作系统和应用程序奠定了基础,但是80286在设计上有些奇葩,例如: 段寄存器为24位,通用寄存器为16位,这样显得不伦不类. 理论上,段寄存器中的数值可以直接作为段基址.80286中16位寄存器最多访问64K的内存,为了访问16M的内存,必须不停的切换段基址. 虽然存在以上的问题,但是80286引入的保护模式是成功的,为了改进以上存在的问题,英特尔设计出了80386,这时计算机进入新时期的标志,80386