《彙編語言》學習筆記

 第一章 基礎知識
 
現在的CPU有至少三種模式: 實模式、保護模式、虛擬8086模式。
在windows上打開cmd,進入的是虛擬8086模式。所以這時的CPU地址總線是20根,即至關於8086.
進入debug調試工具能夠在DOS(實模式)下,或windows的cmd中(8086模式)。
 
另外,現在的32位系統規定內存中0-0X0000FFFF的64k空間保存給DOS使用。
 
 
 

第二章 寄存器(CPU工做原理)
 
8086全部的寄存器都是16位
其中【通用寄存器】是 AX BX CX DX
 
指令的操做對象位數必須是一致的,不然是錯誤的指令。
 
8086的地址線20位,內部是16位,所以是經過兩個16位寄存器合成一個20位的物理地址。
物理地址 = 段地址*16 + 偏移地址 (乘以16即右移四位)
 
10H是8H的2倍,在16進制中。
 
內存並無分段,段的劃分來自於CPU。
在編程時能夠根據須要,將若干地址連續的內存單元看做一個段,用段地址*16定位段的起始地址,用偏移地址定位段中的內存單元。
注意1:段的起始地址必然是16的倍數。即最後一位是0.
注意2:偏移地址是16位,所以尋址能力,即一個段的最大長度爲64KB.
注意3:CPU能夠用不一樣的段地址和偏移地址造成同一個物理地址。
 
【段寄存器】提供段地址
CS DS SS ES 
 
【CS】代碼段寄存器,【IP】指令指針寄存器
8086中,任意時刻,CPU將CS:IP指向的內容看成指令執行。
 
第10節講述了指令執行的詳細過程。
 
實驗一
【debug】
 
-r 查看、更改寄存器內容
-d 查看內存
-e 更改內存
-u 將內存中的機器指令翻譯成彙編指令
-t 執行一條機器指令
-a 以彙編格式在內存中寫入一條機器指令
-p 執行int 21h的時候用這個指令正常退出
-g 直接執行到某一地址(IP)
 
貌似個人環境中debug默認是16進制
 

第三章  寄存器(內存訪問)
 
【mov】的用法:
mov 寄存器,數據   (段寄存器不能夠)
mov 寄存器,寄存器
mov 寄存器,內存單元
mov 內存單元,寄存器
 
8086提供【棧】的設計。這意味着,咱們在基於8086CPU編程的時候,能夠將一段內存看成棧來使用。8086的入棧和出棧操做都是以字爲單位的。
入棧時,棧頂從高地址向低地址方向增加。
 
任意時刻,SS:SP指向棧頂元素。 
PUSH AX:
SP = SP - 2;
將 AX 中的內容送入 SS:SP 指向的內存單元中。
 
POP AX:
見 SS:SP 指向的內存單元的內容送入AX;
SP = SP + 2.
 
PUSH 和 POP 能夠處理寄存器和內存單元。
 
8086沒有防止棧越界的機制。
 


第四章  第一個程序
 
dos中是怎麼加載啓動程序的?
 
1.找到一段起始地址爲SA:0的足夠的內存。
 
2.前256個字節存放PSP(描述程序的前綴)。
 
3.從SA+10:0開始存放程序代碼。
 
4.將內存區的段地址存入DS。DS=SA。
  設置CS和IP指向程序入口。即CS = SA+10.
 

第五章  [BX]和loop指令
 
在彙編源程序中,數據不能以字母開頭。
 

第六章 多段程序
 
在實驗5中發現,在程序中定義一個segment,最終得到的字節數會湊整到16的倍數。
 
程序開頭的assume ...貌似沒有做用,程序不會去對應。但assume cs: 貌似是必須的,不然程序會報錯。
 
程序在編譯後由操做系統選擇一段足夠大的內存空間裝入。前256個字節是PSP, 即程序的一些描述信息,用於和操做系統的加載程序交流。
假如這段空間的起始地址是SA:0,則程序被加載後,默認:
DS=SA,
ES=SA,
SS=SA+10,
CS=SA+10+[code segment相對於源程序段的偏移位置/16].
例如,源程序:
assume cs:code,ds:data,ss:stack
data segment
dw 0                     ;雖然只定義了一個字,但data segment的長度將是16個字節。
data ends
 
