現今許多初學者被誤導從Java、C# 什么的入門,書店也充斥著各種《24小時精通XXX》之類的書籍,使不少初學者產生錯誤的印象:似乎只要買這樣一本書,就真有可
能在極短時間內成為高手。
前幾天我看到國外的一篇文章,標題是“用十年時間學會編程”,而梁肇新在他的
《編程高手箴言》中則建議初學者從C語言入門,并且說只要有耐心的話,就有可能在
2~3年內成功。
而我個人的觀點則是盡量從純匯編入門,先扎好馬步、練好基本功,這樣入門會
慢一些,但你一旦掌握匯編后,再來學習C 語言就是易如反掌之事,再接下來你會發(fā)
現無論你想學習Java或者C?;蛘邔淼?span lang="EN-US" twffan="done">D#之類,全都不在話下。
但在許多人的印象中(這些人不光初學者,甚至包括很多學習程序設計很長時間
的人,當然了,這些人極有可能就是從Java 之類入的門),匯編是極其可怕、極難學
習的。
其實不是這樣的,多年來匯編難于學習其實很重要的一個原因是沒有適合初學者
的書籍,國內匯編教材的傳統(tǒng)都是一開始就畫出密密麻麻的CPU電路圖,再把指令系統(tǒng)
、尋址方式全部列出,再按順序程序設計、循環(huán)程序設計、分支程序設計一路講下去,
但基本上第一章就是初學者的終點站,這不得不說是一件悲哀的事。
直到2003年9月王爽的《匯編語言》出版后,這一切才發(fā)生了改變,可以說這是
國內第一本真正適合初學者入門自學的匯編教材,關于這本書,我在這里不想多說,
不然就有做廣告之嫌,各位可到第二書店或互動出版網上看一看讀者評論就知道了。
我今天的目的正是通過一個極小但極有趣的匯編程序,帶大家到程序設計的田野
走一走,所謂田野,應該沒有高樓大廈、沒有水泥森林,這里只有泥土的芳香、清新
的空氣...
先簡單介紹一下背景知識:開機后,CPU自動轉入FFFF:0000單元執(zhí)行,然后執(zhí)行
BIOS中的硬件檢測和建立中斷向量表,然后調用 int 19h 引導操作系統(tǒng),如果從軟盤
啟動,int 19h 會將軟盤0面0道1扇區(qū)共512字節(jié)讀入內存0:7c00,然后跳轉到0:7c00
處執(zhí)行,這樣操作系統(tǒng)就開始引導了。
我們的任務是寫一個硬盤引導區(qū)備份和恢復工具,這樣一個工具還是比較有用的,
因為病毒常常會破壞硬盤引導區(qū)。程序放在軟盤的引導區(qū)里,通過軟盤引導后,選擇1
可將硬盤的引導區(qū)備份到軟盤0面0道2扇區(qū)內,選擇2可將軟盤0面0道2扇區(qū)內備份好的
硬盤引導區(qū)恢復回去。
程序由安裝部分和任務部分組成,用MASM將程序編譯、鏈接后得到可執(zhí)行的EXE
文件,然后在軟驅中插入軟盤,再在硬盤上執(zhí)行此程序,程序中的安裝部分就會將
任務部分寫入軟盤引導區(qū),這樣,你的備份工具盤就做好了,快備份一下你的硬盤
引導區(qū)吧,然后把軟盤妥善保管好,說不定它真有派上用場的時候呢。
當然,如果你只是想體驗一下,那就在虛擬機里試驗一下好了。
用軟盤啟動并按下“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 ;引導區(qū)末尾置 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 ;扇區(qū)數
mov ch,0 ;磁道號
mov cl,1 ;扇區(qū)號
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 鍵
;讀取硬盤引導區(qū)到內存 0000:7e00h
mov ax,0
mov es,ax
mov bx,7e00h ;es:bx 內存中的數據
mov dh,0 ;磁頭號
mov ch,0 ;磁道號
mov cl,1 ;扇區(qū)號
mov al,1 ;扇區(qū)數
mov dl,80h ;驅動器號
mov ah,2 ;2代表讀
int 13h
;將內存寫到A 盤0面0道2扇區(qū)
mov dh,0 ;磁頭號
mov ch,0 ;磁道號
mov cl,2 ;扇區(qū)號
mov al,1 ;扇區(qū)數
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扇區(qū) 到內存 0000:7e00h
mov ax,0
mov es,ax
mov bx,7e00h ;es:bx 內存中的數據
mov dh,0 ;磁頭號
mov ch,0 ;磁道號
mov cl,2 ;扇區(qū)號
mov al,1 ;扇區(qū)數
mov dl,0 ;驅動器號
mov ah,2 ;2代表讀
int 13h
;將內存寫到硬盤引導區(qū)
mov dh,0 ;磁頭號
mov ch,0 ;磁道號
mov cl,1 ;扇區(qū)號
mov al,1 ;扇區(qū)數
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