6、突破512字节的限制一

辅助函数-->字符串打印,软盘读取

问题:主引导程序中如何进行字符串打印?

BIOS中的字符串打印:

指定打印参数(AX=0X1301,BX=0x0007)

指定字符串的内存地址(ES:BP=串地址)段地址和段内偏移地址来指定目标字符串的内存地址

指定字符串的长度(CX=串长度)

中断调用(int 0x10)

字符串打印示例:

//指定字符串地址:

mov ax, msg(字符串在段内偏移地址)

mov bp, ax

mov ax, ds  段地址

mov es, ax

//指定字符串长度:

mov cx, 6

//指定打印参数

mov ax, 0x1301

mov bx,0x0007

int 0x10

汇编小贴士:

汇编中可以定义函数(函数名使用标签定义):

call function  函数调用

函数体的最后一条指令为ret.  返回指令

如果代码中定义了函数,那么需要定义栈空间:

用于保存关键寄存器的值,栈顶地址通过sp寄存器保存

汇编小贴士:

汇编中的“常量定义”(equ)

用法:Const equ 0x7c00; #define Const 0x7c00

与dx(db,dw,dd)的区别:dx定义占用相应的内存空间。equ定义不会占用任何空间。

定义打印函数:

asm 主引导程序源代码

bin 主引导程序编译得到的二进制代码

IMG 虚拟软盘文件

取代一系列操作makefile:

.PHONY : all clean rebuild
SRC := boot.asm
OUT := boot.bin
IMG := data.img
RM := rm -fr
all : $(OUT) $(IMG)
dd if=$(OUT) of=$(IMG) bs=512 count=1 conv=notrunc
@echo "Success!"
$(IMG) :
bximage $@ -q -fd -size=1.44
$(OUT) : $(SRC)
nasm $^ -o $@
clean :
$(RM) $(IMG) $(OUT)
rebuild :
@$(MAKE) clean

@$(MAKE) all

主引导程序:

short  :短跳转

jmp占一个字节,start占一个字节,另一个用空指令nop填充

为什么前边有三个字节:因为定义的文件头不是可执行的代码,不是啊,所以必须跳过这段头信息,跳到可执行代码处执行。

问题:主引导程序中如何读取指定扇区处的数据?

直接操作硬件:直接操作软驱去读软盘。

软盘的构造:

一个软盘有2个盘面,,每个盘面对应一个磁头。

每一个盘面被划分为若干个圆圈,成为柱面(磁道)。

每一个柱面被划分为若干个扇区,每个扇区512字节。

3.5寸软盘的数据特性:

每个盘面一共80个柱面(编号为0-79)

每个柱面有18个扇区(编号1-18)

存储大小:2*80*18*512=1474560 Bytes=1440kB

软盘数据的读取:

软盘数据以扇区(512字节)为单位进行读取

指定数据所在位置的磁头号,柱面号,扇区号

计算公式:

逻辑扇区号/柱面扇区数(18)=商Q  磁头号:Q&1 柱面号:Q>>1  余R->扇区号:R+1

怎么读,怎么具体拿到数据:

BIOS中的软盘数据读取(int 0x13):


软盘数据读取流程:

指定逻辑扇区号(AX)指定读取扇区数(CX)-->指定内存位置(ES:BX)-->重置软驱状态-->根据逻辑扇区号计算:柱面号,磁头号,扇区号-->int 0x13-->ret

这样数据就读取到内存中了。

汇编小贴士:

汇编中的16位除法操作(div):

被除数放到AX寄存器,除数放到通用寄存器或内存单元(8位),结果:商位于AL,余数位于AH。

磁盘数据的读取:

如何测试呢?将虚拟软盘文件拖到windows中,

0x4400处有我们的字符,计算在那个扇区,4400的16进制除以512得34扇区(逻辑扇区号)的第0字节处。

如果对汇编不熟悉怎么办?

断点调试:ndisasm -o 0x7c00 boot.bin > boot.txt

ndisasm -o 0x7c00(从这个地址处开始) boot.bin > boot.txt(放到这个文件)

找到函数的入口地址,设置断点,在mov bl, [BPB_SecperTrk]设置断点

bochs

6

break 0x7c78  //函数入口设置断点

info break

c   //继续执行

break 0x7c81

info break

c

step

s

s

s

s

s

reg

当得到关键参数时,成功的将逻辑扇区号分解为三元组后,怎么判断分解的对不对呢?打印一下关键寄存器的值,手算一下,对不对比如验证起始扇区号对不对,起始扇区号是由34除以18得到余数之后加1来的。

主引导程序代码:

org 0x7c00
jmp short start
nop
define:  //定义栈空间
    BaseOfStack equ 0x7c00  //栈空间起始地址
