09 主引导程序控制权的转移

 

参考

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

 

这一节,我们来真正的读取文件中的内容到内存中,首先来看一下内存布局是什么样的,如下所示:

 

  Boot占用了512字节,Fat Table占用了4KB,而真正的文件中的内容,我们把它存在0x9000开始的内存地址处。

  加载文件内容的过程如下:

 

  实验步骤如下:

  1、在虚拟软盘中创建体积较大的文本文件,使之内容大小超过一个扇区。

  2、将文件的内容加载到BaseOfLoader地址处。

  3、打印加载的内容,判断是否加载完全。

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
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
org 0x7c00
 
jmp short start
nop
 
define:
    BaseOfStack      equ 0x7c00
    BaseOfLoader     equ 0x9000
    RootEntryOffset  equ 19
    RootEntryLength  equ 14
    EntryItemLength  equ 32
    FatEntryOffset   equ 1
    FatEntryLength   equ 9
 
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
 
    mov si, bx
    mov di, EntryItem
    mov cx, EntryItemLength
 
    call MemCpy
 
    mov ax, FatEntryLength
    mov cx, [BPB_BytsPerSec]
    mul cx
    mov bx, BaseOfLoader
    sub bx, ax
 
    mov ax, FatEntryOffset
    mov cx, FatEntryLength
 
    call ReadSector
 
    mov dx, [EntryItem + 0x1A]
    mov si, BaseOfLoader
 
loading:
    mov ax, dx
    add ax, 31
    mov cx, 1
    push dx
    push bx
    mov bx, si
    call ReadSector
    pop bx
    pop cx
    call FatVec
    cmp dx, 0xFF7
    jnb output
    add si, 512
    jmp loading
 
output:
    mov bp, BaseOfLoader
    mov cx, [EntryItem + 0x1C]
    call Print
 
last:
    hlt
    jmp last
 
 
; cx --> index
; bx --> fat table address
;
; return:
;     dx --> fat[index]
FatVec:
    mov ax, cx
    mov cl, 2
    div cl
 
    push ax
 
    mov ah, 0
    mov cx, 3
    mul cx
    mov cx, ax
 
    pop ax
 
    cmp ah, 0
    jz even
    jmp odd
 
even:    ; FatVec[j] = ( (Fat[i+1] & 0x0F) << 8 ) | Fat[i];
    mov dx, cx
    add dx, 1
    add dx, bx
    mov bp, dx
    mov dl, byte [bp]
    and dl, 0x0F
    shl dx, 8
    add cx, bx
    mov bp, cx
    or  dl, byte [bp]
    jmp return
 
odd:     ; FatVec[j+1] = (Fat[i+2] << 4) | ( (Fat[i+1] >> 4) & 0x0F );
    mov dx, cx
    add dx, 2
    add dx, bx
    mov bp, dx
    mov dl, byte [bp]
    mov dh, 0
    shl dx, 4
    add cx, 1
    add cx, bx
    mov bp, cx
    mov cl, byte [bp]
    shr cl, 4
    and cl, 0x0F
    mov ch, 0
    or  dx, cx
 
return:
    ret
 
; ds:si --> source
; es:di --> destination
; cx    --> length
MemCpy:
 
    cmp si, di
 
    ja btoe
 
    add si, cx
    add di, cx
    dec si
    dec di
 
    jmp etob
 
btoe:
    cmp cx, 0
    jz done
    mov al, [si]
    mov byte [di], al
    inc si
    inc di
    dec cx
    jmp btoe
 
etob:
    cmp cx, 0
    jz done
    mov al, [si]
    mov byte [di], al
    dec si
    dec di
    dec cx
    jmp etob
 
done:
    ret
 
; 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 cx
 
    mov dx, [BPB_RootEntCnt]
    mov bp, sp
 
find:
    cmp dx, 0
    jz noexist
    mov di, bx
    mov cx, [bp]
    push si
    call MemCmp
    pop si
    cmp cx, 0
    jz exist
    add bx, 32
    dec dx
    jmp find
 
exist:
noexist:
    pop cx
 
    ret
 