stack segment
db 16 dup (0)
stack ends
 
code segment
...
code ends
end
 
加載後假設PSP起始地址是SA:0. 則:
DS =SA, 
ES=SA,
SS=SA+10,
CS=SA+11.
 
由以上能夠看出,ds、es、ss的地址都是相對於SA固定的,assume徹底沒有做用。要想改變只有用指令去賦值。而cs則有一個可變的偏移量,其值與assume的定義有關。
 
既然assume ds,es,ss是沒用的,編程時就不必寫了。經試驗徹底可行。寫這個徹底是爲了便於理解。
 
另外,debug加載程序後能夠發現,sp=0. 這說明若是不設置棧,程序會有一個默認的棧,棧頂與代碼段的起始地址相同(這裏的棧頂是指棧滿時的位置),棧的大小爲64k.

第七章   更靈活的定位內存地址的方法
 
大小字母轉換
小寫字母ASCII碼的第五位爲1,對應大寫第五位爲0.(位數從0開始數)
所以能夠用and 和 or 指令。
 
尋址方式有如下幾種:
1 [idata]
2 [bx]
3 [bx+idata]
4 [bx+si]
5 [bx+si+idata]
其中2和3中的bx能夠被si或di代替。
 

第八章  數據處理的兩個基本問題
這兩個基本問題是:數據在哪?數據有多長?
 
總結一下8086的寄存器:
8086  CPU 中寄存器總共爲 【14】 個,且均爲 16 位 。 
即 AX,BX,CX,DX,SP,BP,SI,DI,IP,FLAG,CS,DS,SS,ES 共 14 個。
而這 14 個寄存器按照必定方式又分爲了通用寄存器,控制寄存器和段寄存器。
 
【通用寄存器】:
AX,BX,CX,DX 稱做爲【數據寄存器】:
AX (Accumulator):累加寄存器,也稱之爲累加器;
BX (Base):基地址寄存器;
CX (Count):計數器寄存器; 
DX (Data):數據寄存器;
 
SP 和 BP 又稱做爲【指針寄存器】:
SP (Stack Pointer):堆棧指針寄存器; 
BP (Base Pointer):基指針寄存器;
 
SI 和 DI 又稱做爲【變址寄存器】:
SI (Source Index):源變址寄存器;
DI (Destination Index):目的變址寄存器;
 
【控制寄存器】: 
IP (Instruction Pointer):指令指針寄存器;
FLAG:標誌寄存器;
 
【段寄存器】: 
CS (Code Segment):代碼段寄存器;
DS (Data Segment):數據段寄存器;
SS (Stack Segment):堆棧段寄存器;
ES (Extra Segment):附加段寄存器;
 
【div指令】
格式: div reg
       div 內存單元  
       div後爲除數。
1 除數有8位和16位,在某一寄存器或內存單元中。
2 被除數默認在AX或DX中。若是除數爲8位,被除數則爲16位,在AX中存放。
  若除數爲16位,被除數則爲32位,在DX和AX中存放,DX存放高16位。
3 結果:若是除數爲8位,則AL存放商,AH存放餘數。若是除數爲16位,則AX存 
  商,DX存儲餘數。
 
【尋址方式小結】

尋址方式程序員

含義 (EA偏移地址,SA段地址)編程

名稱windows

[idata]緩存

EA=idata; SA=(ds)工具

 

直接尋址oop

[bx]學習

[si]spa

[di]操作系統

[bp]翻譯

EA=(bx); SA=(ds)

EA=(si); SA=(ds)

EA=(di); SA=(ds)

EA=(bp); SA=(ss)

 

寄存器間接尋址

[bx+idata]

[si+idata]

[di+idata]

[bp+idata]

EA=(bx)+idata; SA=(ds)

EA=(si)+idata; SA=(ds)

EA=(di)+idata; SA=(ds)

EA=(bp)+idata; SA=(ss)

 

寄存器相對尋址

[bx+si]

[bx+di]

[bp+si]

[bp+di]

EA=(bx)+(si); SA=(ds)

EA=(bx)+(di); SA=(ds)

