欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

匯編語(yǔ)言入門(mén)教程(這一篇足矣)

 更新時(shí)間:2020年01月19日 11:29:37   作者:hellsing  
匯編語(yǔ)言是一種最低級(jí)、最古老、不具有移植性的編程語(yǔ)言,它能夠直接訪問(wèn)計(jì)算機(jī)硬件,所以執(zhí)行效率極高,占用資源極少,想學(xué)習(xí)匯編語(yǔ)言的朋友不妨閱讀下本教程

匯編語(yǔ)言是一種最低級(jí)、最古老、不具有移植性的編程語(yǔ)言,它能夠直接訪問(wèn)計(jì)算機(jī)硬件,所以執(zhí)行效率極高,占用資源極少,一般用于嵌入式設(shè)備、驅(qū)動(dòng)程序、實(shí)時(shí)應(yīng)用、核心算法等。

匯編語(yǔ)言的缺點(diǎn)是開(kāi)發(fā)周期特別長(zhǎng),實(shí)現(xiàn)一個(gè)簡(jiǎn)單的功能都非常麻煩,已經(jīng)很少用來(lái)編寫(xiě)應(yīng)用程序了。

1 本講座以匯編初學(xué)者或?qū)R編一點(diǎn)也不了解的讀者為對(duì)象,匯編高手不屬于該范圍,但強(qiáng)烈建議高手指導(dǎo)并增補(bǔ)、修改本文。

2 任何讀者可以跟此貼,提出疑問(wèn),或解答其中的問(wèn)題,但對(duì)于所有跟貼,水貼、內(nèi)容有錯(cuò)、毫不相干貼將直接刪除,有意義的貼可能會(huì)合并到下一講的內(nèi)容中,合并后也將刪除,請(qǐng)跟貼者諒解。同時(shí)按學(xué)習(xí)進(jìn)步,請(qǐng)?zhí)釂?wèn)者逐步提,不要我沒(méi)開(kāi)口,你就問(wèn)怎么編個(gè)病毒的問(wèn)題。

3 借以?huà)伌u引玉,但不希望大家只朝我扔磚頭,希望大家踴躍思考,使之完善。

大家坐好了,。不要,不要,不要,男女同學(xué)不要相互,女同學(xué)不要對(duì)我….

1 匯編需要什么工具和程序,到哪里下載?

目前階段,匯編程序僅需要兩個(gè)程序就夠了: masm.exe,link.exe。前者是編譯程序,后者是鏈接程序。

另外,為了驗(yàn)證和調(diào)試程序,還需要一個(gè)程序debug.exe,該程序由windows本身就提供,所以就不提供下載地址了。
將二者下載后,放到某一個(gè)目錄中(任意目錄都可以),考慮到很多命令需要通過(guò)鍵盤(pán)敲入,所以建議你不要把文件放入到長(zhǎng)文件名目錄、中文目錄或很深的目錄中。比如你可以建一個(gè)“D:\Masm”目錄,并建議此后的程序都放這個(gè)目錄,此后稱(chēng)這個(gè)目錄為匯編目錄。

2 學(xué)習(xí)匯編需要有哪些編程方面的知識(shí)。

沒(méi)有任何編程方面的知識(shí),學(xué)習(xí)此語(yǔ)言等于緣木求魚(yú),所以請(qǐng)放棄學(xué)習(xí)的想法。一般來(lái)說(shuō)至少要知道如下幾點(diǎn):

*)程序的運(yùn)行邏輯結(jié)構(gòu)有順序(按語(yǔ)句依次執(zhí)行)、分支結(jié)構(gòu)(IF…THEN…ELSE…),循環(huán)結(jié)構(gòu)(FOR…NEXT)三種結(jié)構(gòu)。

*)知道什么是子程序,什么是調(diào)用。

*)匯編程序員的視角。不同編程視角編程要求是不一樣的。比如刪除文件,

>>用戶(hù)的視角是找到“刪除”按鈕或菜單,然后單擊一下即可。

>>高級(jí)程序員的視角是知道刪除的文件,并發(fā)出刪除命令。這些通過(guò)API實(shí)現(xiàn)。

>>匯編程員的視角是得到要?jiǎng)h除的文件名,找到該文件所在位置,通過(guò)調(diào)用刪除“中斷命令”進(jìn)行刪除。

>>操作系統(tǒng)開(kāi)發(fā)人員的視角則是接到刪除命令后,先找到系統(tǒng)根目錄區(qū),由根目錄區(qū)的鏈接依次找到子目錄區(qū),直到找到要?jiǎng)h除的文件,然后按照操作系統(tǒng)刪除文件的規(guī)則對(duì)該文件名進(jìn)行修改。比如DOS,只把第一個(gè)字符改成"?"。

按程序語(yǔ)句等價(jià)的角度看,一行VB的打印語(yǔ)句,用匯編實(shí)現(xiàn)大約需要一百二十多行。知道匯編語(yǔ)言的視角后就要知道,前面的道路是坎坷的,沒(méi)有耐心是不行的。想通過(guò)幾分鐘幾行程序就完成很復(fù)雜的操作不是件容易的事。

3 學(xué)匯編有什么用?

匯編產(chǎn)生于DOS時(shí)代或更早,而現(xiàn)在是Windows時(shí)代,所以可能遺憾地說(shuō):盡管還有批牛人在用匯編開(kāi)發(fā)核心級(jí)程序,但我們幾乎沒(méi)什么用,除了必要時(shí)間能拿來(lái)分析一兩個(gè)程序的部分代碼之外,別的也就沒(méi)干什么用了。并且并不是所有的匯編命令都能在windows下使用。而泛泛地追求“時(shí)髦”而學(xué)本語(yǔ)言,最后的結(jié)果是損了夫人又折兵。所以學(xué)之前你要考慮好。我勸那些為了當(dāng)“黑客”而學(xué)匯編的人就此止步。

第零講 預(yù)備知識(shí)

1 一個(gè)匯編程序的編譯過(guò)程是怎么樣的。

1)首先你需要找一個(gè)編輯器,編輯器用任何“純文本”編輯器都可以。比如記事本。編好以后保存到匯編目錄中。擴(kuò)展名為asm,比如myfirst.asm。但這里建議你找一個(gè)能顯示出當(dāng)前行的編譯器。這樣出錯(cuò)后排錯(cuò)很容易。
2)然后在DOS下進(jìn)入D:\Masm目錄中,輸入“masm myfirst.asm",如果有錯(cuò)系統(tǒng)會(huì)提示出錯(cuò)的行位置和出錯(cuò)原因。
3)然后再輸入“l(fā)ink myfirst.obj”,即可看到當(dāng)前目錄下有一個(gè)myfirst.exe程序。

2 宏匯編和匯編有什么區(qū)別嗎?

二者的區(qū)別在于前者提供宏,后者不提供。后者已找不到了,所以你可以認(rèn)為二者沒(méi)有區(qū)別。

3 機(jī)器語(yǔ)言、匯編語(yǔ)言、高級(jí)語(yǔ)言的關(guān)系

最早的計(jì)算機(jī)采用機(jī)器語(yǔ)言,這種語(yǔ)言直接用二進(jìn)制數(shù)表示,通過(guò)直接輸入二進(jìn)制數(shù),插拔電路板等實(shí)現(xiàn),這種“編程”很容易出錯(cuò),每個(gè)命令都是通過(guò)查命令表實(shí)現(xiàn),既然是通過(guò)“查表”實(shí)現(xiàn)的,那當(dāng)然也可以讓計(jì)算機(jī)來(lái)代替人查表實(shí)現(xiàn)了。于是就產(chǎn)生了匯編語(yǔ)言,所以不管別人怎么定義機(jī)、匯語(yǔ)言,我就認(rèn)為,二者是等價(jià)。后來(lái)人們發(fā)現(xiàn),用匯編語(yǔ)言編某一功能的時(shí)候,連續(xù)一段代碼都是相同或相似,于是就考慮用一句語(yǔ)言來(lái)代替這一段匯編語(yǔ)言,于是就產(chǎn)生了高級(jí)語(yǔ)言。因此,所有高級(jí)語(yǔ)言都能轉(zhuǎn)化成匯編語(yǔ)言,而所以匯編語(yǔ)言又可轉(zhuǎn)化成機(jī)器語(yǔ)言。反之,所有機(jī)器語(yǔ)言可以轉(zhuǎn)成匯編語(yǔ)言(因?yàn)槎叩葍r(jià))。但并不是所以匯編語(yǔ)言都能轉(zhuǎn)成高級(jí)語(yǔ)言。

4 計(jì)算機(jī)的組成

通常都把計(jì)算機(jī)定義成五部分:運(yùn)算器、控制器、存儲(chǔ)器、輸入系統(tǒng)、輸出系統(tǒng)。
為了簡(jiǎn)單其間,我們?nèi)绱死斫猓哼\(yùn)算器+控制器=CPU。存儲(chǔ)器=內(nèi)存(暫不包括外存,永不包括CACHE)。輸入系統(tǒng)=鍵盤(pán)(不包括鼠標(biāo)),輸入系統(tǒng)=顯示器(不包括打印機(jī),繪圖儀)。

5 寄存器和內(nèi)存的區(qū)別

寄存器在CPU中。內(nèi)存在內(nèi)存條中。前者的速度比后者快100倍左右。后面的程序要求每條指定要么沒(méi)有內(nèi)存數(shù)據(jù),要么在有一個(gè)寄存器的參與下有一個(gè)內(nèi)存數(shù)據(jù)。(也就是說(shuō),不存在只訪問(wèn)內(nèi)存的指令)。

6 匯編語(yǔ)言的計(jì)數(shù)

與生活中的計(jì)數(shù)不一樣,匯編中的計(jì)數(shù)是從0開(kāi)始的。比如16個(gè)計(jì)數(shù),則是從0~15,而不是生活中的1~16。這一點(diǎn)看起來(lái)簡(jiǎn)單,真運(yùn)算起來(lái)就不是件容易的事了,不信等著瞧。

7 進(jìn)制問(wèn)題

又與生活中不一樣的地方是進(jìn)制。切記下面的常識(shí):

*)計(jì)算機(jī)內(nèi)部存儲(chǔ)都用二進(jìn)制。
*)我們的匯編源程序默認(rèn)都用十進(jìn)制。(除非你指明類(lèi)型)
*)我們用的調(diào)試程序debug默認(rèn)的都是十六進(jìn)制。(無(wú)法指明其他類(lèi)型)
其中十六進(jìn)制的十六個(gè)個(gè)位數(shù)依次是:0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F(xiàn)。

8 進(jìn)制轉(zhuǎn)換

一個(gè)比較簡(jiǎn)單的方法是查表法。

十進(jìn)制 十六進(jìn)制 二進(jìn)制

0 0 0000
1 1 0001
2 2 0010
3 3 0011
4 4 0100
5 5 0101
6 6 0110
7 7 0111
8 8 1000
9 9 1001
10 A 1010
11 B 1011
12 C 1100
13 D 1101
14 E 1110
15 F 1111