; ds:si --> source
; es:di --> destination
; cx    --> length
;
; return:
;        (cx == 0) ? equal : noequal
MemCmp:
 
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:
 
    ret
 
; es:bp --> string address
; cx    --> string length
Print:
    mov dx, 0
    mov ax, 0x1301
    mov bx, 0x0007
    int 0x10
    ret
 
; no parameter
ResetFloppy:
 
    mov ah, 0x00
    mov dl, [BS_DrvNum]
    int 0x13
 
    ret
 
; ax    --> logic sector number
; cx    --> number of sector
; es:bx --> target address
ReadSector:
 
    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
 
    ret
 
MsgStr db  "No LOADER ..."
MsgLen equ ($-MsgStr)
Target db  "LOADER     "
TarLen equ ($-Target)
EntryItem times EntryItemLength db 0x00
Buf:
    times 510-($-$$) db 0x00
    db 0x55, 0xaa

95行跳转到加载文件内容的地址处,96行为文件的长度。运行bochs,可以看到文件内容全部打印出来了,结果如下:

 

 

 以上我们加载的文件只是文本内容,下面我们在文件中写入程序,并编译成可执行程序,然后将这个可执行程序文件放到虚拟软盘中,并加载到指定地址,然后跳转到这个地址执行。

  待加载文件中的内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
org 0x9000
 
begin:
    mov si, msg
 
print:
    mov al, [si]
    add si, 1
    cmp al, 0x00
    je end
    mov ah, 0x0E
    mov bx, 0x0F
    int 0x10
    jmp print
 
end:
    hlt
    jmp end
 
msg:
    db 0x0a, 0x0a
    db "Hello, D.T.OS!"
    db 0x0a, 0x0a
    db 0x00

为了方便起见,我们修改makefile,如下:

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
.PHONY : all clean rebuild
 
BOOT_SRC := boot.asm
BOOT_OUT := boot
 
LOADER_SRC := loader.asm
LOADER_OUT := loader
 
IMG := data.img
IMG_PATH := /mnt/hgfs
 
RM := rm -fr
 
all : $(IMG) $(BOOT_OUT) $(LOADER_OUT)
    @echo "Build Success ==> D.T.OS!"
 
$(IMG) :
    bximage $@ -q -fd -size=1.44
     
$(BOOT_OUT) : $(BOOT_SRC)
    nasm $^ -o $@
    dd if=$@ of=$(IMG) bs=512 count=1 conv=notrunc
     
$(LOADER_OUT) : $(LOADER_SRC)
    nasm $^ -o $@
    sudo mount -o loop $(IMG) $(IMG_PATH)
    sudo cp $@ $(IMG_PATH)/$@
    sudo umount $(IMG_PATH)
     
clean :
    $(RM) $(IMG) $(BOOT_OUT) $(LOADER_OUT)
     
rebuild :
    @$(MAKE) clean
    @$(MAKE) all

  makefile完成编译boot.asm,编译loader.asm,写入boot.bin到第一个扇区,挂载a.img到/mnt/hgfs目录,写入loader可执行文件,卸载a.img等。

  我们修改boot.asm,程序如下:

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
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
org 0x7c00
 
jmp short start
nop
 
define:
    BaseOfStack      equ 0x7c00
    BaseOfLoader     equ 0x9000
    RootEntryOffset  equ 19
    RootEntryLength  equ 14
    EntryItemLength  equ 32
    FatEntryOffset   equ 1
    FatEntryLength   equ 9
 
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
     
    mov si, bx
    mov di, EntryItem
    mov cx, EntryItemLength
     
    call MemCpy
     
    mov ax, FatEntryLength
    mov cx, [BPB_BytsPerSec]
    mul cx
    mov bx, BaseOfLoader
    sub bx, ax
     
    mov ax, FatEntryOffset
    mov cx, FatEntryLength
     
    call ReadSector
     
    mov dx, [EntryItem + 0x1A]
    mov si, BaseOfLoader
     
loading:
    mov ax, dx
    add ax, 31
    mov cx, 1
    push dx
    push bx
    mov bx, si
    call ReadSector
    pop bx
    pop cx
    call FatVec
    cmp dx, 0xFF7
    jnb BaseOfLoader
    add si, 512
    jmp loading
     
