汇编语言--1. 备份引导区

来源:百度文库 编辑:神马文学网 时间:2024/10/02 18:40:17
《程序设计----到田野走一走》
现今许多初学者被误导从Java、C# 什么的入门,书店也充斥着各种《24小时精通XXX》之类的书籍,使不少初学者产生错误的印象:似乎只要买这样一本书,就真有可
能在极短时间内成为高手。
前几天我看到国外的一篇文章,标题是“用十年时间学会编程”,而梁肇新在他的
《编程高手箴言》中则建议初学者从C语言入门,并且说只要有耐心的话,就有可能在
2~3年内成功。
而我个人的观点则是尽量从纯汇编入门,先扎好马步、练好基本功,这样入门会
慢一些,但你一旦掌握汇编后,再来学习C 语言就是易如反掌之事,再接下来你会发
现无论你想学习Java或者C#或者将来的D#之类,全都不在话下。
但在许多人的印象中(这些人不光初学者,甚至包括很多学习程序设计很长时间
的人,当然了,这些人极有可能就是从Java 之类入的门),汇编是极其可怕、极难学
习的。
其实不是这样的,多年来汇编难于学习其实很重要的一个原因是没有适合初学者
的书籍,国内汇编教材的传统都是一开始就画出密密麻麻的CPU电路图,再把指令系统
、寻址方式全部列出,再按顺序程序设计、循环程序设计、分支程序设计一路讲下去,
但基本上第一章就是初学者的终点站,这不得不说是一件悲哀的事。
直到2003年9月王爽的《汇编语言》出版后,这一切才发生了改变,可以说这是
国内第一本真正适合初学者入门自学的汇编教材,关于这本书,我在这里不想多说,
不然就有做广告之嫌,各位可到第二书店或互动出版网上看一看读者评论就知道了。
我今天的目的正是通过一个极小但极有趣的汇编程序,带大家到程序设计的田野
走一走,所谓田野,应该没有高楼大厦、没有水泥森林,这里只有泥土的芳香、清新
的空气...
先简单介绍一下背景知识:开机后,CPU自动转入FFFF:0000单元执行,然后执行
BIOS中的硬件检测和建立中断向量表,然后调用 int 19h 引导操作系统,如果从软盘
启动,int 19h 会将软盘0面0道1扇区共512字节读入内存0:7c00,然后跳转到0:7c00
处执行,这样操作系统就开始引导了。
我们的任务是写一个硬盘引导区备份和恢复工具,这样一个工具还是比较有用的,
因为病毒常常会破坏硬盘引导区。程序放在软盘的引导区里,通过软盘引导后,选择1
可将硬盘的引导区备份到软盘0面0道2扇区内,选择2可将软盘0面0道2扇区内备份好的
硬盘引导区恢复回去。
程序由安装部分和任务部分组成,用MASM将程序编译、链接后得到可执行的EXE
文件,然后在软驱中插入软盘,再在硬盘上执行此程序,程序中的安装部分就会将
任务部分写入软盘引导区,这样,你的备份工具盘就做好了,快备份一下你的硬盘
引导区吧,然后把软盘妥善保管好,说不定它真有派上用场的时候呢。
当然,如果你只是想体验一下,那就在虚拟机里试验一下好了。
用软盘启动并按下“1”进行备份后的画面如下:

程序里已经尽可能详细地作了注释,清单如下:
assume ds:data,cs:codesg
data segment
db 512 dup (0)       ;安装程序先将任务程序复制到这里,再写入软盘
data ends
codesg segment
start:
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~安装程序~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
mov ax,data
mov es,ax
mov ax,cs
mov ds,ax
;首先将引导部分复制到 es:di,即数据段 0偏移
mov si,offset br_start                 ;ds:si 指向任务程序
mov di,0                        ;es:di 复制到这里
mov cx,offset br_end-offset br_start      ;得到任务程序长度
cld
rep movsb                       ;开始复制
mov byte ptr es:[510],55h              ;引导区末尾置 AA55h
mov byte ptr es:[511],0aah
call writedisk                     ;写入软盘
mov ax,4c00h
int 21h
writedisk:
mov bx,0                        ;es:bx 写入的数据
mov ah,3                        ;3代表写
mov al,1                        ;扇区数
mov ch,0                        ;磁道号
mov cl,1                        ;扇区号
mov dh,0                        ;碰头号
mov dl,0                        ;驱动器号
int 13h
ret
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~安装程序~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~任务程序~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
br_start:
mov ax,0b800h
mov es,ax
mov cx,2000
mov bx,0
clear:                          ;清屏
mov byte ptr es:[bx],‘ ‘
add bx,2
loop clear
mov ax,cs
mov ds,ax
mov si,offset copyleft-offset br_start+7c00h  ;显示标题
mov dl,10
mov dh,1
mov cl,14
mov bx,offset echo_str-offset br_start+7c00h
call bx
mov si,offset show_str1-offset br_start+7c00h ;显示菜单
mov dl,10
mov dh,3
mov cl,10
mov bx,offset echo_str-offset br_start+7c00h
call bx
mov si,offset show_str2-offset br_start+7c00h ;显示菜单
mov dl,10
mov dh,4
mov cl,10
mov bx,offset echo_str-offset br_start+7c00h
call bx
go:
mov ah,0                        ;读取用户输入
int 16h
cmp ah,2
je $+9                      ;用户选择1,即备份
cmp ah,3
je $+3bh                        ;用户选择2,即恢复
jmp $-0eh                       ;错误选择,重新输入
backup:
;ah=2   1 键
;读取硬盘引导区到内存    0000:7e00h
mov ax,0
mov es,ax
mov bx,7e00h                    ;es:bx 内存中的数据
mov dh,0                        ;磁头号
mov ch,0                        ;磁道号
mov cl,1                        ;扇区号
mov al,1                        ;扇区数
mov dl,80h                      ;驱动器号
mov ah,2                        ;2代表读
int 13h
;将内存写到A 盘0面0道2扇区
mov dh,0                        ;磁头号
mov ch,0                        ;磁道号
mov cl,2                        ;扇区号
mov al,1                        ;扇区数
mov dl,0                        ;驱动器号
mov ah,3                        ;3代表写
int 13h
mov si,offset show_str3-offset br_start+7c00h ;显示提示信息
mov dl,10
mov dh,6
mov cl,12
mov bx,offset echo_str-offset br_start+7c00h
call bx
mov bx,offset go-offset br_start+7c00h    ;等待新的输入
jmp bx
restore:
;ah=3   2 键
;读取A 盘 0面0道2扇区 到内存 0000:7e00h
mov ax,0
mov es,ax
mov bx,7e00h                    ;es:bx 内存中的数据
mov dh,0                        ;磁头号
mov ch,0                        ;磁道号
mov cl,2                        ;扇区号
mov al,1                        ;扇区数
mov dl,0                        ;驱动器号
mov ah,2                        ;2代表读
int 13h
;将内存写到硬盘引导区
mov dh,0                        ;磁头号
mov ch,0                        ;磁道号
mov cl,1                        ;扇区号
mov al,1                        ;扇区数
mov dl,80h                      ;驱动器号
mov ah,3                        ;3代表写
int 13h
mov si,offset show_str4-offset br_start+7c00h ;显示提示信息
mov dl,10
mov dh,6
mov cl,12
mov bx,offset echo_str-offset br_start+7c00h
call bx
mov bx,offset go-offset br_start+7c00h     ;等待新的输入
jmp bx
copyleft:
db ‘Harddisk Boot Sector Backup and Restore tool‘,0
show_str1:
db ‘1) Backup  boot Sector to   floppydisk‘,0
show_str2:
db ‘2) Restore boot Sector from floppydisk‘,0
show_str3:
db ‘Backup  success,please remove floppy and restart computer...‘,0
show_str4:
db ‘Restore success,please remove floppy and restart computer...‘,0
;子函数,按给定参数显示字符串
;ds:[si]  指向字符串首地址
;dl   列,0~79
;dh   行,0~24
;cl   颜色
echo_str:
push ax    ;进入子函数的第一件事,把所有子函数中用到的寄存器入栈
push bx
push cx
push si
mov ax,0b800h
mov es,ax
;根据参数计算行列
;bx=dh*160+dl*2
mov al,dh                       ;计算行
mov ah,160
mul ah
mov bx,ax                       ;保存计算结果
mov al,dl                       ;计算列
mov ah,2
mul ah
add bx,ax                       ;得到最终计算结果
mov ah,cl                       ;颜色
mov ch,0
s:
mov al,ds:[si]
mov cl,al
jcxz ok                         ;是0则退出
mov byte ptr es:[bx],al
inc bx
mov byte ptr es:[bx],ah
inc bx
inc si
jmp s
ok:
pop si                      ;结束子函数
pop cx
pop bx
pop ax
ret
br_end:
nop
codesg ends
end start