前言:本文涉及两种代码,未安装虚拟机的参照第一种代码实现三四功能即可,
阅读下面的材料
开机后,CPU自动进入到FFFF:0单元处执行,此处有一条跳转指令。CPU执行该指令后,转去执行BIOS中的硬件系统检测和初始化程序。
初始化程序将建立BIOS所支持的中断向量,即将BIOS提供的中断例程的入口地址登记在中断向量表中。
硬件系统检测和初始化完成后,调用int 19h进行操作系统的引导。
如果设为从软盘启动操作系统,则int 19h将主要完成以下工作。
控制0号软驱,读取软盘0道0面1扇区的内容到0:7c00;
将CS:IP指向0:7c00。
软盘的0道0面1扇区中装有操作系统引导程序。int 19h将其装到0:7c00处后,设置CPU从0:7c00开始执行此处的引导程序,操作系统被激活,控制计算机。
如果在0号软驱中没有软盘,或发生软盘I/O错误,则int 19h将主要完成以下工作。
读取硬盘C的0道0面1扇区的内容到0:7c00;
将CS:IP指向0:7c00。
该程序的功能如下:
(1)列出功能选项,让用户通过键盘进行选择,界面如下:
1)reset pc ;重新启动计算机
2)start system ;引导现有的操作系统
3)clock ;进入始终程序
4)set clock ;设置时间
(2)用户输入“1”后重新启动计算机(提示:考虑ffff:0单元)
(3)用户输入“2”后引导现有的操作系统(提示:考虑硬盘C的0道0面1扇区)
(4)用户输入“3”后,执行动态显示当前日期,时间的程序
显示格式如下:年/月/日/ 时/分/秒
进入此项功能后,一直动态显示当前的时间,在屏幕上将出现时间按秒变化的效果(提示:循环读取CMOS)。
当按下F1键后,改变显示颜色:按下ESC键后,返回到主选单(提示:利用键盘中断)。
(5)用户输入“4”后可更改当前的日期,时间,更改后返回到主选单(提示:输入字符串)
以下内容进实现 3 4号功能
assume cs:code,ds:data,ss:stack
data segment
BEGIN db 512 dup(0) ;因为一个扇区字节大小为512
BEGIN_BOOT db 512 dup(0) ;2号扇区 ds:[si]->es:[di]
db 512 dup(0) ;3
db 512 dup(0) ;4
data ends
stack segment
db 128 dup(0)
stack ends
code segment
start: mov ax,stack
mov ss,ax
mov sp,128(0)
; mov bx,OFFSET Boot_end - OFFSET Boot
; call cpy_boot_toDiskA ;把上述代码复制到软盘中
call cpy_Boot
call sav_old_int9 ;因为要编写新的int9
mov bx,0
push bx
mov bx,7e00h
push bx
retf ;相当于执行 pop ip pop cs 返还到保存在0:7e00h中的 Boot代码
;ret 相当于 pop ip
mov ax,4c00h
int 21h
;int 19h 的内容: 将软盘0面0道1扇区(512)-》写入 0:7c00h cs:ip=0:7c00h
;将0面0到2扇区开始的 3个扇区中的内容 复制 到 0:7e00h cs:ip-07e00h
;先将 OFFSET Boot_end -OFFSET Boot 复制到 0面0道2扇区开始的3个扇区
;es:[bx]->复制到 1 2 3 4扇区
;==========================================================
Boot: jmp BOOT_START
;*******************************************************************
;*******************************************************************
;*******************************************************************
;数据区
OPTION_1 db '1) restart pc ',0 ;地址两个字节????
OPTION_2 db '2) start system ',0
OPTION_3 db '3) show clock ',0
OPTION_4 db '4) set clock ',0
ADDRESS_OPTION dw OFFSET OPTION_1 - OFFSET Boot + 7e00h ;ADDRESS_OPTION[0] 可以不加OFFSET的!!!
dw OFFSET OPTION_2 - OFFSET Boot + 7e00h
dw OFFSET OPTION_3 - OFFSET Boot + 7e00h
dw OFFSET OPTION_4 - OFFSET Boot + 7e00h
TIME_CMOS db 9,8,7,4,2,0 ;CMOS RAM中存储的时间信息 详情看实验16
TIME_STYLE db 'YY/MM/DD HH:MM:SS',0
STRING_STACK db 12 dup('0'),0 ;time_style 中12个字节型数据
;*******************************************************************
;*******************************************************************
;*******************************************************************
BOOT_START: call init_reg ;寄存器 对es ds赋值 es 0b800 ds 0
call clear_screen ;清屏
call show_option
jmp choose_option
mov ax,4c00h
int 21h
;==========================================================
choose_option: call clear_buff ;调用了int 16h 来处理键盘缓冲区中已经输入数据 详情看实验十七
mov ah,0 ;从数据缓存区中读取数据
int 16h ; ah 扫描码 al ASCII码
cmp al,'1'
je isChooseOne
cmp al,'2'
je isChooseTwo
cmp al,'3'
je isChooseThree
cmp al,'4'
je isChooseFour
jmp choose_option ;不用管ret
;==========================================================
isChooseOne: mov di,160*3
mov byte ptr es:[di],'1' ;es是0b800h 将写入的数据 显示到屏幕上
jmp choose_option
isChooseTwo: mov di,160*3
mov byte ptr es:[di],'2' ;es是0b800h
jmp choose_option
isChooseThree: mov di,160*3
mov byte ptr es:[di],'3' ;es是0b800h
call show_clock ;功能3:执行动态显示当前日期,时间的程序!!!
jmp BOOT_START
isChooseFour: mov di,160*3
mov byte ptr es:[di],'4' ;es是0b800h
call set_clock
jmp choose_option
;======================================================================
set_clock: call clear_string_stack
call show_string_stack
call get_string
call set_time ;修改cmos中的时间
ret
;=======================================================
set_time:
mov bx,OFFSET TIME_CMOS -Boot+7e00h
mov si,OFFSET STRING_STACK - OFFSET Boot + 7e00h
mov cx,6
setTime: mov dx,ds:[si] ;换位 bcd码
sub dh,30h ;ds:[si] ='12'
sub dl,30h ; dh ='2' dl= '1'
shl dl,1
shl dl,1
shl dl,1
shl dl,1
and dh,00001111b
or dl,dh
mov al,ds:[bx] ;传递给cmos
out 70h,al
mov al,dl
out 71h,al
add si,2
inc bx
loop setTime
ret
;=========================================================
get_string: mov si,OFFSET STRING_STACK -OFFSET Boot +7e00h
mov bx,0 ;当作栈顶
getString: call clear_buff
mov ah,0
int 16h
cmp al,'0'
jb notNumber
cmp al,'9'
ja notNumber
call char_push
call show_string_stack
jmp getString
getStringRet: ret
notNumber: cmp ah,0eh
je isBackSpace
cmp ah,1ch ;确认键
je getStringRet
jmp getString
;========================================================
isBackSpace: call char_pop
call show_string_stack
jmp getString
;=============================================================
char_pop: cmp bx,0
je charPopRet
dec bx
mov byte ptr ds:[si+bx],'0'
charPopRet: ret
;=======================================================
char_push: cmp bx,11 ;偏移地址 0-11
ja charPushRet
mov ds:[si+bx],al
inc bx
charPushRet: ret
;===========================================================
show_string_stack:
push si
push di
mov si,OFFSET STRING_STACK - OFFSET Boot +7e00h
mov di,160*4
call show_string
pop di
pop si
ret
;====================================================================
clear_string_stack:
push bx
push cx
push es
push si
push di
mov bx,OFFSET STRING_STACK -OFFSET Boot +7e00h
mov dx,3030h
mov cx,6
clearStringStack:
mov ds:[bx],dx
add bx,2
loop clearStringStack
pop di
pop si
pop es
pop cx
pop bx
ret
;==========================================================
show_clock: call show_style
call set_new_int9
mov bx,OFFSET TIME_CMOS -OFFSET Boot +7e00h
showTime: mov si,bx
mov cx,6
mov di,160*20
showDate: mov al,ds:[si]
out 70h,al ;访问CMOS端口 与cpu建立链接 十四章知识 70h为地址端口 将ds:[si] (单元号)送入端口70h out 为向此端口写入
in al,71h ;71H为数据端口 in 为向此单元读出
mov ah,al
shr ah,1
shr ah,1
shr ah,1
shr ah,1
and al,00001111b ;因4位一个字节=一个字符 因此读出时间信息 把其分别至于ah 与al中
add ah,30h
add al,30h
mov es:[di],ah
mov es:[di+2],al
add di,6 ;因还有一个 / 字符“ ” 字符 :字符
inc si
loop showDate
jmp showTime
showTimeRet: call set_old_int9 ;把原来的int 9重新设置回来
ret
;=======================================================
set_old_int9:
push bx
push es
mov bx,0
mov es,bx
cli
push es:[200h]
pop es:[9*4]
push es:[202h]
pop es:[9*4+2]
sti
pop es
pop bx
ret
;==========================================================
set_new_int9:
push bx
push es
mov bx,0
mov es,bx
cli
mov word ptr es:[9*4],OFFSET new_int9 -OFFSET Boot +7e00h
mov word ptr es:[9*4+2],0
sti
pop es
pop bx
ret
;==========================================================
new_int9: ;第十五章内容 外中断
; push bx
push ax
call clear_buff ;调用int 16h 来进行 即 把缓存区中的数据清理一下
in al,60h ;读出键盘的输入 随后引发int9中断
pushf ;开始int 9 标志寄存器入栈 设置int 9
; pushf
; pop bx
; and bh,11111100b
; push bx
; popf ;if=0 tf=0 通常不设置
call dword ptr cs:[200h] ;cs ip 入栈 相关内容在 第十章 转移地址在内存中的call指令
; ip=cs*16+200 cs=cs*16+202 从内存地址位中断类型吗*4和终端类型码*4+2 的两个子单元中读取中断处理程序的地址设置 ip和cs
cmp al,01h ;ESC
je isEsc ;此时仍有一个问题 若按了esc 确实停止了 但此时屏幕上仍然有color
;因此需要跳转到开头
cmp al,3Bh ;F1的意思
jne int9Ret
call change_time_color
int9Ret: pop ax
; pop bx
iret ;pop ip pop cs popf
;=========================================================
isEsc: pop ax ;此步的目的 即复刻int9Ret
add sp,4 ;但不同的是 不需要pop ip 与cs 直接返回showTimeRet即可
popf ;从栈中弹出数据送入标志寄存器中
jmp showTimeRet
;==========================================================
change_time_color:
push bx
push cx
push es
mov bx,0b800h
mov es,bx
mov bx,160*20+1 ;时间显示的位置
mov cx,17 ;时间字符的长度 没必要改变太多的颜色
changeTimeColor:
inc byte ptr es:[bx]
add bx,2
loop changeTimeColor
pop es
pop cx
pop bx
ret
;==========================================================
show_style:
mov si,OFFSET TIME_STYLE-OFFSET Boot +7E00h
mov di,160*20
call show_string ;可直接调用
ret
;==========================================================
clear_buff: mov ah,1 ;ah=1 即向键盘缓冲区中写入数据
int 16h
jz clearBuffRet
mov ah,0 ;ah=0 即向键盘缓冲区中读出数据
int 16h
jmp clear_buff
clearBuffRet: ret
;==========================================================
show_option:
mov bx,OFFSET ADDRESS_OPTION - OFFSET Boot + 7e00h
mov di,160*10+30*2
mov cx,4
showOption: mov si,ds:[bx] ;地址赋予si!!
call show_string
add bx,2
add di,160 ;换下一行
loop showOption
ret
;==========================================================
show_string: push dx
push ds
push es
push si
push di
showString: mov dl,ds:[si]
cmp dl,0
je showStringRet
mov es:[di],dl
add di,2
inc si
jmp showString
showStringRet:
pop di
pop si
pop es
pop ds
pop dx
ret
;==========================================================
clear_screen:
mov bx,0
mov dx,07000h
mov cx,2000
clearScreen: mov es:[bx],dx
add bx,2
loop clearScreen
ret
;==========================================================
init_reg: mov bx,0b800h
mov es,bx
mov bx,0
mov ds,bx
ret
Boot_end: nop
;==========================================================
sav_old_int9:
mov bx,0
mov es,bx
push es:[9*4] ;将原来的int 9 保存到此单元
pop es:[200h]
push es:[9*4+2]
pop es:[202h]
ret
;==========================================================
cpy_Boot:
mov bx,cs
mov ds,bx
mov si,OFFSET Boot
mov bx,0
mov es,bx
mov di,7E00H
mov cx,OFFSET Boot_end - OFFSET Boot
cld
rep movsb
ret
code ends
end start
没有虚拟机的话 写到这一步就ok了 以下代码在虚拟机下运行即可
assume cs:code,ds:data,ss:stack
data segment
BEGIN db 512 dup(0) ;因为一个扇区字节大小为512
BEGIN_BOOT db 512 dup(0) ;2号扇区 ds:[si]->es:[di]
db 512 dup(0) ;3
db 512 dup(0) ;4
data ends
stack segment
db 128 dup(0)
stack ends
code segment
start: mov ax,stack
mov ss,ax
mov sp,128(0)
mov bx,OFFSET Boot_end - OFFSET Boot
call cpy_introduce_toDiskA ;引导程序
call cpy_boot_toDiskA ;把上述代码复制到软盘中
; call cpy_Boot
; call sav_old_int9 ;因为要编写新的int9
; mov bx,0
; push bx
; mov bx,7e00h
; push bx
; retf ;相当于执行 pop ip pop cs 返还到保存在0:7e00h中的 Boot代码
;ret 相当于 pop ip
mov ax,4c00h
int 21h
;int 19h 的内容: 将软盘0面0道1扇区(512)-》写入 0:7c00h cs:ip=0:7c00h
;将0面0到2扇区开始的 3个扇区中的内容 复制 到 0:7e00h cs:ip-07e00h
;先将 OFFSET Boot_end -OFFSET Boot 复制到 0面0道2扇区开始的3个扇区
;es:[bx]->复制到 1 2 3 4扇区
;===================================================================
introduce: mov bx,0
mov ss,bx
mov sp,7c00h
call sav_old_int9
call cpy_boot_FromDiskA
mov bx,0
push bx
mov bx,7e00h
push bx
retf
;========================================================
cpy_boot_FromDiskA:
mov bx,0
mov es,bx
mov bx,7e00h
mov al,2
mov ch,0
mov cl,2
mov dl,0
mov ah,0
mov ah,2
int 13h
ret
;==========================================================
sav_old_int9:
mov bx,0
mov es,bx
push es:[9*4] ;将原来的int 9 保存到此单元
pop es:[200h]
push es:[9*4+2]
pop es:[202h]
ret
db 512 dup(0)
introduce_end: nop
;===============================================================
cpy_introduce_toDiskA:
mov bx,cs
mov es,bx
mov bx,OFFSET introduce
mov al,1
mov ch,0
mov cl,1
mov dl,0
mov dh,0
mov ah,3
int 13h
ret
;===============================================================
cpy_boot_toDiskA:
mov bx,cs
mov es,bx
mov bx,OFFSET Boot
;利用 int 13h 中断例程对磁盘进行读写
mov al,2 ;写入的扇区数 因下面代码的大小 两个512 扇区足够
mov ch,0 ;磁道号
mov cl,2 ;扇区号
mov dl,0 ;驱动器号 软驱从0开始 0:软驱A 1:软驱B 硬盘从80h开始 80h:硬盘C 81h: 硬盘D
mov dh,0 ;面号
mov ah,3 ;int 13h的3号功能表示写扇区
int 13h
ret
;==========================================================
Boot: jmp BOOT_START
;*******************************************************************
;*******************************************************************
;*******************************************************************
;数据区
OPTION_1 db '1) restart pc ',0 ;地址两个字节????
OPTION_2 db '2) start system ',0
OPTION_3 db '3) show clock ',0
OPTION_4 db '4) set clock ',0
ADDRESS_OPTION dw OFFSET OPTION_1 - OFFSET Boot + 7e00h ;ADDRESS_OPTION[0] 可以不加OFFSET的!!!
dw OFFSET OPTION_2 - OFFSET Boot + 7e00h
dw OFFSET OPTION_3 - OFFSET Boot + 7e00h
dw OFFSET OPTION_4 - OFFSET Boot + 7e00h
TIME_CMOS db 9,8,7,4,2,0 ;CMOS RAM中存储的时间信息 详情看实验16
TIME_STYLE db 'YY/MM/DD HH:MM:SS',0
STRING_STACK db 12 dup('0'),0 ;time_style 中12个字节型数据
;*******************************************************************
;*******************************************************************
;*******************************************************************
BOOT_START: call init_reg ;寄存器 对es ds赋值 es 0b800 ds 0
call clear_screen ;清屏
call show_option
jmp choose_option
mov ax,4c00h
int 21h
;==========================================================
choose_option: call clear_buff ;调用了int 16h 来处理键盘缓冲区中已经输入数据 详情看实验十七
mov ah,0 ;从数据缓存区中读取数据
int 16h ; ah 扫描码 al ASCII码
cmp al,'1'
je isChooseOne
cmp al,'2'
je isChooseTwo
cmp al,'3'
je isChooseThree
cmp al,'4'
je isChooseFour
jmp choose_option ;不用管ret
;==========================================================
isChooseOne: mov di,160*3
mov byte ptr es:[di],'1' ;es是0b800h 将写入的数据 显示到屏幕上
mov bx,0ffffh ;每次重启后都是从此处开始读入
push bx
mov bx,0
push bx
retf
jmp choose_option
isChooseTwo: mov di,160*3
mov byte ptr es:[di],'2' ;es是0b800h
call start_system
jmp choose_option
isChooseThree: mov di,160*3
mov byte ptr es:[di],'3' ;es是0b800h
call show_clock ;功能3:执行动态显示当前日期,时间的程序!!!
jmp BOOT_START
isChooseFour: mov di,160*3
mov byte ptr es:[di],'4' ;es是0b800h
call set_clock
jmp choose_option
;=================================================================
start_system: mov bx,0
mov es,bx
mov bx,7c00h
mov al,1
mov ch,0
mov cl,1
mov cl,80h ;硬盘c
mov dh,0
mov ah,2
int 13h
mov bx,0
push bx
mov bx,7c00h
push bx
retf
ret
;======================================================================
set_clock: call clear_string_stack
call show_string_stack
call get_string
call set_time ;修改cmos中的时间
ret
;=======================================================
set_time:
mov bx,OFFSET TIME_CMOS -Boot+7e00h
mov si,OFFSET STRING_STACK - OFFSET Boot + 7e00h
mov cx,6
setTime: mov dx,ds:[si] ;换位 bcd码
sub dh,30h ;ds:[si] ='12'
sub dl,30h ; dh ='2' dl= '1'
shl dl,1
shl dl,1
shl dl,1
shl dl,1
and dh,00001111b
or dl,dh
mov al,ds:[bx] ;传递给cmos
out 70h,al
mov al,dl
out 71h,al
add si,2
inc bx
loop setTime
ret
;=========================================================
get_string: mov si,OFFSET STRING_STACK -OFFSET Boot +7e00h
mov bx,0 ;当作栈顶
getString: call clear_buff
mov ah,0
int 16h
cmp al,'0'
jb notNumber
cmp al,'9'
ja notNumber
call char_push
call show_string_stack
jmp getString
getStringRet: ret
notNumber: cmp ah,0eh
je isBackSpace
cmp ah,1ch ;确认键
je getStringRet
jmp getString
;========================================================
isBackSpace: call char_pop
call show_string_stack
jmp getString
;=============================================================
char_pop: cmp bx,0
je charPopRet
dec bx
mov byte ptr ds:[si+bx],'0'
charPopRet: ret
;=======================================================
char_push: cmp bx,11 ;偏移地址 0-11
ja charPushRet
mov ds:[si+bx],al
inc bx
charPushRet: ret
;===========================================================
show_string_stack:
push si
push di
mov si,OFFSET STRING_STACK - OFFSET Boot +7e00h
mov di,160*4
call show_string
pop di
pop si
ret
;====================================================================
clear_string_stack:
push bx
push cx
push es
push si
push di
mov bx,OFFSET STRING_STACK -OFFSET Boot +7e00h
mov dx,3030h
mov cx,6
clearStringStack:
mov ds:[bx],dx
add bx,2
loop clearStringStack
pop di
pop si
pop es
pop cx
pop bx
ret
;==========================================================
show_clock: call show_style
call set_new_int9
mov bx,OFFSET TIME_CMOS -OFFSET Boot +7e00h
showTime: mov si,bx
mov cx,6
mov di,160*20
showDate: mov al,ds:[si]
out 70h,al ;访问CMOS端口 与cpu建立链接 十四章知识 70h为地址端口 将ds:[si] (单元号)送入端口70h out 为向此端口写入
in al,71h ;71H为数据端口 in 为向此单元读出
mov ah,al
shr ah,1
shr ah,1
shr ah,1
shr ah,1
and al,00001111b ;因4位一个字节=一个字符 因此读出时间信息 把其分别至于ah 与al中
add ah,30h
add al,30h
mov es:[di],ah
mov es:[di+2],al
add di,6 ;因还有一个 / 字符“ ” 字符 :字符
inc si
loop showDate
jmp showTime
showTimeRet: call set_old_int9 ;把原来的int 9重新设置回来
ret
;=======================================================
set_old_int9:
push bx
push es
mov bx,0
mov es,bx
cli
push es:[200h]
pop es:[9*4]
push es:[202h]
pop es:[9*4+2]
sti
pop es
pop bx
ret
;==========================================================
set_new_int9:
push bx
push es
mov bx,0
mov es,bx
cli
mov word ptr es:[9*4],OFFSET new_int9 -OFFSET Boot +7e00h
mov word ptr es:[9*4+2],0
sti
pop es
pop bx
ret
;==========================================================
new_int9: ;第十五章内容 外中断
; push bx
push ax
call clear_buff ;调用int 16h 来进行 即 把缓存区中的数据清理一下
in al,60h ;读出键盘的输入 随后引发int9中断
pushf ;开始int 9 标志寄存器入栈 设置int 9
; pushf
; pop bx
; and bh,11111100b
; push bx
; popf ;if=0 tf=0 通常不设置
call dword ptr cs:[200h] ;cs ip 入栈 相关内容在 第十章 转移地址在内存中的call指令
; ip=cs*16+200 cs=cs*16+202 从内存地址位中断类型吗*4和终端类型码*4+2 的两个子单元中读取中断处理程序的地址设置 ip和cs
cmp al,01h ;ESC
je isEsc ;此时仍有一个问题 若按了esc 确实停止了 但此时屏幕上仍然有color
;因此需要跳转到开头
cmp al,3Bh ;F1的意思
jne int9Ret
call change_time_color
int9Ret: pop ax
; pop bx
iret ;pop ip pop cs popf
;=========================================================
isEsc: pop ax ;此步的目的 即复刻int9Ret
add sp,4 ;但不同的是 不需要pop ip 与cs 直接返回showTimeRet即可
popf ;从栈中弹出数据送入标志寄存器中
jmp showTimeRet
;==========================================================
change_time_color:
push bx
push cx
push es
mov bx,0b800h
mov es,bx
mov bx,160*20+1 ;时间显示的位置
mov cx,17 ;时间字符的长度 没必要改变太多的颜色
changeTimeColor:
inc byte ptr es:[bx]
add bx,2
loop changeTimeColor
pop es
pop cx
pop bx
ret
;==========================================================
show_style:
mov si,OFFSET TIME_STYLE-OFFSET Boot +7E00h
mov di,160*20
call show_string ;可直接调用
ret
;==========================================================
clear_buff: mov ah,1 ;ah=1 即向键盘缓冲区中写入数据
int 16h
jz clearBuffRet
mov ah,0 ;ah=0 即向键盘缓冲区中读出数据
int 16h
jmp clear_buff
clearBuffRet: ret
;==========================================================
show_option:
mov bx,OFFSET ADDRESS_OPTION - OFFSET Boot + 7e00h
mov di,160*10+30*2
mov cx,4
showOption: mov si,ds:[bx] ;地址赋予si!!
call show_string
add bx,2
add di,160 ;换下一行
loop showOption
ret
;==========================================================
show_string: push dx
push ds
push es
push si
push di
showString: mov dl,ds:[si]
cmp dl,0
je showStringRet
mov es:[di],dl
add di,2
inc si
jmp showString
showStringRet:
pop di
pop si
pop es
pop ds
pop dx
ret
;==========================================================
clear_screen:
mov bx,0
mov dx,07000h
mov cx,2000
clearScreen: mov es:[bx],dx
add bx,2
loop clearScreen
ret
;==========================================================
init_reg: mov bx,0b800h
mov es,bx
mov bx,0
mov ds,bx
ret
Boot_end: nop
;==========================================================
cpy_Boot:
mov bx,cs
mov ds,bx
mov si,OFFSET Boot
mov bx,0
mov es,bx
mov di,7E00H
mov cx,OFFSET Boot_end - OFFSET Boot
cld
rep movsb
ret
code ends
end start



