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处

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

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
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直接访问,而要经过其他寄存器间接访问,如下:

 

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
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   lh03061238  阅读(136)  评论(0编辑  收藏  举报

编辑推荐:
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5
点击右上角即可分享
微信分享提示