《匯編語言》(王爽)筆記


1、有多少根控制總線,就意味着CPU提供了對外部器件的多少種控制。

 

2、匯編指令 偽指令

 

3、CPU通過總線控制接口,接口控制設備

 

4、CPU對物理器件的操作,通過控制線發出內存讀寫命令,把他們都當作內存來對待。所有的物理存儲器被看作一個由若干存儲單元組成的邏輯存儲器,每個物理存儲器在這個邏輯存儲器中張有一個地址段,即一段地址空間。CPU在這段地址空間中讀寫數據,實際上就是在相對應的物理存儲器中讀寫數據。

 

5、內部總線實現CPU內部各個器件之間的聯系,外部總線實現CPU和主板上其他器件的聯系。

 

6、

mov ax,8226
mov bx,ax
add ax,bx

ax + bx = 1044CH
ax = 044CH(最高位並不丟棄,只是存不下)

7、

mov ah,0
mov al,C5H
add al,93H

al + 93H = 158H
ax = 0058H(此時al作為一個獨立的8位寄存器來使用的,和ah沒有關系,CPU在執行這條指令是認為ah和al是兩個不相關的寄存器。不要錯誤的認為,諸如add al,93H的指令產生的進位會存儲在ah中,add al,93H 進行的是8為運算)

add ax,93H
ax =
0158H(如果執行add ax,93H ,低8位的進位會存儲在ah中,CPU在執行這條指令時認為只有一個16位寄存器ax,進行的是16位運算。)

8、 在8086PC機中,存儲單元的地址用兩個元素來描述,即段地址和偏移地址
段地址*16 + 偏移地址 = 物理地址
一個段的起始地址一定是16的倍數,一個段的長度最大為64KB

9、 4個段寄存器:cs、ds、ss、es

 

10、CS、IP是8086CPU中兩個最關鍵的寄存器,它們指示了CPU當前要讀取指令的地址。CS為代碼段寄存器,IP為指令指針寄存器。在8086PC機中,任意時刻,設CS中的內容為M,IP中的內容為N,8086CPU將從內存M*16+N單元開始,讀取一條指令並執行。(CS:IP)

 

11、8086CPU工作過程
(1)從CS:IP指向的內存單元讀取指令,讀取的指令進入指令緩沖器
(2)IP = IP + 送讀取指令的長度,從而指向下一條指令
(3)執行指令。轉到步驟(1),重復這個過程

12、ax、bx、cx、dx 可以用mov指令來改變,mov指令被稱為傳送指令,但是mov指令不能用於設置cs、ip的值,原因很簡單,因為8086CPU沒有提供這樣的功能。8086CPU為CS、IP提供了另外的指令來改變它們的值。能夠改變CS、IP的內容的指令被統稱為轉移指令。
jmp 2AE3:3,執行后:CS=2AE3H,IP=0003H,CPU將從2AE33H處讀取指令
若想僅修改IP的內容,可用形如“jmp 某一合法寄存器”的指令完成,如
jmp ax,指令執行前:ax=1000H,cs=2000H,ip=0003H
指令執行后:ax=1000H,cs=2000H,ip=1000H

13、Debug指令

R P   A T   E D U

 

14、[]說明操作對象是一個內存單元,[]中是內存單元的偏移地址,它的段地址默認放在ds中。
如何把一個數據送入ds呢?我們以前用類似“mov ax,1”這樣的指令來完成,從理論上講,我們可以用相似的方式:mov ds,1000H,來將1000H送入ds。可是,現實並非如此,8086CPU不支持將數據直接送入段寄存器的操作,ds是一個段寄存器,所以 mov ds,1000H這條指令是非法的。那么如何將1000H送入ds呢?只好用一個寄存器來進行中轉,即先將1000H送入一個一般寄存器,如bx,再將bx中的內容送入ds。(立即數到段寄存器,硬件設計問題,他們之間沒有通路)

