分享

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

 skywood 2006-11-12
《程序设计----到田野走一走》

 

    现今许多初学者被误导从JavaC# 什么的入门,书店也充斥着各种《24小时精通XXX》之类的书籍,使不少初学者产生错误的印象:似乎只要买这样一本书,就真有可

在极短时间内成为高手。

    前几天我看到国外的一篇文章,标题是用十年时间学会编程,而梁肇新在他的

《编程高手箴言》中则建议初学者从C语言入门,并且说只要有耐心的话,就有可能在

23年内成功。

    而我个人的观点则是尽量从纯汇编入门,先扎好马步、练好基本功,这样入门会

慢一些,但你一旦掌握汇编后,再来学习C 语言就是易如反掌之事,再接下来你会发

现无论你想学习Java或者C#或者将来的D#之类,全都不在话下。

    但在许多人的印象中(这些人不光初学者,甚至包括很多学习程序设计很长时间

的人,当然了,这些人极有可能就是从Java 之类入的门),汇编是极其可怕、极难学

习的。

    其实不是这样的,多年来汇编难于学习其实很重要的一个原因是没有适合初学者

的书籍,国内汇编教材的传统都是一开始就画出密密麻麻的CPU电路图,再把指令系统

、寻址方式全部列出,再按顺序程序设计、循环程序设计、分支程序设计一路讲下去,

但基本上第一章就是初学者的终点站,这不得不说是一件悲哀的事。

    直到20039月王爽的《汇编语言》出版后,这一切才发生了改变,可以说这是

国内第一本真正适合初学者入门自学的汇编教材,关于这本书,我在这里不想多说,

不然就有做广告之嫌,各位可到第二书店或互动出版网上看一看读者评论就知道了。

 

    我今天的目的正是通过一个极小但极有趣的汇编程序,带大家到程序设计的田野

走一走,所谓田野,应该没有高楼大厦、没有水泥森林,这里只有泥土的芳香、清新

的空气...

    先简单介绍一下背景知识:开机后,CPU自动转入FFFF:0000单元执行,然后执行

BIOS中的硬件检测和建立中断向量表,然后调用 int 19h 引导操作系统,如果从软盘

启动,int 19h 会将软盘001扇区共512字节读入内存0:7c00,然后跳转到0:7c00

处执行,这样操作系统就开始引导了。

    我们的任务是写一个硬盘引导区备份和恢复工具,这样一个工具还是比较有用的,

因为病毒常常会破坏硬盘引导区。程序放在软盘的引导区里,通过软盘引导后,选择1

可将硬盘的引导区备份到软盘002扇区内,选择2可将软盘002扇区内备份好的

硬盘引导区恢复回去。

    程序由安装部分和任务部分组成,用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 002扇区

       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 002扇区 到内存 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   列,079

    ;dh   行,024

    ;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

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多