《程序设计----到田野走一走》 现今许多初学者被误导从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 |
|