EA=(bp)+(si); SA=(ss)

EA=(bp)+(di); SA=(ss)

 

基址變址尋址

[bx+si+idata]

[bx+di+idata]

[bp+si+idata]

[bp+di+idata]

EA=(bx)+(si)+idata; SA=(ds)

EA=(bx)+(di)+idata; SA=(ds)

EA=(bp)+(si)+idata; SA=(ss)

EA=(bp)+(di)+idata; SA=(ss)

 

相對基址變址尋址

另外,能夠手動指定段基址寄存器。
 
【指令要處理的數據長度】
8086CPU的指令,能夠處理兩種長度的數據,byte和word. 因此在機器指令中必需要指明。有三種方法指明:
1 經過寄存器名
2 若沒有寄存器名,用操做符X ptr指明內存單元的長度,X能夠爲word或byte.
3 有的指令默認處理字單元或字節單元。如push只進行字操做。
 

第九章 轉移指令的原理
 
能夠修改IP,或同時修改CS和IP的指令統稱爲轉移指令。
  只修改IP時,稱爲段內轉移,好比 jmp ax. 段內轉移又分短轉移和近轉移。偏移量前者爲8位,後者爲    16位。所以前者的IP修改範圍是-128~127,後者的修改範圍是-32768~32767.
  同時修改CS和IP時,稱爲段間轉移,好比 jmp 1000:0.
 
8086CPU的轉移指令分爲如下幾類:
 無條件轉移指令(如jmp)
 條件轉移指令
 循環指令(如loop)
 過程
 中斷
 
【jmp 指令】
1. jmp short 標號     翻譯成機器指令是 EBXX,XX爲8位的位移,範圍是-128~127,爲段內短轉移。
2. jmp far ptr 標號   翻譯成機器指令是 EAXXXXXXXX,包含CS和IP的目的地址,爲段間轉移。
3. jmp 寄存器           寄存器內容爲IP目的地址,爲段內近轉移。
4. jmp word ptr 內存地址    內存的字內容爲IP目的地址,爲段內近轉移。
5. jmp dword ptr 內存地址  內存的兩個字內容分別爲IP和CS地址,爲段間轉移。
 
在作實驗9的時候,個人程序即便是對的,直接執行也看不到結果,而用debug一步步執行則看到顯示緩存沒有被改變。
解決方法: 進入debug  而後 -g 執行完的地址(通常是mov ax,4c00h)原理不知道。---貌似是由於中斷。
 

第十章   call 和 ret 指令
 
call 指令至關於先push ip或者push cs, push ip,而後jmp ...
轉移的方式與上一章中的jmp用法徹底同樣。
 
ret指令相反,至關於 pop ip
retf則至關於 pop ip, pop cs
 
call 和 ret 配合使用則能夠實現子程序機制。
 
【mul指令】
1. 兩乘數同爲8位或16位。若爲8位,則一個默認在AH中,另外一個在8位寄存器或內存中;若爲16位,則一個默認在AX中,另外一個在16位寄存器或內存中。
2. 結果:若爲8位,則默認放在AX中。若爲16位,則默認DX中存放高16位,AX中存放低16位。
格式爲 mul 寄存器或內存單元。
 
爲了解決子程序與主程序【寄存器衝突】的問題,能夠這樣編寫子程序:
子程序開始:子程序中要使用的寄存器入棧
                       子程序內容
                       子程序中使用的寄存器出棧
                       返回(ret、retf)
 
由實驗10.2得出的結論:
1. div可能會出現除法溢出錯誤
2. 在程序中有兩次須要先保存ax的值,而後ax將用於別的運算。而空閒的寄存器不夠,這時就用棧來幫忙。不過棧有出棧順序的問題,這多是一個障礙。即若是你進棧以後又有別的數據進棧,此時你想出棧就得先把另外一個數據出棧。
 

第十一章  標誌寄存器
 
標誌寄存器 flag 中存儲的信息一般稱爲程序狀態字(PSW).
 