好了,結(jié)合6,7,8三條。大家來(lái)算一個(gè)“題”。某一組數(shù)據(jù)顯示時(shí),每個(gè)數(shù)據(jù)占了四個(gè)位置,

每行共十六個(gè)。問(wèn):十六進(jìn)制的13位置在哪里(第幾行,第幾列)。

格式如下:m m m m n n n n o o o o p p p p '注:之所以沒(méi)用ABC是怕與上面十六進(jìn)制弄混。
r r r r s s s s t t t t u u u u

第一講 基礎(chǔ)知識(shí)

1 訪問(wèn)內(nèi)存

程序在內(nèi)存中,訪問(wèn)內(nèi)存是幾乎每一程序都要進(jìn)行的操作,計(jì)算機(jī)對(duì)內(nèi)存編址是線性的,也就是說(shuō)是一維的,比如256M的內(nèi)存,地址就應(yīng)該是從0~(256M-1),這個(gè)地址稱(chēng)為物理地址或絕對(duì)地址。

1.1 地址表示

但從匯編程序員的角度看,內(nèi)存卻是二維的,要說(shuō)明一個(gè)地址,需要給出兩個(gè)值,就象你在平面上指定一點(diǎn)需要說(shuō)出(X,Y)坐標(biāo)一樣,匯編程序員的內(nèi)存視角也需要兩個(gè)“坐標(biāo)”,前一個(gè)稱(chēng)為段地址(Segment),后一個(gè)稱(chēng)為偏移地址(Offset),該地址稱(chēng)為邏輯地址。
比如“1234:3DF5”就是一個(gè)地址?!?F3F:”不是一個(gè)地址,因?yàn)樗挥卸蔚刂罚瑳](méi)有編移地址。注意此后的地址都用十六進(jìn)制表示。

1.2 地址計(jì)算

前面提到,計(jì)算機(jī)編址是一維的,匯編程序員是二維的,那么二者怎么換算呢?由后者到前者的換算方法是,“段地址串”后面加個(gè)“0”,然后再加上偏移地址。
比如“1234:3DF5”(十六進(jìn)制的加減運(yùn)算參見(jiàn)相關(guān)資料)
12340 ‘串后加了一個(gè)0
3DF5
—–
16135 '注意此串仍然是十六進(jìn)制。
所以,匯編程序員眼中的地址“1234:3DF5”就是物理地址(計(jì)算機(jī)編址):16135。
知道了由后者向前者的轉(zhuǎn)換,那么由前者向后者的轉(zhuǎn)換呢?
“不知道”,為什么不知道,繼續(xù)往下看。
1.3 到底哪個(gè)地址對(duì)。
知道了1.2的地址算法后,我又發(fā)現(xiàn)一個(gè)問(wèn)題:
“1000:6135”的物理地址是多少呢? 10000+6135=16135。
“1001:6125”的物理地址呢? 10010+6125=16135。
……
那么到底哪個(gè)對(duì)呢?問(wèn)題的回答是這樣的:假設(shè)我現(xiàn)在讓你按一下“L”鍵,我可以告訴你如下幾種方法中的一種或幾種。1 請(qǐng)按一下“L”鍵; 2請(qǐng)按一下鍵盤(pán)上第四行第十個(gè)鍵;3 請(qǐng)按一下第十列中的第四個(gè)鍵;4 請(qǐng)按一下“K”右邊的鍵;5 按標(biāo)準(zhǔn)指法單擊一下右手無(wú)名指。
舉上面的例子也就是說(shuō),同一個(gè)地址有很多種表示方式,具體用哪一種,要看實(shí)際使用時(shí)的情況。但無(wú)論用哪種方式,只要能達(dá)到目的即可。(實(shí)際中該問(wèn)題一般不會(huì)受此問(wèn)題困擾,但初學(xué)時(shí)突然想不通)。
1.4 有多少內(nèi)存可以訪問(wèn)
無(wú)論是段地址還是偏移地址都是四位十六進(jìn)制(如果不夠四位,前面補(bǔ)0)。也就是說(shuō):總共可以訪問(wèn)的地址說(shuō)是:0000:0000~FFFF:FFFF。 總共FFFF0+FFFF+1=10FFF0個(gè)地址。也就是不到1M的空間。
記住如下結(jié)論:
*)不管你實(shí)際內(nèi)存有多少,目前我們只能訪問(wèn)不到1M的空間。
*)而實(shí)際上連這1M也用不完。其中上端的384K的址只能讀不能寫(xiě),只能讀,一般稱(chēng)為ROM。
*)低端的640K可以讀寫(xiě)。但這640K的低端100多K也不能隨便寫(xiě),因此DOS系統(tǒng)使用該區(qū)。
*)原來(lái)1024M的內(nèi)存,匯編程序只能使用其中400多K。這段內(nèi)存的容易相當(dāng)于一個(gè)普通文檔的大小。不過(guò)這就足夠了。

2 DEBUG的使用

先記住以下兩個(gè)命令:D命令和Q命令。前者是顯示內(nèi)存內(nèi)容,后者是退出DEBUG命令。
————-以下為抄別的人內(nèi)容—————
DEBUG.EXE程序是專(zhuān)門(mén)為分析、研制和開(kāi)發(fā)匯編語(yǔ)言程序而設(shè)計(jì)的一種調(diào)試工具,具有跟蹤程序執(zhí)行、觀察中間運(yùn)行結(jié)果、顯示和修改寄存器或存儲(chǔ)單元內(nèi)容等多種功能。它能使程序設(shè)計(jì)人員或用戶(hù)觸及到機(jī)器內(nèi)部,因此可以說(shuō)它是80X86CPU的心靈窗口,也是我們學(xué)習(xí)匯編語(yǔ)言必須掌握的調(diào)試工具。

1)DEBUG程序使用

在DOS提示符下鍵入命令:

C>DEBUG [盤(pán)符:][路徑][文件名.EXE][參數(shù)1][參數(shù)2]

這時(shí)屏幕上出現(xiàn)DEBUG的提示符“-”,表示系統(tǒng)在DEBUG管理之下,此時(shí)可以用DEBUG進(jìn)行程序調(diào)試。若所有選項(xiàng)省略,僅把DEBUG裝入內(nèi)存,可對(duì)當(dāng)前內(nèi)存中的內(nèi)容進(jìn)行調(diào)試,或者再用N和L命令,從指定盤(pán)上裝入要調(diào)試的程序;若命令行中有文件名,則DOS把DEBUG程序調(diào)入內(nèi)存后,再由DEBUG將指定的文件名裝入內(nèi)存。

2)DEBUG的常用命令

(1)退出命令 Q
格式:Q
功能:退出DEBUG,返回到操作系統(tǒng)。
(2)顯示存儲(chǔ)單元命令 D
格式1:D[起始地址]
格式2:D[起始地址][結(jié)束地址|字節(jié)數(shù)]
功能:格式1從起始地址開(kāi)始按十六進(jìn)制顯示80H個(gè)單元的內(nèi)容,每行16個(gè)單元,共8行,每行右邊顯示16個(gè)單元的ASCII碼,不可顯示的ASCII碼則顯示“·”。格式2顯示指定范圍內(nèi)存儲(chǔ)單元的內(nèi)容,其他顯示方式與格式1一樣。如果缺省起始地址或地址范圍,則從當(dāng)前的地址開(kāi)始按格式1顯示。
例如: -D 200 ;表示從DS:0200H開(kāi)始顯示128個(gè)單元內(nèi)容
-D 100 120 ;表示顯示DS:0100-DS:0120單元的內(nèi)容
說(shuō)明:在DEBUG中,地址表示方式有如下形式:
段寄存器名:相對(duì)地址,如:DS:100
段基值:偏移地址(相對(duì)地址),如:23A0:1500

————————–小抄結(jié)束——————————–

3 驗(yàn)證第一節(jié)里的內(nèi)容

運(yùn)行“開(kāi)始/程序/附件/MS-DOS命令提示符”(這是win2000,win98下自己找吧)
在“_”下輸入D,顯示

-d
1398:0100 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 …………….
1398:0110 00 00 00 00 00 00 00 00-00 00 00 00 34 00 87 13 …………4…
1398:0120 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 …………….
1398:0130 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 …………….
1398:0140 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 …………….
1398:0150 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 …………….
1398:0160 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 …………….
1398:0170 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 …………….
-

我們記下:1398:011C的值是個(gè)34。1389:011C的物理地址應(yīng)該是:13A9C。
那么1000:3A9C的物理地址也應(yīng)該是13A9C,他的內(nèi)存也應(yīng)該是34,(因?yàn)楸緛?lái)就是一個(gè)地址嗎,就象第三行第十列和第十列第三行當(dāng)然應(yīng)該是同一個(gè)位置)。
-d 1000:3A9C
1000:3A90 34 00 87 13 4…
1000:3AA0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 …………….
1000:3AB0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 …………….
1000:3AC0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 …………….
1000:3AD0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 …………….
1000:3AE0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 …………….
1000:3AF0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 …………….
1000:3B00 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 …………….
1000:3B10 00 00 00 00 00 00 00 00-00 00 00 00 …………
-
果然如此,同樣你可以驗(yàn)證:13A9:000C也肯定是指這一個(gè)地址,不信試試。

4 DEBUG命令

——————-繼續(xù)小抄—————-
前面已學(xué)過(guò):顯示存儲(chǔ)單元命令 D
再學(xué)一個(gè)命令
(1)修改存儲(chǔ)單元命令 E

格式1:E[起始地址] [內(nèi)容表]

格式2:E[地址]

功能:格式1按內(nèi)容表的內(nèi)容修改從起始地址開(kāi)始的多個(gè)存儲(chǔ)單元內(nèi)容,即用內(nèi)容表指定的內(nèi)容來(lái)代替存儲(chǔ)單元當(dāng)前內(nèi)容。

例如:—E DS:0100 'VAR' 12 34

表示從DS:0100 為起始單元的連續(xù)五個(gè)字節(jié)單元內(nèi)容依次被修改為

'V'、'A'、'R'、12H、34H。

格式2是逐個(gè)修改指定地址單元的當(dāng)前內(nèi)容。

如:—E DS:0010

156F:0010 41.5F

其中156F:0010單元原來(lái)的值是41H,5FH為輸入的修改值。若只修改一個(gè)單元的內(nèi)容,這時(shí)按回車(chē)鍵即可;若還想繼續(xù)修改下一個(gè)單元內(nèi)容,此時(shí)應(yīng)按空格鍵,就顯示下一個(gè)單元的內(nèi)容,需修改就鍵入新的內(nèi)容,不修改再按空格跳過(guò),如此重復(fù)直到修改完畢,按回車(chē)鍵返回DEBUG“-”提示符。如果在修改過(guò)程中,將空格鍵換成按“-”鍵,則表示可以修改前一個(gè)單元的內(nèi)容。

——————-小抄結(jié)束—————-