15、棧頂的段地址存放在SS中,偏移地址存放在SP中。任意時刻,SS:SP指向棧頂元素。push指令和pop指令執行時,CPU從SS和SP中得到棧頂的地址。

 

16、如果將10000H~1000FH這段空間當作棧,初始狀態棧是空的,此時,SS=1000H,SP=?
SP=0010H

17、

push sp-=2
pop sp+=2

18、棧空間當然也是內存空間的一部分,它只是一段可以以一種特殊的方式進行訪問的內存空間。

 

19、Debug的T命令在執行修改寄存器SS的指令時,下一條指令也緊接着被執行。

 

20、段結束、程序結束、程序返回

 

21、編譯時發現的錯誤:語法錯誤
運行時發現的錯誤:邏輯錯誤

22、操作系統是由多個功能模塊組成的龐大、復雜的軟件系統。任何通用的操作系統,都要提供一個稱為shell的程序,用戶使用這個程序來操作計算機系統進行工作。DOS中有一個程序command.com,這個程序在DOS中稱為命令解釋器,也就是DOS系統的shell

 

23、CPU執行loop指令需要兩步:先減一,后判斷,然后跳轉
①(cx) = (cx)-1 ②判斷cx中的值,不為零則轉至標號處繼續循環
assume cs:code


code segment
mov ax,2

  mov cx,11 ;循環框架,3步
s:   add ax,ax
  loop s

mov ax,4c00h
int 21h ;int指令要用P執行,其他的用t
code ends


end

24、在匯編程序中,數據不能以字母開頭,要在前面加0。比如,9138h在匯編源程序中可以直接寫為9138h,而a000h在匯編源程序中要寫為0a000h。

 

25、Debug中,執行到指定地址用g,
eg: g 0012 ;執行到cs:0012
Debug中,跳出循環用p指令
遇到loop 0012時,用p執行

26、

(1)在匯編源程序中,如果用指令訪問一個內存單元,則在指令中必須用[]來表示內存單元,如果在[]里用一個常量idata直接給出內存單元的偏移地址,就要在[]的前面顯示地給出段地址所在的段寄存器。比如:
mov al,ds:[0]
如果沒有在[]的前面顯示地給出段地址所在的段寄存器,比如:
mov al,[0]
那么,編譯器masm將把指令中的[idata]解釋為idata
(2)如果在[]里用寄存器,比如bx,間接給出內存單元的偏移地址,則段地址默認在ds中。當然,也可以顯式地給出段地址所在的段寄存器。

 

27、dw define word

 

28、and指令,可將操作對象的相應位設為0,其他位不變。or指令,可將操作對象的相應位設為1,其他位不變。
大小寫轉換,加減20h,做or或者and運算實現

 

29、
20H
0010 0000 B
將第五位置0,相當於減20h
and al,11011111
將第五位置1,相當於加20h
or al,00100000

30、mov ax,[200+bx]
mov ax,200[bx] ;類似於高級語言的數組,200相當於數組名,bx相當於下標
mov ax,[bx].200

 

31、bx,bp,si,di
(1)在8086CPU中,只有這4個寄存器可以用在[]中進行內存單元的尋址。比如下面的指令都是正確的:
mov ax,[bx]
mov ax,[bp]
mov ax,[bx+si]
mov ax,[bx+di]
mov ax,[bp+si]
mov ax,[bp+di]
下面的指令都是錯誤的:
mov ax,[cx]
mov ax,[ax]
mov ax,[dx]
mov ax,[ds]
(2)在[]中,這4個寄存器可以單個出現,或只能以4種組合出現:bx和si、bx和di、bp和si、bp和di
(3)只要在[]中使用寄存器bp,而指令中沒有顯性地給出段地址,段地址就默認在ss中。比如下面的指令
mov ax,[bp]
mov ax,[bp+idata]
mov ax,[bp+si}
mov ax,[bp+si+idata]
其他情況,默認段寄存器為ds