1. ZF,在flag的第6位,零標誌位。相關指令執行後的結果如爲0,則ZF=1。運算指令如add、sub等會影響ZF位,而傳送指令如mov、push等指令則不影響。
2. PF,在flag的第2位,奇偶標誌位。相關指令執行後的結果的全部二進制位中1的個數如爲偶數,則PF=1.
3. SF,在flag的第7位,符號標誌位。相關指令執行後的結果如爲負,則SF=1。咱們看待數據能夠是有符號數(補碼錶示),也能夠是無符號數,這兩種在計算機中的表示和計算都是同樣的。所以計算指令必定會影響SF位,而咱們不必定須要這種影響。
4. CF,在flag的第0位,進位標誌位。記錄了運算結果的最高有效位向更高位的進位值,或從更高位的借位值。CF進位針對的是無符號數。
5. OF,在flag的第11位,溢出標誌位。好比8位寄存器,所能表示的範圍是-128~127. 若是結果超出這個範圍,則OF=1. OF位針對的是有符號數。
6. DF , 在flag的第10位,方向標誌位。在串處理指令如movsb,movsw中,控制每次操做後si,di的增減。8086CPU提供兩條指令對DF位進行設置: cld指令: 將DF置0;std指令:將DF置1.
 
要注意CF和OF的區別。CPU在執行add等指令的時候,包含兩種含義:無符號數運算和有符號數運算。對於無符號數運算,CPU用CF位來記錄是否產生了進位;對於有符號數運算,CPU用OF位來記錄是否產生了溢出,以及用SF位來記錄結果的符號。
 
adc,帶進位加指令。格式: adc 對象1,對象2. 功能: 對象1=對象1+對象2+CF. 利用adc和add配合就能夠對更大的數據進行加法運算。
sbb , 帶借位減指令。原理與adc相同。
 
cmp , 比較指令。 格式:cmp 對象1,對象2. 功能: 計算【對象1-對象2】,但不保存結果,僅根據結果對flag進行設置。
 
條件轉移指令。全部的條件轉移指令的轉移範圍都是-128~127. 如je,jne,jb,jnb,ja,jna. 條件轉移指令每每和jmp指令結合使用,但並非必須的。jmp指令只負責比較後設置相應flag位,條件轉移指令則根據相應flag位決定是否跳轉.
 
串傳送指令: movsb,movsw. 前者一次傳送一個字節,後者傳送一個字  
movsb至關於 mov es:[di],byte ptr ds:[si]    ;8086並不支持這樣的指令,這裏只是個描述。
;若是DF=0
inc si  
inc di
;若是DF=1
dec si
dec di
通常來講,movsb和movsw都和rep配合使用,格式: rep movsb;至關於:
s:    movsb
      loop s
 
pushf,將flag值壓棧,popf,將flag值出棧。
 

第十二章  內中斷
 
中斷類型碼爲一個字節型數據,能夠表示256種中斷信息。產生中斷信息的事件稱爲中斷源。CPU內部有4種中斷源:
1. 除法錯誤。如除法溢出。 中斷碼:0
2. 單步執行。中斷碼:1
3. 執行 int0 指令。中斷碼:4
4. 執行 int 指令。格式爲int n , n 便是提供給CPU的中斷類型碼。
 
CPU用8位的中斷類型碼經過中斷向量表找到相應的中斷處理程序的入口地址。中斷向量表就是中斷向量的列表。而中斷向量就是中斷處理程序的入口地址。即,中斷向量表就是中斷處理程序的入口地址的列表。
8086規定中斷向量表存放在內存的0000:0000到0000:03E8的1000個內存單元中。
 
中斷過程:從響應中斷到設置完CS和IP到中斷向量,這個過程是由CPU硬件自動完成的,這個過程稱爲中斷過程。
1 取得中斷類型碼N;
2 pushf
3 TF=0,IF=0
4 push CS
5 push IP
6 (IP)=(N*4), (CS)=(N*4+2)
以後,CPU開始執行由程序員編寫的中斷處理程序。
 
中斷處理程序:
1 保存用到的寄存器
2 處理中斷
3 恢復用到的寄存器
4 用iret指令返回
iret出棧的順序與中斷過程的入棧順序相反。
 
--------------------------------------------------
因時間關係,看到這裏對彙編語言的學習告一段落。
--------------------------------------------------
相關文章
相關標籤/搜索