5 使用DOS時(shí),匯編用戶(hù)可以從DOS操作系統(tǒng)中得到什么?
現(xiàn)在編程,通常很多功能都是通過(guò)調(diào)用系統(tǒng)API。很多高級(jí)語(yǔ)言都直接把這些API包裝起來(lái),以系統(tǒng)接口或函數(shù)的方式提供給用戶(hù),那么匯編函數(shù)都能得到什么呢?
首先,匯編用戶(hù)有很多東西可以調(diào)用。他們主要是:
5.1 BIOS提供的接口?,F(xiàn)在硬件與軟件的區(qū)分已越來(lái)越不明顯,很多硬件不僅僅是電路,而還要提供一些固化寫(xiě)入硬件的一部分“程序”,這些程序以ROM的方式出現(xiàn),匯編用戶(hù)最大的好處就是可以直接使用這些“程序”,這些使用不僅功能強(qiáng)大,而且效率非常高。
5.2 DOS功能調(diào)用,作為操作系統(tǒng)也象BIOS一樣向用戶(hù)提供了相應(yīng)的“程序”。這些程序在很大程序上擴(kuò)充了BIOS。與BIOS不同的是,這部分程序放在內(nèi)存中,它可以被修改。而B(niǎo)IOS中不能再修改。
==========================================================
以上兩種接口都通過(guò)一種相同的格式調(diào)用,這些程序統(tǒng)稱(chēng)為“中斷”,現(xiàn)在先不要理解中斷的本意,你現(xiàn)在可以認(rèn)為是系統(tǒng)提供給你的函數(shù)。
============================================================
5.3 系統(tǒng)共享數(shù)據(jù)區(qū)。編過(guò)程序的人都知道全局變量的好處,全局變量方便之外在于任何函數(shù)、過(guò)程都可以調(diào)用、讀取、修改。全局變量不足之處是危險(xiǎn)性,有一個(gè)過(guò)程改了這個(gè)變量值,其它的也得跟著改變了。DOS操作系統(tǒng)同樣也提供了這樣的共享數(shù)據(jù)區(qū),該區(qū)是整個(gè)系統(tǒng)的共享區(qū),任何程序都可以查找、修改。當(dāng)然,修改某處必然會(huì)對(duì)其它程序造成影響。

6 再談中斷

前面5.2已提到中斷了,現(xiàn)在問(wèn)題是不同硬件不一樣,即使相同硬件的ROM,不同版本,各個(gè)BIOS中斷程序所處的位置也不一樣,DOS中斷也一樣,不同版本、不同配置,在內(nèi)存位置也不一樣。那么你使用某一個(gè)中斷,系統(tǒng)怎么知道你使用的那個(gè)中斷程序在哪呢?
為了解決這一問(wèn)題,DOS會(huì)在啟動(dòng)的時(shí)候,把所有這些(BIOS和DOS)中斷的首地址保存到一個(gè)地址。這個(gè)地址很容易記,這段地址是內(nèi)存的絕對(duì)零地址(0000:0000)。前面已講過(guò),每個(gè)地址在匯編程序員角度來(lái)看是二維的,也就是分為段地址和偏移地址。每個(gè)地址各占兩個(gè)字節(jié),所以要表示這個(gè)二維地址需要4個(gè)字節(jié)。所以每個(gè)中斷首地址由4個(gè)字節(jié)表示。一共256個(gè)中斷,占用了1024個(gè)字節(jié)的位置。
另外需要注意的是,這4個(gè)表示地址的字節(jié),數(shù)據(jù)是由低向高的。比如12 34 56 78所表示的地址是:7856:3412。
一般用INT M表示中斷M,如果M是十六進(jìn)制,則在后面加上一個(gè)H。比如19號(hào)中斷,十六進(jìn)制應(yīng)該是13H。所以該中斷就是INT 13H。

7 再談系統(tǒng)共享數(shù)據(jù)區(qū)

該共享數(shù)據(jù)區(qū)在絕對(duì)地址:0040:0000開(kāi)始。

8 驗(yàn)證我上面說(shuō)的內(nèi)容

8.1 找中斷
運(yùn)行DEBUG后。輸入D 0000:0000。顯示絕對(duì)零地址的內(nèi)容。
C:\>debug
-d 0:0
0000:0000 68 10 A7 00 8B 01 70 00-16 00 9B 03 8B 01 70 00 h…..p…….p.
0000:0010 8B 01 70 00 B9 06 0E 02-40 07 0E 02 FF 03 0E 02 ..p…..@…….
0000:0020 46 07 0E 02 0A 04 0E 02-3A 00 9B 03 54 00 9B 03 F…….:…T…
0000:0030 6E 00 9B 03 88 00 9B 03-A2 00 9B 03 FF 03 0E 02 n……………
0000:0040 A9 08 0E 02 99 09 0E 02-9F 09 0E 02 5D 04 0E 02 …………]…
0000:0050 A5 09 0E 02 0D 02 DC 02-B8 09 0E 02 8B 05 0E 02 …………….
0000:0060 02 0C 0E 02 08 0C 0E 02-13 0C 0E 02 AD 06 0E 02 …………….
0000:0070 AD 06 0E 02 A4 F0 00 F0-37 05 0E 02 71 84 00 C0 ……..7…q…
-u 0070:018B
0070:018B 1E PUSH DS
0070:018C 50 PUSH AX
0070:018D B84000 MOV AX,0040
0070:0190 8ED8 MOV DS,AX
0070:0192 F70614030024 TEST WORD PTR [0314],2400
0070:0198 754F JNZ 01E9
0070:019A 55 PUSH BP
0070:019B 8BEC MOV BP,SP
0070:019D 8B460A MOV AX,[BP+0A]
0070:01A0 5D POP BP
0070:01A1 A90001 TEST AX,0100
0070:01A4 7543 JNZ 01E9
0070:01A6 A90002 TEST AX,0200
0070:01A9 7422 JZ 01CD
首先,D命令把中斷首地址顯示出來(lái)。每4個(gè)表示一個(gè)地址。其中INT 0的中斷首地址為:00A7:1068,INT 1的中斷地址為:0070:018B…….0070:018B是中斷3的首地址。后面那個(gè)U命令就表示顯示該地址的“中斷程序”的內(nèi)存。
你們可以試著找找INT 13H的位置在哪。
8.2 驗(yàn)證系統(tǒng)共享數(shù)據(jù)區(qū)
系統(tǒng)共享數(shù)據(jù)區(qū)內(nèi)容極為豐富,我實(shí)在記不住哪么多了。我曾記在一個(gè)本上,可惜那個(gè)本早在N年前(3<n<6)就丟了。兄弟們誰(shuí)找到這個(gè)地址的內(nèi)容,一定要貼上來(lái),這里有東西可以讓大家眼界大開(kāi)。
前幾年,我用的286計(jì)算機(jī)是黑白顯示器(555555~~~~~~~~~,別嫌我老、舊、慢呀),可當(dāng)時(shí)有個(gè)游戲非要彩顯,不是彩顯不讓運(yùn)行。我就是改了這個(gè)區(qū)的某一個(gè)位,讓哪游戲“以為”我用的是彩顯,于是游戲能用了。雖然不好看,但總能用。
在DOS下,你每按一個(gè)鍵,系統(tǒng)都會(huì)記下來(lái),下面我們一起找找這個(gè)鍵盤(pán)緩沖區(qū)的地址。知道這個(gè)地址,你就可以作一個(gè)“虛擬”鍵盤(pán),通過(guò)發(fā)命令來(lái)模擬某個(gè)人在按鍵。這個(gè)地址位于:0040:001E。 其中每個(gè)鍵有兩個(gè)字節(jié),一個(gè)字節(jié)是ASCII碼,一個(gè)是掃描碼。共16個(gè)。
C:\>debug
-d 40:0
0040:0000 F8 03 F8 02 E8 03 E8 02-BC 03 78 03 78 02 80 9F ……….x.x…
0040:0010 22 C8 00 80 02 28 00 00-00 00 2A 00 2A 00 20 39 "….(….*.*. 9
0040:0020 34 05 30 0B 3A 27 30 0B-0D 1C 64 20 20 39 34 05 4.0.:'0…d 94.
0040:0030 30 0B 3A 27 30 0B 0D 1C-71 10 0D 1C 64 20 00 00 0.:'0…q…d ..
0040:0040 A2 00 C3 00 A2 AF 09 E1-C8 03 50 00 00 10 00 00 ……….P…..
0040:0050 00 18 00 00 00 00 00 00-00 00 00 00 00 00 00 00 …………….
0040:0060 0F 0C 00 D4 03 29 30 7F-03 00 C0 00 A1 B7 11 00 …..)0………
0040:0070 00 00 00 00 00 00 00 00-14 14 14 00 01 01 01 01 …………….
-d 0040:0000
0040:0000 F8 03 F8 02 E8 03 E8 02-BC 03 78 03 78 02 80 9F ……….x.x…
0040:0010 22 C8 00 80 02 28 00 00-00 00 2A 00 2A 00 3A 27 "….(….*.*.:'
0040:0020 30 0B 30 0B 30 0B 30 0B-0D 1C 64 20 20 39 30 0B 0.0.0.0…d 90.
0040:0030 30 0B 30 0B 30 0B 08 0E-08 0E 34 05 30 0B 00 00 0.0.0…..4.0…
0040:0040 1F 00 C3 00 A2 AF 09 E1-C8 03 50 00 00 10 00 00 ……….P…..
0040:0050 00 18 00 00 00 00 00 00-00 00 00 00 00 00 00 00 …………….
0040:0060 0F 0C 00 D4 03 29 30 7F-03 00 C0 00 24 B8 11 00 …..)0…..$…
0040:0070 00 00 00 00 00 00 00 00-14 14 14 00 01 01 01 01 …………….
-
既然是鍵盤(pán)緩沖區(qū),每個(gè)輸入的鍵都會(huì)顯示在該區(qū)中,第一次我只輸入了“d 40:0”,所以你可以在此后顯示數(shù)據(jù)右邊字符中找到這些字符,注意是間隔開(kāi)的。
第二次我輸入“d 0040:0000”,則右邊顯示的是“d 0040:0000”的內(nèi)容。你可以找找。

第二講 內(nèi)存映象

之所以把這個(gè)內(nèi)存單獨(dú)放一章,是為了說(shuō)明它的重要性,后面的幾乎很多程序都需要你對(duì)這一章的理解。這里的內(nèi)存映象就是指當(dāng)你把一個(gè)可執(zhí)行文件(EXE或COM文件)放到內(nèi)存后,整個(gè)內(nèi)存“看”起來(lái)是什么樣子的。
前面講過(guò),這里匯編程序只能訪問(wèn)1M的內(nèi)存空間,所以下面就以1M內(nèi)存為例。并且以DOS操作系統(tǒng)作為講解對(duì)象,所以所編出來(lái)的程序也僅是DOS程序。事實(shí)上,通過(guò)winasm可以訪問(wèn)遠(yuǎn)遠(yuǎn)超過(guò)1M的空間,并且可以編出FOR windows的程序。但那是另外的話(huà)題。我們暫且不說(shuō)那些。

