9、主引导程序控制权的转移

BootLoader内存布局

低----->高


0x7c00之前是栈空间,0x9000之后是Loader程序,之间是主引导程序。最终会将控制权从主引导程序(boot程序)跳转到0x9000处向后执行,也就是将控制权从boot程序转交给loader程序。fat表在0x7e00到0x9000之间,4kB。

通过fat边加载文件内容:


bx寄存器指向fat表的起始地址,之后EntryItem(目标文件的文件目录项)+0x1A,bp指向了DIR_FstClus目标文件所在的第一簇,因为fat12里边1簇就是一个扇区,所以DIR_FstClus指向了目标文件的第一个扇区,si指向了0x9000,(目标地址),然后循环,读扇区内容,指定逻辑扇区号dx+31(对应33+j-2),备份dx,bx值,pop cx,将dx中的值放到cx中,然后调用FatVec获取下一个扇区。si向后偏移512字节,准备读取下一个扇区。

试验步骤:

1.在虚拟软盘中创建体积较大的文本文件(Loader)

2.将Loader的内容加载到BaseOfLoader(0x9000)地址处

3、打印Loader中的文本(判断加载是否完全)

cx必须对应的是表项下标、

dx是读取到的值,与0xFF7比较,如果小于,接着循环。

代码量超过了512字节,调整

读取文件长度,在0x1c的地方 mov cx, [EntryItem+ 0x1C]

到虚拟软盘查看:将虚拟软盘挂载到linux中去:

sudo mount -o loop data.img /mnt/hgfs/

打开loader这个文件:

sudo gedit /mnt/hgfs/loader 

将这个虚拟软盘从当前linux中移除掉:

sudo umount /mnt/hgfs/

将代码复制到d.t.中,大小是4kb,一个扇区放不下,结果打印一下,是代码,这样就把文件内容加载到内存中了。

移除,重新运行查看。make  bochs  6  c

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
 ;  pop dx
 ;  mov cx, dx
call FatVec
cmp dx,0xFF7
jnb BaseOfLoader
add si, 512

jmp loading

接下来创建一个loader程序,

第一个Loader程序:

起始地址0x9000(org 0x9000)

通过int 0x10在屏幕上打印字符串

汇编小贴士:标志寄存器


如果ZF为1,就执行跳转。

汇编小贴士:

jxx代表了一个指令族,功能是根据标志位进行跳转。

jo:当OF为1则跳转

jc:当CF为1则跳转

jns:当SF不为1则跳转

jz:当ZF为1则跳转

je:比较结果为相等则跳转(即:jz)

试验:

org 0x9000  当前程序放到这个地址处进行执行

begin:
mov si, msg  si指向要打印的代码
print:
mov al, [si]
add si, 1
cmp al, 0x00
je end       相等结束
mov ah, 0x0E

mov bx, 0x0F

int 0x10

jmp print

//mov ax, 0x1301 打印不是这个吗?

//mov bx, 0x0007

//int 0x10

end:
hlt
jmp end
msg:
db 0x0a,0x0a
db "hello ,d.s.os"
db 0x0a,0x0a

db 0x00

保存之后编译, nasm loader.asm -o loader

为了说明问题:反编译

ndisasm -o 0x9000 loader > loader.txt  从地址0x9000处向后反编译

反编译结果:

00009000  BE1B90     mov si,0x901b
00009003  8A04         mov al,[si]
00009005  81C60100   add si,0x1
00009009  3C00           cmp al,0x0对应 cmp al, 0x00
0000900B  740A          jz 0x9017 ====je编译器将je作为jz

0000900D  B40E          mov ah,0xe

然后将loader拷贝到软盘中,然后 从boot跳转到loader来进行执行,,

将当前虚拟软盘挂载到linux中:

sudo mount -o loop data.img /mnt/hgfs/

然后将loader拷贝过去:

sudo cp loader /mnt/hgfs/loader

之后将虚拟软盘卸载下来:

sudo umount /mnt/hgfs

接下来运行:bochs 6 c

然后将data虚拟软盘文件拷贝到E盘,然后在虚拟机运行

改写makefile:

加上虚拟软盘在linux中的挂载路径IMG_PATH := /mnt/hgfs

编译:nasm $^ -o $@

编译完boot程序后,将boot程序烧写到虚拟软盘中。

dd if=@ of=$(IMG) bs=512 count=1 conv=notrunc

接下来定义规则编写loader程序,

编译完之后将结果拷贝到虚拟软盘中,所以说先进行挂载:

sudo mount -o loop $(IMG) $(IMG_PATH)

挂载好之后进行拷贝:

sudo cp $@ $(IMG_PATH)/$@

拷贝完之后卸载:sudo umount $(IMG_PATH)

clean也要变化:

$(RM) $(IMG) $(BOOT_OUT) $(LOADER_OUT)

.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==>w.s.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

运行结果:只有当Target db  "LOADER     "是这个的时候在会打印w.s.os(或者是6个空格),当内容改变成别的时候就不会打印这个,会打印no leader(控制权没有转移)

小结:

Boot需要进行重构保证在512字节内完成功能。

在汇编程序中尽量确保函数调用前后通用寄存器的状态不变、

Boot成功加载Loader后将控制权转移。

Loader程序没有代码体积上的限制。


你可能感兴趣的:(9、主引导程序控制权的转移)