32、尋址方式
1、立即數尋址
2、直接尋址
[idata]
3、寄存器間接尋址
[bx][bp][si][di]
4、寄存器相對尋址
[bx+idata][bp+idata][si+idata][di+idata]
5、基址變址尋址
[bx+si][bx+di][bp+si][bp+di]
6、相對基址變址尋址
[bx+si+idata][bx+di+idata][bp+si+idata][bp+di+idata]


33、div(da高低余商)
被除數:如果除數為8位,被除數則為16位,默認放在ax中;如果除數為16位,被除數為32位,dx存放高16位,ax存放低16位。
結果:如果除數為8位,則al存儲除法操作的商,ah存儲除法操作的余數;如果除數為16位,則ax存儲除法操作的商,dx存儲除法操作的余數。


34、dd define double word


35、db 3 dup(0) 定義了3個字節

db 3 dup(0,1,2) 定義了9個字節
db 3 dup('abc','ABC') 定義了18個字節


36、jmp short 標號//段內短轉移,它對IP的修改范圍為-128~127
jmp near ptr 標號//段內近轉移,它對IP的修改范圍為-32768~32767
jmp far ptr 標號//段間轉移,cs=標號所在段的段地址;ip=標號所在段的偏移地址


(機器碼中,轉移位移的計算方法)


37、轉移地址在內存中的jmp指令
jmp word ptr 內存單元地址(段內轉移)
jmp dword ptr 內存單元地址(斷間轉移,從內存單元地址處開始存放着兩個字,高地址處的字是轉移的目的段地址,低地址處是轉移的目的偏移地址)


38、所有的有條件轉移指令都是短轉移
jcxz(如果(cx)==0,轉移到標號處執行)


39、所有的循環指令都是短轉移
loop((cx)=(cx)-1,如果(cx)≠0)


40、ret指令用棧中的數據,修改IP的內容,從而實現近轉移;
(ip)=((ss)*16+(sp))
(sp)=(sp)+2
相當於 pop IP
retf指令用棧中的數據,修改CS和IP的內容,從而實現遠轉移
(ip)=((ss)*16+(sp))
(sp)=(sp)+2
(cs)=((ss)*16+(sp))
(sp)=(sp)+2
相當於 pop IP
pop CS


41、call將當前IP或CS和IP壓入棧中,轉移
call 標號
(1) (sp)=(sp)-2
((ss)*16+(sp))=(ip)
(2) (ip)=(ip)+16位位移
相當於 push IP
jmp near ptr 標號
call far ptr 標號
(1) (sp)=(sp)-2
((ss)*16+(sp))=(cs)
(sp)=(sp)-2
((ss)*16+(sp))=(ip)
(2) (cs)=標號所在段的段地址
(ip)=標號所在段的偏移地址
相當於 push CS
push IP
jmp far ptr 標號
call 16位reg
(sp)=(sp)-2
((ss)*16+(sp))=(IP)
(IP)=(16位reg)
相當於 push IP
jmp 16位reg
call word ptr 內存單元地址
(sp)=(sp)-2
((ss)*16+(sp))=(IP)
(ip)=(內存單元地址)
相當於 push IP
jmp word ptr 內存單元地址
call dword ptr 內存單元地址
相當於 push CS
push IP
jmp dword ptr 內存單元地址


42、在Debug中單步跟蹤的結果,不能代表CPU的實際執行結果。

 

43、mul乘法指令
(1)兩個相乘的數,要么都是8位,要么都是16位。如果是8位,一個默認放在AL中,另一個放在8位reg或內存字節單元中;如果是16位,一個默認在AX中,另一個放在16位reg或內存字單元中。
(2)結果:如果是8位乘法,結果默認放在AX中;如果是16位乘法,結果高位默認在DX中存放,低位在AX中放。

 

44、
assume ds:data,cs:code ;實現求立方運算


data segment
dw 1,2,3,4,5,6,7,8
dd 0,0,0,0,0,0,0,0
data ends