2.1 內(nèi)存映象
首先,這1M內(nèi)存如果我們不再以二維的方式看,而是一維的,線性地看(二維和一維的轉(zhuǎn)化方式參見(jiàn)前面章節(jié))。但描述還是以二維的方式描述,從最底端到最高端依次是:
1 中斷向量區(qū):該區(qū)由0000:0000~0000:03FF。這里存著系統(tǒng)的所有中斷的中斷向量表,對(duì)于中斷向量表,你現(xiàn)在先理解為一些程序的首地址。由這個(gè)地址你就能找到該程序。
2 系統(tǒng)數(shù)據(jù)區(qū):該區(qū)由0040:0000~0040:XXXX(不好意思,忘了),這里存著整個(gè)系統(tǒng)中,DOS操作系統(tǒng)要用的數(shù)據(jù),由于這個(gè)區(qū)的數(shù)據(jù)對(duì)用戶(hù)是開(kāi)放的,所以用戶(hù)當(dāng)然也可以從這里讀出來(lái)用。
3 DOS操作系統(tǒng)區(qū):操作系統(tǒng)常駐內(nèi)存,你向計(jì)算機(jī)發(fā)的每個(gè)命令其實(shí)都是操作系統(tǒng)執(zhí)行的。這個(gè)區(qū)的大小主要是由操作系統(tǒng)的版本和用戶(hù)的配置大小決定,如果是驅(qū)動(dòng)程序配置,就放到根目錄下的config.sys里,如果是程序,就放到autoexec.bat里。這里設(shè)置在現(xiàn)在的windows 95/98/nt/me/2000/xp/2003中仍然有,所以我就不多說(shuō)了。
4 用戶(hù)程序,這個(gè)當(dāng)然就是你執(zhí)行的程序了,這種程序分兩種,一種是擴(kuò)展名為com文件,一種是exe文件,從程序內(nèi)睝@矗罷叱絳虻乃母齠沃睪希ê竺嬉艙饉母齠危?,所以桩岓长度謮娜诱浕庚f?,觽儼面段地址的理金q褪莄om文件最大只能是64K,所以com文件只適合小的程序。而exe,四個(gè)段可任何分配,并可擴(kuò)充段,而且每個(gè)段的段地址可以任何改動(dòng),因此exe的訪問(wèn)內(nèi)存能力大多了。這種格式訪問(wèn)能力只受地址結(jié)構(gòu)的限制了。
用戶(hù)程序所占的內(nèi)存大小完全由程序本身決定,但最大,只能到640K。這一點(diǎn),怪不得別人,只能怪當(dāng)前計(jì)算機(jī)軟硬件設(shè)置高手高手高高手們(包括比爾蓋茨)們的失誤了,60年代的超級(jí)計(jì)算機(jī)只有36K的內(nèi)存,所以他們就在80年代得到一個(gè)結(jié)論:640K的內(nèi)存足夠了。
如果用戶(hù)程序大于由操作系統(tǒng)所占內(nèi)存的頂?shù)椎?40K之間的內(nèi)存量,就會(huì)顯示:內(nèi)存不夠,因而程序不能執(zhí)行。這種現(xiàn)象對(duì)于一開(kāi)始就用windows的人來(lái)說(shuō),幾乎沒(méi)見(jiàn)過(guò),但對(duì)于一開(kāi)始用DOS并打漢字的人來(lái)說(shuō),再正常不過(guò)。如果小于這段內(nèi)存,多余部分就空著。
5 從640K到1M-64K,這段內(nèi)存就很難說(shuō)清了。這段內(nèi)存中有一部分被硬件占有,有一部分是顯示緩沖區(qū)點(diǎn)有,還有一部分是系統(tǒng)ROM占有。
6 從1M-64K到1M之間的這段64K的內(nèi)存叫作HMA。這段內(nèi)存是小孩沒(méi)娘,說(shuō)來(lái)話(huà)長(zhǎng),我們先不說(shuō)他。
2.2 驗(yàn)證上面的理論

2.2.1 中斷向量表
中斷向量表就是所有中斷向量首地址表,這里保存著每個(gè)中斷程序的首地址,幾乎所有的匯編書(shū)都把中斷后面后面的章節(jié)中,并且對(duì)中斷的解釋也僅從字面意思解釋?zhuān)詫?dǎo)致大學(xué)對(duì)中斷的不重要和誤解。沒(méi)耐心的沒(méi)到這個(gè)章節(jié)就不學(xué)匯編了,有耐心的到這里才豁然開(kāi)朗。我現(xiàn)在不講中斷的原意。我直接告訴你,你把中斷當(dāng)成API也許更合適。也就是說(shuō),別人把很多已作好的功能放到了內(nèi)存中。并且把調(diào)用這一功能的號(hào)告訴了你,你只要調(diào)用這些功能號(hào),系統(tǒng)就自動(dòng)從這個(gè)中斷向量表中找到對(duì)應(yīng)的中斷,然后執(zhí)行你的功能。
首先讓你感受一下中斷的魅力一下吧。比如中斷21H的2A功能調(diào)用是讀取系統(tǒng)的日期,這個(gè)調(diào)用的規(guī)則是,調(diào)用前AH寄存器置為2A。調(diào)用后年在CX中,月在DH中,DL在日中,星期在AL中。
-a
139D:0100 mov ah,2a
139D:0102 int 21
139D:0104 int 3
139D:0105
-g=100

AX=2A05 BX=0000 CX=07D4 DX=0C18 SP=FFEE BP=0000 SI=0000 DI=0000
DS=139D ES=139D SS=139D CS=139D IP=0104 NV UP EI PL NZ NA PO NC
139D:0104 CC INT 3
-
可能上面的程序你目前還看不懂。不過(guò)沒(méi)關(guān)系,“mov ah,2a”表示調(diào)用功能號(hào)是2a號(hào)?!癷nt 21”表示調(diào)用十六進(jìn)制21號(hào)中斷,“int 3”表示3號(hào)中斷,表示程序運(yùn)行到這一句時(shí)停一下。“g=100”表示從“139D:0100 ”開(kāi)始執(zhí)行。
AX=2A05 BX=0000 CX=07D4 DX=0C18 SP=FFEE BP=0000 SI=0000 DI=0000
DS=139D ES=139D SS=139D CS=139D IP=0104 NV UP EI PL NZ NA PO NC
表示執(zhí)行的結(jié)果。其中CX是年,這個(gè)年是由CX中存。07D4十進(jìn)制就是2004年。DH+DL=DX,所以DH=0C,DL=18。二者轉(zhuǎn)化為十進(jìn)制就是DH=12,DL=24,也就是今天了。AX=AH+AL=2A05,所以AL=05。那就是今天是星期五。
上面可能你們現(xiàn)在還看不懂,不過(guò)通過(guò)解說(shuō)你應(yīng)該可以知道,僅僅兩行命令,就讀到了現(xiàn)在的值?,F(xiàn)在需要作的就是把這些值提取出來(lái)用作他用了。

從中斷的作來(lái)與中斷向量表又有什么關(guān)系呢?原來(lái)你在匯編里運(yùn)行int 21時(shí),系統(tǒng)就在上面的中斷向量表中找到int 21的中斷地址,該中斷的地址應(yīng)該位于:0000:0084~0000:0087,具體算法前面已說(shuō)明了。
-d 0000:0084 0087
0000:0080 7C 10 A7 00 |…
-
找到內(nèi)容是:00A7:107C。然后系統(tǒng)就轉(zhuǎn)到這個(gè)地址執(zhí)行int 21。

2.2.2 系統(tǒng)數(shù)據(jù)區(qū)前面都已說(shuō)明過(guò)。不再多說(shuō)。系統(tǒng)區(qū),很多DOS中斷程序?qū)崿F(xiàn)部分就在這個(gè)區(qū)。程序運(yùn)行區(qū)依不同的程序而不用。

2.2.3 640K~1M之間,這期間有些地方是ROM,有些地方是硬件的BIOS區(qū)。我僅以?xún)蓚€(gè)例子說(shuō)明這一區(qū)。
ROM區(qū):ROM區(qū)就是只讀內(nèi)存,也就是說(shuō)這個(gè)區(qū)的數(shù)據(jù)只能讀不能寫(xiě)。比如F000:0000開(kāi)始的內(nèi)存是ROM。我們來(lái)寫(xiě)一下,然后再看看效果。
-d f000:0000 0005 '顯示由F000:0000到F000:0005的六個(gè)字節(jié)值。
F000:0000 04 E8 A2 FF F9 C3 ……
-e f000:0000 '修改命令
F000:0000 04.00 E8.00 A2.00 FF.00 F9.00 C3.00'注意,.后面的是我改的,把這幾個(gè)值都改成0了。
-d f000:0000 0005 '再次顯示這個(gè)區(qū)的數(shù)據(jù)。
F000:0000 04 E8 A2 FF F9 C3 ……
-
通過(guò)上面測(cè)試,發(fā)現(xiàn)該區(qū)數(shù)據(jù)仍然未改變。但你要是試別的RAM區(qū)的,肯定會(huì)變。如果想試你自己試試吧。

顯示緩沖區(qū):在文本方式下,B800:0000開(kāi)始的地址保存著屏幕上每個(gè)字符位置的值。在文本方式下,屏幕被分為80 X 25。每個(gè)位置有兩個(gè)值,一個(gè)值是ASCII字符,一個(gè)值是該ASCII的屬性值(主要是顏色)。所以一個(gè)屏幕共有80X25X2=400個(gè)字符。
我們來(lái)改:
-d b800:0000 0010 '顯示屏幕緩沖區(qū)的內(nèi)容,注意此時(shí)本行最左邊的“-”是屏幕左上角。
B800:0000 2D 07 64 07 20 07 62 07-38 07 30 07 30 07 3A 07 -.d. .b.8.0.0.:.
B800:0010 30 0
-
看上面的命令,屏幕最上邊一行是“-d b800:0000 0010”,所以他的內(nèi)容就是“2D 07 64 07 20 07 62 07-38 07 30 07 30 07 3A 07”其中,2D是“-”的ASCII值,07是“-”的屬性值。64是“d”的ASCII值,07是“d”的屬性值。。。。。
現(xiàn)在修改這些值。我把左上角的字改成黃顏色的“-”,那當(dāng)然是改b800:0001的屬性值了。
-e b800:0001 0e
是不是左上角的顏色變成黃色了嗎?
好了,把第二個(gè)字符變成綠色的“-”吧?
-e b800:0002 2d 0b
變了嗎?

第三章 匯編指令