output:
    mov bp, MsgStr
    mov cx, MsgLen
    call Print
     
last:
    hlt
    jmp last   
 
 
; cx --> index
; bx --> fat table address
;
; return:
;     dx --> fat[index]
FatVec:
    mov ax, cx
    mov cl, 2
    div cl
     
    push ax
     
    mov ah, 0
    mov cx, 3
    mul cx
    mov cx, ax
     
    pop ax
     
    cmp ah, 0
    jz even
    jmp odd
 
even:    ; FatVec[j] = ( (Fat[i+1] & 0x0F) << 8 ) | Fat[i];
    mov dx, cx
    add dx, 1
    add dx, bx
    mov bp, dx
    mov dl, byte [bp]
    and dl, 0x0F
    shl dx, 8
    add cx, bx
    mov bp, cx
    or  dl, byte [bp]
    jmp return
     
odd:     ; FatVec[j+1] = (Fat[i+2] << 4) | ( (Fat[i+1] >> 4) & 0x0F );
    mov dx, cx
    add dx, 2
    add dx, bx
    mov bp, dx
    mov dl, byte [bp]
    mov dh, 0
    shl dx, 4
    add cx, 1
    add cx, bx
    mov bp, cx
    mov cl, byte [bp]
    shr cl, 4
    and cl, 0x0F
    mov ch, 0
    or  dx, cx
 
return:
    ret
 
; ds:si --> source
; es:di --> destination
; cx    --> length
MemCpy:
     
    cmp si, di
     
    ja btoe
     
    add si, cx
    add di, cx
    dec si
    dec di
     
    jmp etob
     
btoe:
    cmp cx, 0
    jz done
    mov al, [si]
    mov byte [di], al
    inc si
    inc di
    dec cx
    jmp btoe
     
etob:
    cmp cx, 0
    jz done
    mov al, [si]
    mov byte [di], al
    dec si
    dec di
    dec cx
    jmp etob
 
done:  
    ret
 
; 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 cx
     
    mov dx, [BPB_RootEntCnt]
    mov bp, sp
     
find:
    cmp dx, 0
    jz noexist
    mov di, bx
    mov cx, [bp]
    push si
    call MemCmp
    pop si
    cmp cx, 0
    jz exist
    add bx, 32
    dec dx
    jmp find
 
exist:
noexist:
    pop cx
        
    ret
 
; ds:si --> source
; es:di --> destination
; cx    --> length
;
; return:
;        (cx == 0) ? equal : noequal
MemCmp:
 
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:  
 
    ret
 
; es:bp --> string address
; cx    --> string length
Print:
    mov dx, 0
    mov ax, 0x1301
    mov bx, 0x0007
    int 0x10
    ret
 
; no parameter
ResetFloppy:
     
    mov ah, 0x00
    mov dl, [BS_DrvNum]
    int 0x13
     
    ret
 
; ax    --> logic sector number
; cx    --> number of sector
; es:bx --> target address
ReadSector:
     
    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
     
    ret
 
MsgStr db  "No LOADER ..." 
MsgLen equ ($-MsgStr)
Target db  "LOADER     "
TarLen equ ($-Target)
EntryItem times EntryItemLength db 0x00
Buf:
    times 510-($-$$) db 0x00
    db 0x55, 0xaa

第90行改为跳转到文件内容加载地址处,而不再跳转到output。第309行文件的名字也改为LOADER。

  执行make,然后运行bochs,结果如下:

 

  可以看到,文件中的可执行程序被加载并成功执行了,成功打印出字符串。此时的打印是文件中的可执行程序中print函数实现的,而不是我们的加载程序中的Print函数实现的。

  我们将data.img拷贝到windows下,在真正的机器上试一下,设置如下:

 

 

 

  启动虚拟机,我们看到了以下结果:

  我们的加载程序和可执行文件都成功运行了。

 

 

 

  

 

  

  

  

  

posted on   lh03061238  阅读(81)  评论(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
点击右上角即可分享
微信分享提示