code segment
start:   mov ax,data
    mov ds,ax
    mov si,0
    mov di,16
    mov cx,8

s:     mov bx,[si]
    call cube ;調用帶一個參數的函數cube
    mov [di],ax
    mov [di+2],dx
    add si,2
    add di,4

    loop s
    mov ax,4c00h
    int 21h

cube:  mov ax,bx
    mov bx
    mov bx
    ret
code ends


end start


45、寄存器沖突問題
子程序的標准框架如下:
子程序開始: 子程序中使用的寄存器入棧
子程序內容
子程序中使用的寄存器出棧
返回(ret、retf)

46、子程序的內部處理和顯存的結構密切相關,但是向外提供了與顯存結構無關的接口。通過調用這個子程序,進行字符串的顯示時可以不必了解顯存的機構,為編程提供了方便。注意體會這種設計思想。

 

47、8086CPU的標志寄存器有16位,其中存儲的信息通常被稱為程序狀態字,PSW。

 

48、flag的第6位是ZF,零標志位。它記錄相關指令執行后,其結果是否為0。
flag的第2位是pf,奇偶標志位。它記錄相關指令執行后,其結果的所有bit位中1的個數是否為偶數。
flag的第7位是sf,符號標志位。它記錄相關指令執行后,其結果是否為負。
flag的第0位是cf,進位標志位。一般情況下,在進行無符號數運算的時候,它記錄了運算結果的最高有效位向更高位的進位值,或從更高位的借位值。
flag的第11位是of,溢出標志位。一般情況下,of記錄了有符號數運算的結果是否產生溢出進行記錄。

49、adc是帶進位加法指令,它利用了cf位上記錄的進位值。
指令格式:adc 操作對象1,操作對象2
功能:操作對象1 =操作對象1+操作對象2+cf

50、sbb是帶借位減法指令,它利用了cf位上記錄的借位值。
指令格式:sbb 操作對象1,操作對象2
功能:操作對象1 =操作對象1-操作對象2-cf

51、cmp是比較指令,cmp的功能相當於減法指令,只是不保存結果。cmp指令執行后,將對標志寄存器產生影響。

 

52、flag的第10位是df,方向標志位。在串處理指令中,控制每次操作后,si、di的增減。df=0,每次操作后si、di遞增;df=1,每次操作后si、di遞減。

 

53、串傳送指令
格式:movsb
功能:

(1)、((es)*16+(di))=((ds)*16+(si))
(2)、如果df=0,則:(si)=(si)+1
   (di)=(di)+1
     如果df=1,則;(si)=(si)-1
   (di)=(di)-1
當然也可以傳送一個字,movsw,增量為2
一般來說,movsb,movsw都和rep配合使用,用匯編語法來描述rep movsb的功能就是:
s:movsb
   loop s
可見,rep的作用是根據cx的值,重復執行后面的串傳送指令。

8086CPU提供下面兩條指令對df位進行設置。
cld指令:將標志寄存器的df位置0
std指令:將標志寄存器的df位置1

 

54、pushf的功能是將標志寄存器的值壓棧,popf是從棧中彈出數據,送入標志寄存器中。

55、用中斷類型碼,在中斷向量表中找到中斷處理程序的入口。找到這個入口地址的最終目的是用它設置CS和IP,使CPU執行中斷處理程序。用中斷類型碼找到中斷向量,並用它設置CS和IP,這個工作使用CPU的硬件自動完成的。CPU硬件完成這個工作的過程被稱為中斷過程。

 

56、中斷處理程序iret指令
pop IP
pop CS
popf
可以看到,在中斷過程中,寄存器入棧的順序是標志寄存器、CS、IP,而iret的出棧數序是IP、CS、標志寄存器。