3.1 什么是機(jī)器語(yǔ)言
前面提到“最早的計(jì)算機(jī)采用機(jī)器語(yǔ)言,這種語(yǔ)言直接用二進(jìn)制數(shù)表示,通過(guò)直接輸入二進(jìn)制數(shù),插拔電路板等實(shí)現(xiàn),這種“編程”很容易出錯(cuò),每個(gè)命令都是通過(guò)查命令表實(shí)現(xiàn)”。
比如要執(zhí)行21號(hào)中斷,需要查表,得到21號(hào)中斷的指令就是CD 21。這樣不管你通過(guò)什么方式,在內(nèi)存指令位置,寫(xiě)入兩個(gè)字節(jié),一個(gè)是CD(這可不是音樂(lè)光盤(pán),而是二進(jìn)制數(shù),轉(zhuǎn)成十進(jìn)制就是205),另一個(gè)是21(同樣是十六進(jìn)制,十進(jìn)制是33)。
上面就是機(jī)器語(yǔ)言。

3.2 什么是匯編語(yǔ)言
前面也提到“既然是通過(guò)“查表”實(shí)現(xiàn)的,那當(dāng)然也可以讓計(jì)算機(jī)來(lái)代替人查表實(shí)現(xiàn)了。于是就產(chǎn)生了匯編語(yǔ)言”,匯編語(yǔ)言產(chǎn)生的重要目的就是用容易記的符號(hào)來(lái)代替容易出錯(cuò)的二進(jìn)制數(shù)(或十六進(jìn)制數(shù))。
比如前面的21號(hào)中斷,機(jī)器語(yǔ)言是CD 21。而匯編語(yǔ)言就規(guī)定中斷用int表示(interrupt的前三個(gè)字母),21號(hào)中斷就成了int 21h。其中21后面的h表示是表示這個(gè)21是十六進(jìn)制。由于大小寫(xiě)不敏感,所以int 21h寫(xiě)成下列方式都等價(jià):
int 33
Int 21h
INT 21H

3.3 匯編指令集

一、數(shù)據(jù)傳輸指令

───────────────────────────────────────
它們?cè)诖尜A器和寄存器、寄存器和輸入輸出端口之間傳送數(shù)據(jù).
1. 通用數(shù)據(jù)傳送指令.
MOV 傳送字或字節(jié).
MOVSX 先符號(hào)擴(kuò)展,再傳送.
MOVZX 先零擴(kuò)展,再傳送.
PUSH 把字壓入堆棧.
POP 把字彈出堆棧.
PUSHA 把AX,CX,DX,BX,SP,BP,SI,DI依次壓入堆棧.
POPA 把DI,SI,BP,SP,BX,DX,CX,AX依次彈出堆棧.
PUSHAD 把EAX,ECX,EDX,EBX,ESP,EBP,ESI,EDI依次壓入堆棧.
POPAD 把EDI,ESI,EBP,ESP,EBX,EDX,ECX,EAX依次彈出堆棧.
BSWAP 交換32位寄存器里字節(jié)的順序
XCHG 交換字或字節(jié).( 至少有一個(gè)操作數(shù)為寄存器,段寄存器不可作為操作數(shù))
CMPXCHG 比較并交換操作數(shù).( 第二個(gè)操作數(shù)必須為累加器AL/AX/EAX )
XADD 先交換再累加.( 結(jié)果在第一個(gè)操作數(shù)里 )
XLAT 字節(jié)查表轉(zhuǎn)換.
── BX 指向一張 256 字節(jié)的表的起點(diǎn), AL 為表的索引值 (0-255,即
0-FFH); 返回 AL 為查表結(jié)果. ( [BX+AL]->AL )
2. 輸入輸出端口傳送指令.
IN I/O端口輸入. ( 語(yǔ)法: IN 累加器, {端口號(hào)│DX} )
OUT I/O端口輸出. ( 語(yǔ)法: OUT {端口號(hào)│DX},累加器 )
輸入輸出端口由立即方式指定時(shí), 其范圍是 0-255; 由寄存器 DX 指定時(shí),
其范圍是 0-65535.
3. 目的地址傳送指令.
LEA 裝入有效地址.
例: LEA DX,string ;把偏移地址存到DX.
LDS 傳送目標(biāo)指針,把指針內(nèi)容裝入DS.
例: LDS SI,string ;把段地址:偏移地址存到DS:SI.
LES 傳送目標(biāo)指針,把指針內(nèi)容裝入ES.
例: LES DI,string ;把段地址:偏移地址存到ES:DI.
LFS 傳送目標(biāo)指針,把指針內(nèi)容裝入FS.
例: LFS DI,string ;把段地址:偏移地址存到FS:DI.
LGS 傳送目標(biāo)指針,把指針內(nèi)容裝入GS.
例: LGS DI,string ;把段地址:偏移地址存到GS:DI.
LSS 傳送目標(biāo)指針,把指針內(nèi)容裝入SS.
例: LSS DI,string ;把段地址:偏移地址存到SS:DI.
4. 標(biāo)志傳送指令.
LAHF 標(biāo)志寄存器傳送,把標(biāo)志裝入AH.
SAHF 標(biāo)志寄存器傳送,把AH內(nèi)容裝入標(biāo)志寄存器.
PUSHF 標(biāo)志入棧.
POPF 標(biāo)志出棧.
PUSHD 32位標(biāo)志入棧.
POPD 32位標(biāo)志出棧.

二、算術(shù)運(yùn)算指令

───────────────────────────────────────
ADD 加法.
ADC 帶進(jìn)位加法.
INC 加 1.
AAA 加法的ASCII碼調(diào)整.
DAA 加法的十進(jìn)制調(diào)整.
SUB 減法.
SBB 帶借位減法.
DEC 減 1.
NEC 求反(以 0 減之).
CMP 比較.(兩操作數(shù)作減法,僅修改標(biāo)志位,不回送結(jié)果).
AAS 減法的ASCII碼調(diào)整.
DAS 減法的十進(jìn)制調(diào)整.
MUL 無(wú)符號(hào)乘法.
IMUL 整數(shù)乘法.
以上兩條,結(jié)果回送AH和AL(字節(jié)運(yùn)算),或DX和AX(字運(yùn)算),
AAM 乘法的ASCII碼調(diào)整.
DIV 無(wú)符號(hào)除法.
IDIV 整數(shù)除法.
以上兩條,結(jié)果回送:
商回送AL,余數(shù)回送AH, (字節(jié)運(yùn)算);
或 商回送AX,余數(shù)回送DX, (字運(yùn)算).
AAD 除法的ASCII碼調(diào)整.
CBW 字節(jié)轉(zhuǎn)換為字. (把AL中字節(jié)的符號(hào)擴(kuò)展到AH中去)
CWD 字轉(zhuǎn)換為雙字. (把AX中的字的符號(hào)擴(kuò)展到DX中去)
CWDE 字轉(zhuǎn)換為雙字. (把AX中的字符號(hào)擴(kuò)展到EAX中去)
CDQ 雙字?jǐn)U展. (把EAX中的字的符號(hào)擴(kuò)展到EDX中去)

三、邏輯運(yùn)算指令

───────────────────────────────────────
AND 與運(yùn)算.
or 或運(yùn)算.
XOR 異或運(yùn)算.
NOT 取反.
TEST 測(cè)試.(兩操作數(shù)作與運(yùn)算,僅修改標(biāo)志位,不回送結(jié)果).
SHL 邏輯左移.
SAL 算術(shù)左移.(=SHL)
SHR 邏輯右移.
SAR 算術(shù)右移.(=SHR)
ROL 循環(huán)左移.
ROR 循環(huán)右移.
RCL 通過(guò)進(jìn)位的循環(huán)左移.
RCR 通過(guò)進(jìn)位的循環(huán)右移.
以上八種移位指令,其移位次數(shù)可達(dá)255次.
移位一次時(shí), 可直接用操作碼. 如 SHL AX,1.
移位>1次時(shí), 則由寄存器CL給出移位次數(shù).
如 MOV CL,04
SHL AX,CL

四、串指令

───────────────────────────────────────
DS:SI 源串段寄存器 :源串變址.
ES:DI 目標(biāo)串段寄存器:目標(biāo)串變址.
CX 重復(fù)次數(shù)計(jì)數(shù)器.
AL/AX 掃描值.
D標(biāo)志 0表示重復(fù)操作中SI和DI應(yīng)自動(dòng)增量; 1表示應(yīng)自動(dòng)減量.
Z標(biāo)志 用來(lái)控制掃描或比較操作的結(jié)束.
MOVS 串傳送.
( MOVSB 傳送字符. MOVSW 傳送字. MOVSD 傳送雙字. )
CMPS 串比較.
( CMPSB 比較字符. CMPSW 比較字. )
SCAS 串掃描.
把AL或AX的內(nèi)容與目標(biāo)串作比較,比較結(jié)果反映在標(biāo)志位.
LODS 裝入串.
把源串中的元素(字或字節(jié))逐一裝入AL或AX中.
( LODSB 傳送字符. LODSW 傳送字. LODSD 傳送雙字. )
STOS 保存串.
是LODS的逆過(guò)程.
REP 當(dāng)CX/ECX<>0時(shí)重復(fù).
REPE/REPZ 當(dāng)ZF=1或比較結(jié)果相等,且CX/ECX<>0時(shí)重復(fù).
REPNE/REPNZ 當(dāng)ZF=0或比較結(jié)果不相等,且CX/ECX<>0時(shí)重復(fù).
REPC 當(dāng)CF=1且CX/ECX<>0時(shí)重復(fù).
REPNC 當(dāng)CF=0且CX/ECX<>0時(shí)重復(fù).

五、程序轉(zhuǎn)移指令

───────────────────────────────────────
1>無(wú)條件轉(zhuǎn)移指令 (長(zhǎng)轉(zhuǎn)移)
JMP 無(wú)條件轉(zhuǎn)移指令
CALL 過(guò)程調(diào)用
RET/RETF過(guò)程返回.
2>條件轉(zhuǎn)移指令 (短轉(zhuǎn)移,-128到+127的距離內(nèi))
( 當(dāng)且僅當(dāng)(SF XOR OF)=1時(shí),OP1<op2 )
JA/JNBE 不小于或不等于時(shí)轉(zhuǎn)移.
JAE/JNB 大于或等于轉(zhuǎn)移.
JB/JNAE 小于轉(zhuǎn)移.
JBE/JNA 小于或等于轉(zhuǎn)移.
以上四條,測(cè)試無(wú)符號(hào)整數(shù)運(yùn)算的結(jié)果(標(biāo)志C和Z).
JG/JNLE 大于轉(zhuǎn)移.
JGE/JNL 大于或等于轉(zhuǎn)移.
JL/JNGE 小于轉(zhuǎn)移.
JLE/JNG 小于或等于轉(zhuǎn)移.
以上四條,測(cè)試帶符號(hào)整數(shù)運(yùn)算的結(jié)果(標(biāo)志S,O和Z).
JE/JZ 等于轉(zhuǎn)移.
JNE/JNZ 不等于時(shí)轉(zhuǎn)移.
JC 有進(jìn)位時(shí)轉(zhuǎn)移.
JNC 無(wú)進(jìn)位時(shí)轉(zhuǎn)移.
JNO 不溢出時(shí)轉(zhuǎn)移.
JNP/JPO 奇偶性為奇數(shù)時(shí)轉(zhuǎn)移.
JNS 符號(hào)位為 "0" 時(shí)轉(zhuǎn)移.
JO 溢出轉(zhuǎn)移.
JP/JPE 奇偶性為偶數(shù)時(shí)轉(zhuǎn)移.
JS 符號(hào)位為 "1" 時(shí)轉(zhuǎn)移.
3>循環(huán)控制指令(短轉(zhuǎn)移)
LOOP CX不為零時(shí)循環(huán).
LOOPE/LOOPZ CX不為零且標(biāo)志Z=1時(shí)循環(huán).
LOOPNE/LOOPNZ CX不為零且標(biāo)志Z=0時(shí)循環(huán).
JCXZ CX為零時(shí)轉(zhuǎn)移.
JECXZ ECX為零時(shí)轉(zhuǎn)移.
4>中斷指令
INT 中斷指令
INTO 溢出中斷
IRET 中斷返回
5>處理器控制指令
HLT 處理器暫停, 直到出現(xiàn)中斷或復(fù)位信號(hào)才繼續(xù).
WAIT 當(dāng)芯片引線TEST為高電平時(shí)使CPU進(jìn)入等待狀態(tài).
ESC 轉(zhuǎn)換到外處理器.
LOCK 封鎖總線.
NOP 空操作.
STC 置進(jìn)位標(biāo)志位.
CLC 清進(jìn)位標(biāo)志位.
CMC 進(jìn)位標(biāo)志取反.
STD 置方向標(biāo)志位.
CLD 清方向標(biāo)志位.
STI 置中斷允許位.
CLI 清中斷允許位.

六、偽指令

───────────────────────────────────────
DW 定義字(2字節(jié)).
PROC 定義過(guò)程.
ENDP 過(guò)程結(jié)束.
SEGMENT 定義段.
ASSUME 建立段寄存器尋址.
ENDS 段結(jié)束.
END 程序結(jié)束.
3.4 再談寄存器和內(nèi)存的區(qū)別
第零講說(shuō)到“寄存器在CPU中。內(nèi)存在內(nèi)存條中。前者的速度比后者快100倍左右。后面的程序要求每條指定要么沒(méi)有內(nèi)存數(shù)據(jù),要么在有一個(gè)寄存器的參與下有一個(gè)內(nèi)存數(shù)據(jù)。(也就是說(shuō),不存在只訪問(wèn)內(nèi)存的指令)?!?br /> 寄存器是在CPU中的存儲(chǔ)器,而內(nèi)存是在內(nèi)存條中的存儲(chǔ)器。CPU訪問(wèn)寄存器,只需要通過(guò)微指令直接就可以訪問(wèn),而訪問(wèn)內(nèi)存則要先經(jīng)過(guò)總線,再由總線到達(dá)內(nèi)存控制器,讀到某單元的內(nèi)存數(shù)據(jù)后放上總線,再傳到CPU中,CPU才能使用。
8086系列計(jì)算機(jī)的寄存器,共有14個(gè),每個(gè)都是十六位的。
AX,BX,CX,DX,SP,BP,SI,DI,CS,DS,SS,ES,IP,F(xiàn)LAGS。
其中前四位,每個(gè)可以單位再分成兩個(gè),AX=AH+AL,BX=BH+BL,CX=CH+CL,DX=DH+DL。這些分開(kāi)的每個(gè)都是8位的。
這個(gè)分開(kāi)不要理解成平時(shí)語(yǔ)言中的分開(kāi),你可以理解為AX是由AH和AL組合成的,你給AL付值,就意味著同時(shí)給AX的低半部付值。你給AX付值,就意味著同時(shí)改變AH和AL。這樣作的好處是你可以更靈活地控制這個(gè)寄存器。

3.5 指令說(shuō)明
看了3.3的指令集和3.4的寄存器,是不是已經(jīng)了,或者了?不要急,上面的東西雖然多,我也沒(méi)讓你一下學(xué)會(huì),(其實(shí)有些永遠(yuǎn)也不會(huì)似乎也不是什么大不了的事)。為了應(yīng)付看的懂我后面所說(shuō)的,我把其中的指令挑幾個(gè)重點(diǎn)的,你必須要記住,其它的慢慢學(xué)吧。

1數(shù)據(jù)傳輸指令。
mov A,B
注意不是move,這個(gè)指令是把B中的數(shù)據(jù)復(fù)制給A,(B中仍保存原狀)。這里的A和B可以是寄存器,可以是內(nèi)存。但可以同時(shí)是寄存器,不能同時(shí)是內(nèi)存。比如
mov ax,100 ;這是對(duì)的,注意100在這里叫立即數(shù),但這個(gè)數(shù)在編譯系統(tǒng)編譯成exe的時(shí)候保存在內(nèi)存中。如果學(xué)過(guò)別的高級(jí)語(yǔ)言,你就可以理解為這就是賦值語(yǔ)句 Let ax=100/ax:=100;/ax=100。
2 偽指令
偽指令就是不是真的指令,但他同時(shí)又是指令。之所以說(shuō)這樣矛盾的話(huà),是因?yàn)閭沃噶畈皇菣C(jī)器語(yǔ)言的一部分,而是匯編語(yǔ)言的一部分,是你告訴匯編的編譯系統(tǒng)如何去作。
string DB '這是我的第一個(gè)匯編語(yǔ)言程序$'
上面一行指令中,DB就是偽指令,他的作用就是告訴編譯程序,把后面一些數(shù)據(jù)或字符串放到內(nèi)存中。當(dāng)然對(duì)于exe來(lái)說(shuō),已在內(nèi)存中了,就不用“告訴”了。(這就是為什么叫偽指令)。string是你給這段內(nèi)存起的名字,如果你不需要這段內(nèi)存,不起名字也可以,但如果后面要用,當(dāng)然要加上這個(gè)名字。'這是我的第一個(gè)匯編語(yǔ)言程序$'這個(gè)就是要處理的數(shù)據(jù),當(dāng)然你也可以換成別的內(nèi)容,但需要注意的是,要以'$'結(jié)尾,這是匯編的約寫(xiě),即:只是到了$,就認(rèn)為字符串結(jié)束,否則就一直向下找,直到找到一個(gè)$為止。所以這就要求你的字符串中不能有'$',如果必須有,再換別的處理方式,后面再說(shuō)。
3 地址傳送指令
Lea A,string
前面已經(jīng)定義了string,后面要把地址找到,就要用到lea指令。lea是把字符串的地址給A這個(gè)寄存器中,A當(dāng)然可以上前面提到的任意寄存器。注意地址和內(nèi)容的區(qū)別。如果是內(nèi)容就是把string的字符串給A了。(當(dāng)然這也不成立,一個(gè)字符串有很多字節(jié),而一個(gè)寄存器只有兩個(gè)字節(jié))。
那么從上面也看到了,string代表一個(gè)地址,lea把這個(gè)地址給了A,那這個(gè)地址到底在哪里呢?事實(shí)上這不重要,就象你要把某書(shū)店買(mǎi)書(shū),這個(gè)書(shū)店在哪并不是最重要的,有沒(méi)有你要的書(shū)才是最重要的。所以你前面標(biāo)出string,后面引用就行了,至于這個(gè)地址到底在哪是編譯程序的事,不是你的事。

4 運(yùn)算指令
ADD A,N
這個(gè)很容易理解吧,寄存器A加上N,把和仍存在A中。類(lèi)似于高級(jí)語(yǔ)言中的let a=a+n/a:=a+n/a+=n。

5 串操作指令
記住串操作指令表面很復(fù)雜,其實(shí)很簡(jiǎn)單。
因?yàn)樗拖笠粋€(gè)復(fù)雜的數(shù)學(xué)公式一樣簡(jiǎn)單,你所要記住的就是公式的格式,使用時(shí)具體套用即可。
從一個(gè)地址到另一個(gè)地址的復(fù)制需要注意的是:
*把源串段地址給DS。
*把源串編址給SI。
*把目的串段址給ES。
*把目的串偏址給DI。
*把要復(fù)制的個(gè)數(shù)給CX,這里可不考慮$了。
*把FLAG中的方向標(biāo)志標(biāo)志你要的方向,一個(gè)是順向,另一個(gè)是逆向。
*發(fā)送loop movs,scans等命令。

6 轉(zhuǎn)移指令
記?。簾o(wú)條件轉(zhuǎn)移指令 jmp。等于轉(zhuǎn) jz,不等于時(shí)轉(zhuǎn)jnz

7 中斷指令
int 中斷號(hào),注意進(jìn)制,默認(rèn)是十進(jìn)制,所以十六進(jìn)制就加h。

好了,上面的指令變成七八個(gè)了,這你不能嫌多了吧,如果再嫌多就不要繼續(xù)向下看了。

4.1 匯編程序框架

data SEGMENT '數(shù)據(jù)段,編程者可以把數(shù)據(jù)都放到這個(gè)段里
….數(shù)據(jù)部分
'數(shù)據(jù)格式是: 標(biāo)識(shí)符 db/dw 數(shù)據(jù)。
data ENDS'數(shù)據(jù)段結(jié)束處。

edata SEGMENT '附加數(shù)據(jù)段,編程者可以把數(shù)據(jù)都放到這個(gè)段里
….附加數(shù)據(jù)部分
edata ENDS'附加數(shù)據(jù)段結(jié)束處。

code SEGMENT'代碼段,實(shí)際的程序都是放這個(gè)段里。
ASSUME CS:code,DS:data,ES:edata '告訴編譯程序,data段是數(shù)據(jù)段DS,code段是代碼段CS
start:MOV AX,data '前面的start表示一個(gè)標(biāo)識(shí)位,后面用到該位,如果用不到,就可以不加
MOV DS,AX '這一句與上一行共同組成把data賦值給DS。段寄存器.
MOV AX,edata
MOV ES,AX '與前一句共同組成edata->ES
…….程序部分
MOV AX,4C00h'程序退出,該句內(nèi)存由下一行決定。退出時(shí),要求ah必須是4c。
INT 21h
code ENDS'代碼段結(jié)束。
END start'整個(gè)程序結(jié)束,并且程序執(zhí)行時(shí)由start那個(gè)位置開(kāi)始執(zhí)行。

上面就是一個(gè)程序的框架結(jié)構(gòu)。在這個(gè)結(jié)構(gòu)中,有三個(gè)段,DS,ES,CS。這三個(gè)段分別存數(shù)據(jù),附加數(shù)據(jù),代碼段。

4.2 編寫(xiě)我們的Hello,world思路。
開(kāi)始編寫(xiě)我們的第一個(gè)程序。
程序要求:顯示一個(gè)“Hello,Mr.286.”怎么樣?
思路:
1 要顯示一個(gè)字符串,根據(jù)前面我讓你們記的七八個(gè)指令夠嗎?答案是:不僅夠,而且還用不完。
首先定義一下總可以吧。

hellostr db 'Hello,Mr.286.$'
最后的$不要忘了。

2 首先要考慮的問(wèn)題就是找中斷,找到合適的中斷,該中斷就能幫我們完成這個(gè)顯示任務(wù)。我找到(在哪找到的,怎么找到的,別問(wèn)我,到網(wǎng)上或書(shū)上都能找到):
——————————————-
中斷INT 21H功能09H

功能描述: 輸出一個(gè)字符串到標(biāo)準(zhǔn)輸出設(shè)備上。如果輸出操作被重定向,那么,將無(wú)法判斷磁盤(pán)已滿(mǎn)
入口參數(shù): AH=09H
DS:DX=待輸出字符的地址
說(shuō)明:待顯示的字符串以'$'作為其結(jié)束標(biāo)志
出口參數(shù): 無(wú)
——————————————-
由上面看到,我們所需要作的就是把DS指向數(shù)據(jù)段,DX指向字符串的地址,AH等于9H,調(diào)用21h中斷。
mov ds,數(shù)據(jù)段地址
lea dx,hellostr 'hellostr已在前面1中定義了。
mov ah,9h
int 21h。
由于只要在調(diào)用int 21h之前把準(zhǔn)備的東西準(zhǔn)備齊就行了,所以int 21h前面三行的順序并不重要。

3 退出程序,運(yùn)行完總要退出呀。再查中斷手冊(cè)
——————————————–
中斷INT 21H功能4CH

功能描述: 終止程序的執(zhí)行,并可返回一個(gè)代碼
入口參數(shù): AH=4CH
AL=返回的代碼
出口參數(shù): 無(wú)

——————————————–
mov ah,4Ch
mov al,0
int 21h

mov ax,4c00h
int 21h
這里需要說(shuō)明的是返回代碼有什么用,返回給誰(shuí)?返回給操作系統(tǒng),因?yàn)槭遣僮飨到y(tǒng)DOS調(diào)用的這個(gè)程序,這個(gè)返回值可以通過(guò)批處理中的errorlevel得到,這里不多說(shuō)明,實(shí)際上操作系統(tǒng)很少處理這一值,因此al你隨便寫(xiě)什么值影響都不大。

4.3 程序?qū)崿F(xiàn)

data SEGMENT
msg DB 'Hello, Mr.286.$'
data ENDS

code SEGMENT
ASSUME CS:code,DS:data
start:MOV AX,data
MOV DS,AX
lea dx,msg
mov ah,9h
int 21h
MOV AX,4C00h
INT 21h
code ENDS
END start

4.4 編譯運(yùn)行。
把上面程序保存成hello286.asm后,就可以編譯運(yùn)行了。進(jìn)入DOS,進(jìn)入?yún)R編目錄,如果還沒(méi)下載,到前面找下載地址。

=================================================
E:\Download\Masm>masm hello286.asm
Microsoft (R) Macro Assembler Version 5.00
Copyright (C) Microsoft Corp 1981-1985, 1987. All rights reserved.

Object filename [hello286.OBJ]:
Source listing [NUL.LST]:
Cross-reference [NUL.CRF]:

50408 + 415320 Bytes symbol space free

0 Warning Errors
0 Severe Errors
說(shuō)明:上面連續(xù)三個(gè)回車(chē),表示我要的都是默認(rèn)值。下面是零個(gè)警告,零個(gè)嚴(yán)重錯(cuò)誤,(當(dāng)然了,我的程序還敢錯(cuò)嗎?)

E:\Download\Masm>link hello286

Microsoft (R) Overlay Linker Version 3.60
Copyright (C) Microsoft Corp 1983-1987. All rights reserved.

Run File [HELLO286.EXE]:
List File [NUL.MAP]:
Libraries [.LIB]:
LINK : warning L4021: no stack segment

說(shuō)明:三個(gè)回車(chē)仍要默認(rèn),后面有個(gè)警告,沒(méi)有棧段,這個(gè)沒(méi)關(guān)系,沒(méi)有的話(huà)系統(tǒng)會(huì)自動(dòng)給一個(gè)()。

E:\Download\Masm>hello286
Hello, Mr.286.
說(shuō)明:運(yùn)行成功。
E:\Download\Masm>
===================================================
4.4 深度思考
4.4.1 是不是數(shù)據(jù)必須放數(shù)據(jù)段,代碼必段放代碼段呢?
答,代碼必段放代碼段,否則你怎么執(zhí)行呀?但數(shù)據(jù)也可以放到代碼段,只是程序要作修改。

code SEGMENT
ASSUME CS:code,DS:data
msg DB 'Hello, Mr.286.$'
start:MOV AX,data
MOV DS,AX
lea dx,msg
mov ah,9h
int 21h
MOV AX,4C00h
INT 21h
code ENDS
END start

編譯后仍然可以。
4.4.2 我編的程序在內(nèi)存中是什么樣子的呢?
————————————————————————
E:\Download\Masm>debug hello286.exe
-u
1420:0000 B81F14 MOV AX,141F
1420:0003 8ED8 MOV DS,AX
1420:0005 8D160000 LEA DX,[0000]
1420:0009 B409 MOV AH,09
1420:000B CD21 INT 21
1420:000D B8004C MOV AX,4C00
1420:0010 CD21 INT 21
1420:0012 FF362421 PUSH [2124]
1420:0016 E87763 CALL 6390
1420:0019 83C406 ADD SP,+06
1420:001C FF362421 PUSH [2124]
-d 141f:0000 L20
141F:0000 48 65 6C 6C 6F 2C 20 4D-72 2E 32 38 36 2E 24 00 Hello, Mr.286.$.
141F:0010 B8 1F 14 8E D8 8D 16 00-00 B4 09 CD 21 B8 00 4C …………!..L
-q

E:\Download\Masm>
——————————————————————————
上面是什么呀?,還記得前面說(shuō)的嗎?
1420:0000 B81F14 MOV AX,141F
| | | | |
段址:偏址 機(jī)器語(yǔ)言 mov指令 把段地址的地址(141f)賦值給AX寄存器。

1420:0012后面的是垃圾數(shù)據(jù),不用管它,把上面程序與源程序作一個(gè)比較,看有什么不用,差別在于把標(biāo)號(hào)語(yǔ)言轉(zhuǎn)成實(shí)際地址了。
程序前兩行一執(zhí)行,數(shù)據(jù)段地址就變成了141f,而那個(gè)字符串偏移地址在0000,由(LEA DX,[0000]看出),所以我用-d 141f:0000 L20(后面L20表示只顯示20個(gè)字節(jié)),就能把段地址顯示出來(lái)了。
所以剛才的程序在內(nèi)存中就變成了:
141f:0000 Hello, Mr.286.$ —–>這是段地址里的內(nèi)存
1420:0000 B81F14 MOV AX,141F ——>這是代碼段里的內(nèi)存。data變成了實(shí)際地址
1420:0003 8ED8 MOV DS,AX
1420:0005 8D160000 LEA DX,[0000] ——>偏址變成了0000,因?yàn)閷?shí)際上msg也就是從頭開(kāi)始的。當(dāng)然是0了。
1420:0009 B409 MOV AH,09 ——->注意Debug里,默認(rèn)的是十六進(jìn)制
1420:000B CD21 INT 21
1420:000D B8004C MOV AX,4C00
1420:0010 CD21 INT 21
剛剛學(xué)習(xí)了8086/8088匯編語(yǔ)言,發(fā)現(xiàn)尋址方式非常重要,于是做了一個(gè)小總結(jié),請(qǐng)各位笑納。
概念:
1.指令集:cpu能夠執(zhí)行的指令的集合。
2.指令:cpu所能夠執(zhí)行的操作。
3.操作數(shù):參加指令運(yùn)算的數(shù)據(jù)。
4.尋址方式:在指令中得到操作數(shù)的方式。
現(xiàn)在就重點(diǎn)討論尋址方式,說(shuō)白了也就是cpu怎么樣從指令中得到操作數(shù)的問(wèn)題。另外再?gòu)?qiáng)調(diào)一點(diǎn)操作數(shù)還分種類(lèi):
1)數(shù)據(jù)操作數(shù):全都是在指令當(dāng)中參加操作的數(shù)據(jù)。
1.立即操作數(shù):它在指令中直接給出。
2.寄存器操作數(shù):它被放到寄存器中。
3.存儲(chǔ)器操作數(shù):當(dāng)然在存儲(chǔ)器也就是內(nèi)存中。
4.i/o操作數(shù):它在你給出的i/o端口中。
2)轉(zhuǎn)移地址操作數(shù):在指令當(dāng)中不是參加運(yùn)算或被處理的數(shù)據(jù)了,而是轉(zhuǎn)移地址。
還可以按照下面分類(lèi)方式:
1)源操作數(shù)src
2)目的操作數(shù)dst
源操作數(shù)都是指令當(dāng)中的第2個(gè)操作數(shù),在執(zhí)行完指令后操作數(shù)不變。而目的操作數(shù)是指令當(dāng)中的第1個(gè)操作數(shù),在執(zhí)行完操作指令后被新的數(shù)據(jù)替代。
我們就圍繞這幾種操作數(shù),也就是操作數(shù)所在的位置展開(kāi)討論。
先說(shuō)數(shù)據(jù)操作數(shù),它分3大類(lèi)共7種。
1)立即數(shù)尋址方式:是針對(duì)立即操作數(shù)的尋址方式。在指令當(dāng)中直接給出,它根本就不用尋址。
例1:mov ax,1234h
mov [bx],5678h
在這里1234h和5678h都是立即操作數(shù),在指令當(dāng)中直接給出。
2)寄存器尋址方式:是針對(duì)寄存器操作數(shù)的尋址方式,它在寄存器中我們就用這中方式來(lái)找到它。
例2:mov bx,ax
mov bp,[si]
在這里ax,bx,ds都算是寄存器尋址,例1中的ax也是寄存器尋址方式。
3)存儲(chǔ)器尋址方式:針對(duì)在內(nèi)存中的數(shù)據(jù)(存儲(chǔ)器操作數(shù))都用這種方式來(lái)尋找,一共有5種(這是我自己的說(shuō)法,便于記憶)。
不得不提及以下的概念:由于8086/8088的字長(zhǎng)是16bit,能夠直接尋址2的16次方也就是64kb,而地址總線是20bit,能夠直接尋址2的20次方也就是1M空間,所以把內(nèi)存分為若干個(gè)段,每個(gè)段最小16byte(被稱(chēng)為小節(jié)),最大64kb,它們之間可以相互重疊,這樣一來(lái)內(nèi)存就被分成以16byte為單元的64k小節(jié),cpu就以1小節(jié)為單位尋址:在段寄存器中給出段地址(16bit),在指令當(dāng)中給出段內(nèi)偏移地址(16bit),然后把段地址左移4bit再與偏移地址求和就得到數(shù)據(jù)在內(nèi)存當(dāng)中的實(shí)際物理地址了,因而可以找到數(shù)據(jù)。
1.存儲(chǔ)器直接尋址方式:在指令當(dāng)中以 [地址] 的方式直接給出數(shù)據(jù)所在內(nèi)存段的偏移地址。
例3:mov ax,es:[1234h]
mov dx,VALUE
mov dx,[VALUE]
在這里[1234h]和VALUE就是在指令中直接給出的數(shù)據(jù)所在內(nèi)存段的偏移地址(16bit)。
VALUE是符號(hào)地址,是用偽指令來(lái)定義的,它代表一個(gè)在內(nèi)存中的數(shù)據(jù)(也就是它的名字)。es:是段前綴符,用來(lái)指出段地址,在這之前應(yīng)該將段地址添入段中,本例中是es,默認(rèn)是ds,也就是不需給出。應(yīng)該注意 [地址] 與立即尋址的區(qū)別,在直接給出的數(shù)據(jù)兩邊加 [] 表示存儲(chǔ)器直接尋址,以區(qū)別立即尋址。另外 VALUE=[VALUE]。
2.寄存器間接尋址:不是在指令中直接給出數(shù)據(jù)在內(nèi)存中的偏移地址,而是把偏移地址放到了寄存器中。
例4:mov ax,[bx]
這里[bx]就是寄存器間接尋址,bx中應(yīng)方入段內(nèi)偏移地址。其中:若使用bx,si,di默認(rèn)段地址為ds,若使用bp則默認(rèn)段地址為ss,并且允許段跨越,也就是加段前綴符。注意:在寄存器兩邊加 [] 以與寄存器尋址區(qū)別。
3.寄存器間接相對(duì)尋址:偏移地址是bx,bp,si,di中的內(nèi)容再與一個(gè)8bit或16bit 的位移量之和。
例5:mov ax,[bx]+12h
mov ax,[si]+5678h
mov ax,[bp]+1234h
在這里[bx]+12h,[si]+5678h,[bp]+1234h都是寄存器間接相對(duì)尋址。12h是8bit位移量,1234h和5678h是16bit位移量。若使用bx,si,di則默認(rèn)段寄存器是ds,若使用bp則默認(rèn)段寄存器是ss,并且允許段跨越。
4.基址變址尋址:偏移地址是一個(gè)基址寄存器和一個(gè)變址寄存器內(nèi)容的和,既:bx或bp中的一個(gè)與si或di中的一個(gè)求和而得到。
例6:mov ax,[bx+si]
mov ax,[bp+di]
上面[bx+si]和[bp+di]都是基址變址尋址。若使用bx做基址寄存器則默認(rèn)段地址為ds,若使用bp為基址寄存器則默認(rèn)段為ss,允許段跨越。
5.基址變址相對(duì)尋址:偏移量是一個(gè)基址寄存器一個(gè)變址寄存器只和再與一個(gè)8bit或一個(gè)16bit位移量只和得到。
例7:mov ax,[bx+si]+12h
mov ax,[bp+di]+1234h
[bx+si]+12h和[bp+di]+1234h就是基址變址相對(duì)尋址。若使用bx做基址寄存器則默認(rèn)段是ds,若使用bp做基址寄存器則默認(rèn)段為ss。允許段跨越。

下面是轉(zhuǎn)移地址操作數(shù)的尋址方式:
1)段內(nèi)直接轉(zhuǎn)移
1.段內(nèi)直接短轉(zhuǎn)移:cs(代碼段)內(nèi)容不變,而ip(指令指針寄存器)內(nèi)容由當(dāng)前ip內(nèi)容+(-127~127),在指令中直接給出。
例8:jmp short SHORT_NEW_ADDR
其中,short是段內(nèi)短轉(zhuǎn)移的操作符,用以指出是轉(zhuǎn)移到當(dāng)前位置前后不超過(guò)±127字節(jié)的地方。而NEW_ADDR是要轉(zhuǎn)移到的符號(hào)地址,它的位置應(yīng)該在當(dāng)前ip指針?biāo)谄频刂凡怀^(guò)
±127的地方。否則語(yǔ)法出錯(cuò)。
2.段內(nèi)直接近轉(zhuǎn)移:cs內(nèi)容不變,而ip內(nèi)容由當(dāng)前ip內(nèi)容+(-32767~32767),在指令中直接給出。
例9:jmp near ptr NEAR_NEW_ADDR
其中near ptr是段內(nèi)近轉(zhuǎn)移的操作符,用以指出轉(zhuǎn)移到當(dāng)前位置前后不超過(guò)±32767的地方。NEAR_NEW_ADDR是要轉(zhuǎn)移到的符號(hào)地址。
2)段內(nèi)間接轉(zhuǎn)移:cs的內(nèi)容不變,而ip的內(nèi)容放在寄存器中或者存儲(chǔ)器中給出。
例10:jmp bx
jmp word ptr [bx]+1234h
這種尋址方式是在寄存器或存儲(chǔ)器中找到要轉(zhuǎn)移到的地址,而地址是16bit的,因而寄存器必須為16bit,如:bx,我們用word ptr來(lái)指定存儲(chǔ)器單元也是16bit的。注意:它是間接的給出,只能使用類(lèi)似于數(shù)據(jù)操作數(shù)中的除立即尋址以外的6種尋址方式(就在上面)。
3)段間直接尋址:cs和ip的內(nèi)容全都變化,由指令當(dāng)中直接給出要轉(zhuǎn)移到的某一個(gè)段內(nèi)的某一個(gè)偏移地址處。
例11:jmp 1234h:5678h
jmp far ptr NEW_ADDR
1234h送入cs中作為新的段地址,5678h送入ip中作為新的偏移地址。far ptr是段間直接轉(zhuǎn)移操作符,NEW_ADDR是另外一個(gè)段內(nèi)的偏移地址,在這個(gè)指令中把NEW_ADDR的段地址送入cs(不用你給出),把它的段內(nèi)偏移地址送入ip中作為新的偏移地址。
4)段間間接尋址:cs和ip的內(nèi)容全變化,由指令當(dāng)中給出的一個(gè)4字節(jié)連續(xù)存儲(chǔ)單元,其中低2字節(jié)送入ip作為偏移地址,高2字節(jié)送入cs作為段地址。
例12:jmp dword ptr [bx][si]+1234h
jmp dword ptr [1234h]
jmp dword ptr [si]
dword ptr是雙字(4個(gè)字節(jié)連續(xù)存儲(chǔ)單元)操作符,用來(lái)指出下面的存儲(chǔ)單元是4個(gè)字節(jié)的。由于它是4個(gè)字節(jié)的,所以只能使用類(lèi)似于數(shù)據(jù)操作數(shù)中的存儲(chǔ)器尋址方式(共5種,還記得嗎?)。

另外作為特殊的尋址方式還有三種:I/O尋址,串尋址,隱含尋址。它們都分別針對(duì)I/O指令,串操作指令以及無(wú)操作數(shù)的指令,而且都比較簡(jiǎn)單,讀者自行總結(jié)。

到此為止說(shuō)明了8086/8088cpu中的所有尋址方式,我這里只是個(gè)總結(jié),具體的細(xì)節(jié)還要大家自己鉆研課本,才能理解。
寫(xiě)的有些倉(cāng)促可能有些遺漏或錯(cuò)誤,還請(qǐng)諒解。

總結(jié)

以上所述是小編給大家介紹的匯編語(yǔ)言入門(mén)教程,希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
如果你覺(jué)得本文對(duì)你有幫助,歡迎轉(zhuǎn)載,煩請(qǐng)注明出處,謝謝!

相關(guān)文章

  • 匯編語(yǔ)言LDR指令和LDR偽指令詳解

    匯編語(yǔ)言LDR指令和LDR偽指令詳解

    這篇文章主要介紹了匯編語(yǔ)言LDR指令和LDR偽指令詳解,偽指令是用來(lái)自動(dòng)拆分代碼值的,會(huì)把一條語(yǔ)句拆分成多條語(yǔ)句,本文結(jié)合示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-01-01
  • 詳解匯編語(yǔ)言RCL(帶進(jìn)位循環(huán)左移)和RCR(帶進(jìn)位循環(huán)右移)指令

    詳解匯編語(yǔ)言RCL(帶進(jìn)位循環(huán)左移)和RCR(帶進(jìn)位循環(huán)右移)指令

    這篇文章主要介紹了匯編語(yǔ)言RCL(帶進(jìn)位循環(huán)左移)和RCR(帶進(jìn)位循環(huán)右移)指令的相關(guān)知識(shí),非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-01-01
  • Go 中的循環(huán)是如何轉(zhuǎn)為匯編的(方法詳解)

    Go 中的循環(huán)是如何轉(zhuǎn)為匯編的(方法詳解)

    這篇文章主要介紹了Go 中的循環(huán)是如何轉(zhuǎn)為匯編的,本文通過(guò)循環(huán)的匯編代碼給大家講解的非常詳細(xì),代碼簡(jiǎn)單易懂,非常不錯(cuò),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-05-05
  • 純匯編實(shí)現(xiàn)打飛機(jī)小游戲的示例代碼

    純匯編實(shí)現(xiàn)打飛機(jī)小游戲的示例代碼

    這篇文章主要介紹了純匯編實(shí)現(xiàn)打飛機(jī)小游戲的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-01-01
  • 匯編基礎(chǔ)教程段的定義應(yīng)用詳解

    匯編基礎(chǔ)教程段的定義應(yīng)用詳解

    這篇文章主要為大家介紹了匯編基礎(chǔ)教程段的基本定義與應(yīng)用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步
    2021-11-11
  • 匯編語(yǔ)言軟件延時(shí)1s的實(shí)現(xiàn)方法

    匯編語(yǔ)言軟件延時(shí)1s的實(shí)現(xiàn)方法

    這篇文章主要介紹了匯編語(yǔ)言軟件延時(shí)1s的實(shí)現(xiàn)方法,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-01-01
  • 一位數(shù)乘法的匯編語(yǔ)言實(shí)現(xiàn)方法

    一位數(shù)乘法的匯編語(yǔ)言實(shí)現(xiàn)方法

    這篇文章主要介紹了一位數(shù)乘法的匯編語(yǔ)言實(shí)現(xiàn)方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-02-02
  • 匯編語(yǔ)言 寄存器內(nèi)存訪問(wèn)原理解析

    匯編語(yǔ)言 寄存器內(nèi)存訪問(wèn)原理解析

    這篇文章主要介紹了匯編語(yǔ)言 寄存器內(nèi)存訪問(wèn)原理解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-01-01
  • X86匯編調(diào)試環(huán)境搭建的過(guò)程

    X86匯編調(diào)試環(huán)境搭建的過(guò)程

    本次使用vscode搭建的,需要的插件有X86 and X86_64 Assembly(也可以使用masm插件),還有一個(gè)hexdump for VSCode。 安裝NASM,并添加到環(huán)境變量,下面看下X86匯編調(diào)試環(huán)境搭建的過(guò)程吧
    2021-11-11
  • 匯編語(yǔ)言指令集學(xué)習(xí)條件轉(zhuǎn)移指令詳解

    匯編語(yǔ)言指令集學(xué)習(xí)條件轉(zhuǎn)移指令詳解

    這篇文章主要為大家介紹了匯編語(yǔ)言指令集學(xué)習(xí)條件轉(zhuǎn)移的指令全面總結(jié)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步
    2021-11-11

最新評(píng)論