《程序設(shè)計(jì)----到田野走一走》 現(xiàn)今許多初學(xué)者被誤導(dǎo)從Java、C# 什么的入門,書店也充斥著各種《24小時(shí)精通XXX》之類的書籍,使不少初學(xué)者產(chǎn)生錯(cuò)誤的印象:似乎只要買這樣一本書,就真有可 能在極短時(shí)間內(nèi)成為高手。 前幾天我看到國外的一篇文章,標(biāo)題是“用十年時(shí)間學(xué)會(huì)編程”,而梁肇新在他的 《編程高手箴言》中則建議初學(xué)者從C語言入門,并且說只要有耐心的話,就有可能在 2~3年內(nèi)成功。 而我個(gè)人的觀點(diǎn)則是盡量從純匯編入門,先扎好馬步、練好基本功,這樣入門會(huì) 慢一些,但你一旦掌握匯編后,再來學(xué)習(xí)C 語言就是易如反掌之事,再接下來你會(huì)發(fā) 現(xiàn)無論你想學(xué)習(xí)Java或者C?;蛘邔淼?span lang=EN-US twffan="done">D#之類,全都不在話下。 但在許多人的印象中(這些人不光初學(xué)者,甚至包括很多學(xué)習(xí)程序設(shè)計(jì)很長時(shí)間 的人,當(dāng)然了,這些人極有可能就是從Java 之類入的門),匯編是極其可怕、極難學(xué) 習(xí)的。 其實(shí)不是這樣的,多年來匯編難于學(xué)習(xí)其實(shí)很重要的一個(gè)原因是沒有適合初學(xué)者 的書籍,國內(nèi)匯編教材的傳統(tǒng)都是一開始就畫出密密麻麻的CPU電路圖,再把指令系統(tǒng) 、尋址方式全部列出,再按順序程序設(shè)計(jì)、循環(huán)程序設(shè)計(jì)、分支程序設(shè)計(jì)一路講下去, 但基本上第一章就是初學(xué)者的終點(diǎn)站,這不得不說是一件悲哀的事。 直到2003年9月王爽的《匯編語言》出版后,這一切才發(fā)生了改變,可以說這是 國內(nèi)第一本真正適合初學(xué)者入門自學(xué)的匯編教材,關(guān)于這本書,我在這里不想多說, 不然就有做廣告之嫌,各位可到第二書店或互動(dòng)出版網(wǎng)上看一看讀者評論就知道了。 我今天的目的正是通過一個(gè)極小但極有趣的匯編程序,帶大家到程序設(shè)計(jì)的田野 走一走,所謂田野,應(yīng)該沒有高樓大廈、沒有水泥森林,這里只有泥土的芳香、清新 的空氣... 先簡單介紹一下背景知識:開機(jī)后,CPU自動(dòng)轉(zhuǎn)入FFFF:0000單元執(zhí)行,然后執(zhí)行 BIOS中的硬件檢測和建立中斷向量表,然后調(diào)用 int 19h 引導(dǎo)操作系統(tǒng),如果從軟盤 啟動(dòng),int 19h 會(huì)將軟盤0面0道1扇區(qū)共512字節(jié)讀入內(nèi)存0:7c00,然后跳轉(zhuǎn)到0:7c00 處執(zhí)行,這樣操作系統(tǒng)就開始引導(dǎo)了。 我們的任務(wù)是寫一個(gè)硬盤引導(dǎo)區(qū)備份和恢復(fù)工具,這樣一個(gè)工具還是比較有用的, 因?yàn)椴《境3?huì)破壞硬盤引導(dǎo)區(qū)。程序放在軟盤的引導(dǎo)區(qū)里,通過軟盤引導(dǎo)后,選擇1 可將硬盤的引導(dǎo)區(qū)備份到軟盤0面0道2扇區(qū)內(nèi),選擇2可將軟盤0面0道2扇區(qū)內(nèi)備份好的 硬盤引導(dǎo)區(qū)恢復(fù)回去。 程序由安裝部分和任務(wù)部分組成,用MASM將程序編譯、鏈接后得到可執(zhí)行的EXE 文件,然后在軟驅(qū)中插入軟盤,再在硬盤上執(zhí)行此程序,程序中的安裝部分就會(huì)將 任務(wù)部分寫入軟盤引導(dǎo)區(qū),這樣,你的備份工具盤就做好了,快備份一下你的硬盤 引導(dǎo)區(qū)吧,然后把軟盤妥善保管好,說不定它真有派上用場的時(shí)候呢。 當(dāng)然,如果你只是想體驗(yàn)一下,那就在虛擬機(jī)里試驗(yàn)一下好了。 用軟盤啟動(dòng)并按下“1”進(jìn)行備份后的畫面如下: 程序里已經(jīng)盡可能詳細(xì)地作了注釋,清單如下: assume ds:data,cs:codesg data segment db 512 dup (0) ;安裝程序先將任務(wù)程序復(fù)制到這里,再寫入軟盤 data ends codesg segment start: ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~安裝程序~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ mov ax,data mov es,ax mov ax,cs mov ds,ax ;首先將引導(dǎo)部分復(fù)制到 es:di,即數(shù)據(jù)段 0偏移 mov si,offset br_start ;ds:si 指向任務(wù)程序 mov di,0 ;es:di 復(fù)制到這里 mov cx,offset br_end-offset br_start ;得到任務(wù)程序長度 cld rep movsb ;開始復(fù)制 mov byte ptr es:[510],55h ;引導(dǎo)區(qū)末尾置 AA55h mov byte ptr es:[511],0aah call writedisk ;寫入軟盤 mov ax,4c00h int 21h writedisk: mov bx,0 ;es:bx 寫入的數(shù)據(jù) mov ah,3 ;3代表寫 mov al,1 ;扇區(qū)數(shù) mov ch,0 ;磁道號 mov cl,1 ;扇區(qū)號 mov dh,0 ;碰頭號 mov dl,0 ;驅(qū)動(dòng)器號 int 13h ret ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~安裝程序~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~任務(wù)程序~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 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 ;顯示標(biāo)題 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,即恢復(fù) jmp $-0eh ;錯(cuò)誤選擇,重新輸入 backup: ;ah=2 1 鍵 ;讀取硬盤引導(dǎo)區(qū)到內(nèi)存 0000:7e00h mov ax,0 mov es,ax mov bx,7e00h ;es:bx 內(nèi)存中的數(shù)據(jù) mov dh,0 ;磁頭號 mov ch,0 ;磁道號 mov cl,1 ;扇區(qū)號 mov al,1 ;扇區(qū)數(shù) mov dl,80h ;驅(qū)動(dòng)器號 mov ah,2 ;2代表讀 int 13h ;將內(nèi)存寫到A 盤0面0道2扇區(qū) mov dh,0 ;磁頭號 mov ch,0 ;磁道號 mov cl,2 ;扇區(qū)號 mov al,1 ;扇區(qū)數(shù) mov dl,0 ;驅(qū)動(dòng)器號 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扇區(qū) 到內(nèi)存 0000:7e00h mov ax,0 mov es,ax mov bx,7e00h ;es:bx 內(nèi)存中的數(shù)據(jù) mov dh,0 ;磁頭號 mov ch,0 ;磁道號 mov cl,2 ;扇區(qū)號 mov al,1 ;扇區(qū)數(shù) mov dl,0 ;驅(qū)動(dòng)器號 mov ah,2 ;2代表讀 int 13h ;將內(nèi)存寫到硬盤引導(dǎo)區(qū) mov dh,0 ;磁頭號 mov ch,0 ;磁道號 mov cl,1 ;扇區(qū)號 mov al,1 ;扇區(qū)數(shù) mov dl,80h ;驅(qū)動(dòng)器號 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 ;子函數(shù),按給定參數(shù)顯示字符串 ;ds:[si] 指向字符串首地址 ;dl 列,0~79 ;dh 行,0~24 ;cl 顏色 echo_str: push ax ;進(jìn)入子函數(shù)的第一件事,把所有子函數(shù)中用到的寄存器入棧 push bx push cx push si mov ax,0b800h mov es,ax ;根據(jù)參數(shù)計(jì)算行列 ;bx=dh*160+dl*2 mov al,dh ;計(jì)算行 mov ah,160 mul ah mov bx,ax ;保存計(jì)算結(jié)果 mov al,dl ;計(jì)算列 mov ah,2 mul ah add bx,ax ;得到最終計(jì)算結(jié)果 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 ;結(jié)束子函數(shù) pop cx pop bx pop ax ret br_end: nop codesg ends end start |
|