57、當TF=1時,CPU在執行完一條指令后將引發單步中斷,轉去執行中斷處理程序。注意,中斷處理程序也是由一條條指令組成的,如果在執行中斷處理程序之前,TF=1,則CPU在執行完中斷處理程序的第一條指令后,又要產生單步中斷,則又要轉去執行單步中斷的中斷處理程序,在執行完中斷處理程序的第一條指令后,又要產生單步中斷,則又要轉去執行單步中斷的中斷處理程序。。。CPU當然不能讓這種情況發生,解決的方法就是,在進入中斷處理程序之前,設置TF=0。

 

58、
中斷程序的安裝
assume cs:code


code segment
start: 設置es:di指向目的地址
    設置ds:si指向源地址
    設置cx為傳輸長度
    rep movsb

   設置中斷向量表

   mov ax,4c00h
   int 21h

   中斷處理程序
code ends


end start

編寫、安裝中斷7ch的中斷例程
功能:將一個全是字母,以0結尾的字符串,轉換為大寫
參數:ds:si指向字符串的首地址

主程序:
assume cs:code,ds:data


data segment
db 'conversation',0
data ends


code segment
start: mov ax,data
    mov ds,ax
    mov si,0
    int 7ch

    mov ax,4c00h
    int 21h
code ends
end start

 

安裝程序:
assume cs:code


code segment
start:     mov ax,cs
        mov ds,ax
          mov si,offset capital
          mov ax,0
        mov es,ax
          mov di,200h
          mov cx,offset capitalend-offset capital
        cld
        rep movsb

      mov ax,0
      mov es,ax
      mov word ptr es:[7ch*4],200h
      mov word ptr es:[7ch*4+2],0
      mov ax,4c00h
      int 21h

capital:   push cx
      push si
change:    mov cl,[si]
      mov ch,0
      jcxz ok
      and byte ptr [si],11011111b
      inc si
      jmp short change
ok:     pop si
      pop cx
      iret
capitalend: nop

code ends


end start

 

59、
db "hello",'X',86
分別定義了字符串,字符和數字

 

60、CPU可以直接讀寫以下3個地方的數據
(1)CPU內部的寄存器
(2)內存單元
(3)端口

 

61、對端口的讀寫只有兩個指令in、out
注意,在in和out指令中,只能使用ax或al來存放從端口中讀入的數據或要發送到端口中的數據。訪問8位端口時用al,訪問16位端口時用ax。

 

62、shl和shr是邏輯移位指令
shl是邏輯左移指令,它的功能為:
(1)將一個寄存器或內存單元中的數據向左移位
(2)將最后移出的一位寫入CF中
(3)最低位用0補充
移動1位
shl al,1
移動位數大於1
mov cl,3
shl al,cl

shr是邏輯右移指令,它和shl所進行的操作剛好相反

 

63、在PC系統中,外中斷源一共有以下兩類
1、可屏蔽中斷
CPU是否響應可屏蔽中斷,要看標志寄存器的IF位的位置。IF=1,響應中斷,IF=0,不響應可屏蔽中斷

(1)取中斷類型碼n
(2)標志寄存器入棧,IF=0,TF=0
(3)CS、IP入棧
(4)(IP)=(N*4),(CS)=(N*4+2)

8086CPU提供的設置IF的指令如下:
sti,設置IF=1
cli,設置IF=0
2、不可屏蔽中斷
不可屏蔽中斷是CPU必須響應的外中斷。
對於8086CPU,不可屏蔽中斷的中斷類型碼固定為2,所以中斷過程中,不需要取中斷類型碼。

(1)標志寄存器入棧,IF=0,TF=0
(2)CS、IP入棧
(3)(IP)=(8),CS=(0AH)

64、前面的課程中,我們一直使用標號來標記指令、數據、段的起始地址。比如:
a: db 1,2,3,4,5,6,7,8
b: dw 0
但是,我們還可以使用一種標號,這種標號不但表示內存單元的地址,還表示了內存單元的長度,即表示在此標號處的單元,是一個字節單元,還是字單元,還是雙字單元。
a db 1,2,3,4,5,6,7,8
b dw 0
注意,標號a、b后面沒有“:”,它們是同時描述內存地址和單元長度的標號。標號a,描述了地址code:0,和從這個地址開始,以后的內存單元都是字節單元;而標號b描述了地址code:8,和從這個地址開始,以后的內存單元都是字單元。
因為這種標號包含了對單元長度的描述,所以,在指令中,它可以代表一個段中的內存單元。比如:

指令:mov ax,b
相當於:mov ax,cs:[8]

指令:mov b,2
相當於:mov word ptr cs:[8],2

指令:inc b
相當於:inc word ptr cs:[8]

在這些指令中,標號b代表了一個內存單元,地址為code:8,長度為兩個字節。

一般來說,我們不在代碼段中定義數據,而是將數據定義到其他段中。在其他段中,我們也可以使用數據標號來描述存儲數據的單元的地址和長度。注意,在后面加有“:”的地址標號,只能在代碼段中使用,不能在其他段中使用。

下面的程序將data段中a標號處的8個數據累加,結果存儲到b標號處的字中。
assume cs:code,ds:data
data segment
a db 1,2,3,4,5,6,7,8
b dw 0
data ends
code segment

add b,ax

code ends
end
注意,如果想在代碼段中直接用數據標號訪問數據,則需要用偽指令assume將標號所在的段和一個段寄存器聯系起來。否則編譯器在編譯的時候,無法確定標號的段地址在哪一個寄存器中。當然,這種聯系是編譯器需要的,但絕對不是說,我們因為編譯器的工作需要,用assume指令將段寄存器和某個段相聯系,段寄存器中就會真的存放該段的地址。我們在程序中還要使用指令對段寄存器進行設置。

指令:add b,ax
編譯為:add [8],ax

65、直接定址表
showsin: jmp short show
     table dw ag0,ag30,ag60,ag90,ag120,ag150,ag180
     ag0 '0',0
     ag30 '0.5',0
     ag60 '0.866',0
     ag90 '1',0
     ag120 '0.866',0
     ag150 '0.5',0
     ag180 '0',0
show:  push bx
       push es
     push si
     mov bx,0b800h
     mov es,bx

     mov ah,0
     mov bl,30
     div bl
     mov bl,al
     mov bh,0
     add bx,bx
     mov table[bx]

     mov si,160*12+40*2
shows:  mov ah,cs:[bx]
     cmp ah,0
     je showret
     mov es:[si],ah
     inc bx
     add si,2
     jmp short shows
showret:  pop si
     pop es
     pop bx
     ret

本程序使用了兩次直接定址表

66、int9中斷例程對鍵盤輸入的處理
按下a鍵,引發鍵盤中斷;CPU執行int 9中斷例程,從60h端口讀出A鍵的通碼,然后檢測狀態字節,看看是否有shift、ctrl等切換鍵按下;發現沒有切換鍵按下,則將A鍵的掃描碼1eh和對應的ascii碼,即字幕‘a’的ascii碼61h,寫入鍵盤緩沖區。緩沖區的字節單元中,高位字節存儲掃描碼,低位字節存儲ascii碼。此時緩沖區的內容如下1E61

按下左shift鍵,引發鍵盤中斷,int 9中斷例程接受左shift鍵的通碼,設置0040:17處的狀態字的第1位為1,表示左shift鍵按下。

按下a鍵,引發鍵盤中斷;CPU執行int 9中斷例程,從60h端口讀出a鍵的通碼;檢測狀態字節,看看是否有切換鍵按下,發現左shift鍵被按下,則將a鍵的掃描碼1EH和shiift_a對應的ascii碼,即字母‘A’的ascii碼41h,寫入鍵盤緩沖區,此時緩沖區中的內容如下:
1E61 1E41

松開左shift鍵,引發鍵盤中斷,int 9中斷例程接受左shift鍵的斷碼,設置0040:17處的狀態字節的第1位為0,表示左shift鍵松開。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM