一、基礎知識
mov ax,bx把BX內容送到AX中。匯編語言有3類指令,匯編指令、偽指令,其他符號。CPU通過地址總線、控制總線、數據總線實現數據的讀寫。數據總線的寬度決定了CPU和外界的數據傳送速度。匯編指令是機器指令的助記符,同機器指令一一對應,只是寫法不同而已。主存是RAM,一般顯卡有顯卡RAM。CPU在操作物理器件如顯卡、網卡等時,實際上是這些設備都在物理存儲器中有對應的空間,CPU操作的是他們對應的這段空間(在其中讀寫數據)。
二、寄存器
對8086CPU,其寄存器都是16位的,AX,BX,CX,DX用來存放一般性的數據,被稱為通用寄存器,為兼容其上一代CPU中寄存器為8位的情況,這四個寄存器都可分為兩個可獨立使用的8位寄存器使用,由X分為H和L,如AX可分為AH和AL。16進制也可直接加,如4E20+1406=6226H,如原來AX中是00C5H,經過add al,93H,al與C5H相加得到158H,然后高位1丟失(只是寄存器不能保存,但CPU并不真是丟棄這個進位值)。進行數據傳送或運算時,兩個操作對象的位數應一致,如mov ax,bl有問題,mov al,100H是將一個高于位的數存放到8位寄存器中,也有問題。8086CPU的上一代8080、8085等是8位機,8086有20位地址總線達到1MB尋址能力,8086CPU又是16位結構,它實際是兩個16位地址合成的方法來形成一個20位的物理地址,物理地址=段地址16(左移4位)+偏移地址,應用到CPU尋址上,段(SA)16+偏移(EA)找到對應內存,因此段的起始地址是16的倍數,偏移為16位,因此大小為64KB,可根據需要將地址連續、起始地址為16的倍數的一組內存單元定義為一個段。8086CPU有4個段寄存器,CS、DS、SS、ES,CS為代碼段寄存器,IP為指令指針寄存器,在8086PC機中,設CS內容為M,IP內容為N,則8086CPU將從內存M*16+N單元開始讀取一條指令并執行即CS:IP中的指令作為當前指令,從CS:IP中讀取的指令放入指令緩沖器,IP在操作過程中會自加,8086CPU加電啟動后CS和IP被設置為FFFFH和0000H。 mov可改變通用寄存器的值,其指令被稱為傳送指令,但不能改變CS、IP中的值,他們需要轉移指令,如jmp,可用jmp 段地址:偏移地址,若只改IP用jmp 某一合法寄存器,如jmp ax,在Debug下,查看內存時對應ASCII會顯示,如果對應無可顯示內容,如0AH,則會可能會顯示為...(點點點)。
三、寄存器(內存訪問)
DS寄存器用來訪問數據的段地址。如mov bx,1000H mov ds bx mov al,[0]相當于把10000H的數據讀到al中,其中[0]是內存單元的偏移,其段地址會從ds中找,因為數據不能直接mov到段寄存器中,所以要用通用寄存器中轉,但內存單元,如[0]可直接到段寄存器。除mov,操作還有add,sub,jmp。 在基于8086CPU編程時,可將一段內存當作棧來使用,push,pop,其入和出都是以字為單位的,如以10000H~1000FH內存用作棧,壓棧時以10000H為頂,段寄存器SS存放棧頂的段地址,即10000H,寄存器SP存放偏移地址,任意時刻SS:SP指向棧頂,入棧時棧頂從高向低地址方向增長,當棧為空時,不存在棧頂,SS:SP只能指向棧的最底部單元下面的單元,如一個空棧先壓入再pop,則之前的數據會依然存在,但它們已不在棧中(可直接用地址訪問到但不能用棧操作),再次push會覆蓋掉這些內容,對棧CPU并未設置越界保護如push,pop過頭,可自己判定,push,pop的對象可是通用、段寄存器及內存(如設置ds后,push [0]),如要清空AX中內容,用sub ax, ax而不用mov ax, 0因為后者的機器碼為3個字節而前者只用2個,除此外還有and,xor(指令短且最快),壓棧時是SP先減2,再壓棧的,可根據空棧時壓棧想象,對一個大小設定為64K的棧,如棧滿了還繼續壓棧,則棧頂將環繞,覆蓋原來棧底的內容,段是自己定義的,對一段內存,可以既是代碼既是存儲空間,又是數據存儲空間還可是棧空間。
四、第一個程序
codesg和ends是一對成對使用的偽指令,其功能是定義一個段,需要也一個段名,至少有一個代碼段。end偽指令標識整個程序結束,assume偽指令假設某一段寄存器和程序中的某一個段相關聯,如assume cs:codesg將自定義的代碼段codesg和cs聯系起來,mov ax,4c00H int 21H用于程序返回。
五、[BX]和loop指令
[bx]表內存單元的偏移,約定符號idata表常量。inc bx表bx中的內容加1。loop 標號,cx里是執行次數,標號:指令。可mov ax,[bx]也可mov al,[bx]。在匯編源程序中,數據不能以字母開頭,如要寫成mov ax,0ffa3H。在debug下可直接用[0]表偏移為0,但在masm的匯編源程序中,此值表示數字0,有時可經bx再[bx]傳入或直接指明段地址所在的段寄存器,如mov al,ds:[0]。附加段寄存器ES:存放當前執行程序中一個輔助數據段的段地址。
六、包含多個段的程序
定義段后,可用dw(define word)定義字型數據,且這些數據處于代碼段的最開始位置。如前面設置個入口地址標志start,后面加end start則由end指定程序的開始位置是start,如果只用end則表示程序結束,可在前面定義數據,后面不規則指定開始標志。程序剛開始assume cs:code時系統會為其分配空間。將段用于棧可mov ax,cs mov ss,ax mov sp ,10H(指定頂)。
七、更靈活的定位內存地址的方法
and,or。db 'unIX',mov al,'a'。ASCII大小寫差20H,即在第6位上大寫為0,小寫為1,可用and/or方式轉換大小寫。可用[bx+idata]方式指定內存單元或idata[bx](如0[bx],5[bx]此方式同C語言中的下標如a[i],b[i]),[bx].200等。SI、DI是8086CPU中和BX功能相近的寄存器,如設置SI為源位置,DI為目標位置進行復制操作,[bx+si]或[bx+di],也可寫成[bx][si],[bx][di],[bx+si(di)+idata]或idata[bx][si]或[bx].200[si]或[bx][si].200,可認為idata是一個常量,而bx,si,di是變量。對于多層循環,可先把外層cx保存起來,內層循環退出后再恢復,可用棧的方式臨時保存數據。
八、數據處理的兩個基本問題
bx,bp,si,di可單獨使用,但bx與bp不能同時使用,si與di不能同時使用。直接包含在機器指令中的數據(執行前在CPU的指令緩沖器中),在匯編語言中稱為立即數(idata),bp類似sp段地址默認在ss中。尋址方式有:直接尋址,寄存器間接尋址,寄存器相對尋址,基址變址尋址(bx/bp+si/di),相對基址變址尋址。顯示指明數據操作單位長度:X ptr其中X為word或byte,如mov word ptr ds:[0],1,inc是16位,但inc si只是增加1。div是除法,除數是8位時被除數為16位放在AX中,商在AL,余數在AH,除數是16位時被除數為32位,高位16位在DX,低16位在AX中,商在AX,余數在DX中。偽指令dd用來定義dword(double dword類型),偽指令dup用于數據重復,db(dw,dd) 次數 dup (重復的數據)。
九、轉移指令的原理
操作符offset用來取標號的偏移地址,如offset start,結果是一個數字。jmp無條件,分段間、段內短轉移(-128127)、段內近轉移(-3276832767)。jmp short 標號,段內短轉移,使用jmp 標號時,會被轉成jmp 對應標號處指令的地址,然后其機器碼可能為EB03看不到目標地址,其中03是跳轉的偏移量,jmp short 標號的功能是(IP)=(IP)+8位位移(可能為負值),jmp near ptr 標號是16位,jmp far ptr 標號段間轉移(遠轉移),如對應機器碼為EA 0B 01 BD 0B其中高地址BD 0B是段地址,0B01是偏移地址。轉移地址在內存中的格式為:jmp word ptr 地址(段內轉移)或jmp dword ptr 地址(段間)(高地址字是段地址,CS=內存單元地址+2,IP=內存單元地址)。jcxz有條件轉移(所有有條件轉移指令都是短轉移),當(cx)=0時轉移不為0時不轉移。loop所有的循環指令都是短轉移。jmp short,jmp near ptr, jcxz,loop,在機器碼中包含的是位移(由補碼給出)而不是目的地址,此設計是為了程序段在內在中浮動裝配。
十、CALL和RET指令
ret指令用棧中的數據,修改IP實現近轉移,retf修改CS和IP實現遠轉移。call指令將當前IP或CS和IP壓入棧中然后轉移,且不能實現短轉移,轉移方式可是jmp near ptr 標號(16位偏移),或jmp far ptr 標號,或轉移地址在寄存器中,如call ax,或轉移地址在內存中如call word ptr 地址(只改IP)或call dword ptr 地址(改CS、IP)。mul只能是88位(一個默認在AL中,另一個在reg或內存中,結果在AX)或1616位(一個默認在AX中,另一個在reg或內存中,結果高位在DX,低位在AX)。
十一、標志寄存器
8086CPU中標志寄存器有16位,其中存儲的信息通常被稱為程序狀態字(PSW),有ZF(零),PF(奇偶),SF(符號),CF(進位),OF(溢出)(CF是對無符號數運算有意義的標志位,而OF是對有符號數運算有意義的標志位,兩者是獨立的,用哪種只與數是否有符號有關)。利用adc可對任意大的數據進行加法,對于連續兩個inc si,inc不會改變cf標志,add可能會修改cf,前面的adc需要加上cf,所有有時不能用add 2來代替inc,sbb帶借位減法。cmp比較指令,功能相當于減法只是不保存結果,執行后將對標志寄存器產生影響,如cmp ax,ax不改變ax的值,但zf,pf=1,sf,cf,of=0。常用無符號轉移指令:je,jne,jb,jnb,ja,jna。DF方向標志位,為0每次si、di遞增,為1遞減,串傳指令:movsb將ds:si指向的內存單元中的字節送入es:di中,再根據df將si和di遞增或遞減,也有movsw,配合rep使用如rep movsb,movsw,根據cx值確定次數。cld命令是設置df=0。pushf將標志寄存器的值壓棧,popf反之。在debug中,of對應OV,NV,sf對NG,PL,zf對ZR,NZ等。
十二、內中斷
內中斷可有除法錯誤(中斷類型碼為0),單步執行(1),執行into指令(4),int(指定),中斷類型碼的作用就是用來定位中斷處理程序。iret指令的作用是彈出IP、CS,及popf。
十三、int指令
int 10h顯示到屏幕。
十四、端口
對端口的讀寫用in,out。移位指令:shl,shr,移動次數放在cl中。BCD碼是以4位二進制數表示十進制數碼的編碼方法。
十五、外中斷
如鍵盤int 9。