header:  //FAT12文件需要的头,第0扇区主引导区,偏移是3,前边是跳转指令
    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    //指定sp栈顶指针寄存器具体值,sp指向栈的起始地址0x7c00,

//程序从低地址向高地址运行,栈起始地址为0x7c00,当函数调用时,就会出现压栈操作,那么栈的增长方向是从高地址到低地址增长,所以他是从高到低,而程序执行是从低到高,所以不会影响内存中的可执行代码,所以可以是0x7c00

    mov ax, 34   //我们要读取的逻辑扇区号为34
    mov cx, 1    //需要连续读取一个扇区
    mov bx, Buf    //读取到Buf这, 指定一下目标内存的地址
    call ReadSector    //调用readsector函数
    mov bp, Buf  //用print函数打印一下看看是不是我们期望的字符串
    mov cx, 29     //打印29字节
    call Print
last:
    hlt
    jmp last    
; es:bp --> string address
; cx    --> string length
Print:
    mov ax, 0x1301 //指定打印参数
    mov bx, 0x0007
    int 0x10
    ret
; no parameter
ResetFloppy:  //重置软驱
    push ax  //备份ah  进栈 
    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  //将cx的值暂时放到栈上
    mov bl, [BPB_SecPerTrk]  //18每个柱面扇区数,这个地方改变了bx寄存器的值,意味着目标内存地址改变了,所以需要之前两行的代码
    div bl   //除法
    mov cl, ah  //余数
    add cl, 1  //余数加1,之后cl为扇区号
    mov ch, al  //商
    shr ch, 1   //商右移一位 ,得到柱面号
    mov dh, al  
    and dh, 1  //按位与,得到磁头号
    mov dl, [BS_DrvNum]   //驱动器号
    pop ax  //将cx中的值拿出来放到ax寄存器中,al里边就有了原来cx寄存器的值,也就是读取的扇区数量
    pop bx
    mov ah, 0x02   //读操作,规定0x02
read:    
    int 0x13 //执行0x13号中断的时候有可能读取失败,失败就在读取,一直读取
    jc read  //错误标识位有没有被设置,设置了就跳转重读
    pop ax
    pop dx
    pop cx
    pop bx    
    ret
MsgStr db  "Hello, DTOS!"    
MsgLen equ ($-MsgStr)  //当前地址减去msgstr地址,两个地址的差就是上边字符串的长度
Buf:
    times 510-($-$$) db 0x00

    db 0x55, 0xaa

小结:本课编写了函数打印字符串,编写了函数打印软盘中的数据。

当汇编代码中定义了函数,那么也需要定义栈空间。其实就是指定栈空间sp寄存器的值

读取数据前,逻辑扇区号需要转化为磁盘的物理位置。

物理软盘上的数据位置由磁头号,柱面号,扇区号唯一确定。

软盘数据以扇区(512字节)为单位进行读取。

7、512字节中

突破限制的预备工作

辅助函数: (字符串打印,软盘读取)内存比较, 根目录区查找

如果要突破512字节限制:

将根目录区加载进入内存(readsect)-->在根目录区中查找目标文件-->存在:通过FAT表项将文件内存加载进入内存-->执行跳转  不存在-->打印错误信息(print函数)-->end

问题:如何在根目录区查找目标文件?

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

将文件名字在程序中指定,然后将指定的名字和每一个文件项的前11个字节进行比对,如果一样 ,就查找成功了。

内存比较:

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

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

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

汇编小贴士:

汇编中的比较与跳转:

比较:cmp cx,0 ;  比较cx的值是否为0

跳转: jz equal; 如果比较的结果为真,则跳转到equal标签处

汇编贴士:

;ds:si -->sourse

;es:di-->destination

;cx-->length

;
; return:
;        (cx == 0) ? equal : noequal

MemCmp:
    push si  //备份
    push di
    push ax
compare:
    cmp cx, 0
    jz equal  //相等跳转equal
    mov al, [si]  //将si指向的字节拿出来放到al中
    cmp al, byte [di] //al中的值与di中指向的一个字节值比较,byte取一个字节
    jz goon  //相等跳转
    jmp noequal   //跳转到不相等处
goon:
    inc si  //si++
    inc di  //di++
    dec cx  //cx--
    jmp compare
equal:
noequal:   
    pop ax
    pop di
    pop si

    ret

//cx寄存器为什么没有备份?

因为我们把cx寄存器作为返回值来使用,就没必要保存它的状态了。

r

打印寄存器值

第二个任务:

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

流程:

加载根目录区bx-->指定目标字符串si-->指定查找次数dx-->dx>0 ? yes mov di,bx mov cx,LEN(no noexist)-->Memcmp-->cx>0(no exist)-yes->add bx,32 dex dx

加载根目录区:

mov ax,19 ;从第19逻辑扇区开始

mov cx,14; 连续读取14个扇区

mov bx,Buf ;读取至Buf中

call ReadSector

汇编小贴士:

访问栈空间中的栈顶数据:

不能使用sp直接访问栈顶数据。通过其它通用寄存器间接访问栈顶数据。

push cx

mov bp,sp

;...

mov cx,[bp]; ERROR-->mov cx, [sp]

;....程序:

; 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  //老用比较函数,所以先把cx寄存器进栈
    mov dx, [BPB_RootEntCnt] //头文件中根目录区最多有BPB_RootEntCnt项
    mov bp, sp  //保存sp的值到bp中,因为反复获取cx寄存器的值,我们要反复用到目标字符串的长度
find:
    cmp dx, 0
    jz noexist
    mov di, bx //bx指向根目录区每一项的入口地址,调用函数之前保存根目录区第0项
    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

//把dx定义成了返回值,所以他的状态不需要改变

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 entr
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

小结:

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

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

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

通过每一项的前11个字节进行判断(MemCmp),如果是findEntry返回,dx寄存器的值不为0,bx寄存器就是目标项的入口地址,找不到dx寄存器的值为0.

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

8、突破下

通过FAT表项将文件内容加载进入内存。

最后的冲刺:

备份目标文件的目录信息(MemCpy)。前面将目标文件的目录信息起始地址查找到了,对我们有用的32个字节?因为根目录区中每一项占32个字节,将根目录区全部加载到内存中然而存在了浪费,所以对我们有用的32个字节拷贝到内存的另一个地方。这样就能有效利用内存了。

加载Fat表,并完成Fat表项的查找与读取(FatVec)。

第一步:内存拷贝,备份目标文件的目录信息(内存拷贝)


实现的关键要点:


坐标si<di, 原内存和目标内存有重叠,原内存地址较小,目标内存起始地址较大,这时必须从后向前进行拷贝,将原内存的最后一个字节拷贝到目标内存的最后一个字节,然后将原内存的倒数第二个字节拷贝到目标内存的倒数第二个字节,从后向前。右边的情况:si>di,这时从前向后拷贝。

重叠是需要考虑的重点情况。

汇编的小贴士:

cmp si, di

ja btoe ; if(si>di)

; ....

; ....

btoe;

; ....

; ....

ja表示 >,jna <=, jb <, jnb >=  (n  反面)

实战:创建内存拷贝函数:

Fat表项的读取:

Fat表中的每个表项占用1.5个字节,即:使用3个字节表示两个表项

第一表项,第二表项是前三个字节


FatVec[j]的“动态组装”:

j=0,2,4,6,8,...

i=j/2*3 -->(i , j均为整形数)

FatVec[j]=((Fat[i+1]& 0x0F)<<8) | Fat[i];  (偶数)

FatVec[i+1]=(Fat[i+2]<<4) | (Fat[i+1]>>4)&(0x0f);(奇数)

汇编小贴士:

汇编中的16位乘法操作(mul)

被乘数放到AL寄存器。

乘数放到通用寄存器或内存单元(8位)

相乘的结果放到AX寄存器中。

试验:fat表项读取函数:

起始簇号为4,并且一个扇区保存文件内容、

ndisasm -o 0x7c00 boot.bin > boot.txt 反编译一下

小结:内存拷贝时需要考虑进行拷贝的方向。

当si>di时,从前向后拷贝。

当si<di时,从后向前拷贝。

Fat表加载到内存中之后,需要“动态组装”表项。

Fat表中使用3个字节表示2个表项,

起始字节=表项下标/2*3-->(运算结果取整)

<bochs:1> break 0x7c8d
<bochs:2> break 0x7c90
<bochs:3> c


<bochs:4> r
eax: 0x00000001 1
ecx: 0x00000004 4
edx: 0x00000000 0
ebx: 0x00007e00 32256
esp: 0x00007c00 31744
ebp: 0x00000000 0
esi: 0x000e7e58 949848
edi: 0x00007dd8 32216
eip: 0x00007c8d
<bochs:5> c
<bochs:6> r
eax: 0x00000002 2
ecx: 0x00007e06 32262
edx: 0x00000fff 4095
ebx: 0x00007e00 32256
esp: 0x00007c00 31744
ebp: 0x00007e06 32262
esi: 0x000e7e58 949848
edi: 0x00007dd8 32216

eip: 0x00007c90


; ds:si --> source
; es:di --> destination
; cx    --> length
MemCpy:
    push si
    push di
    push cx
    push ax
    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:   
    pop ax
    pop cx
    pop di
    pop si

    ret

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程序没有代码体积上的限制。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值