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

匯編基礎(chǔ)程序編寫教程示例

 更新時間:2021年11月04日 17:52:45   作者:LyncDwight  
這篇文章主要為大家介紹了匯編基礎(chǔ),程序編寫教程示例,文中附含詳細的圖文示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助

源程序

1.1 構(gòu)成

寄存器與段的關(guān)聯(lián)假設(shè)

 assume:含義為“假設(shè)”。

它假設(shè)某一段寄存器和程序中的某一個用 segment … ends 定義的段相關(guān)聯(lián)。

通過assume說明這種關(guān)聯(lián),在需要的情況下 ,編譯程序可以將段寄存器和某一個具體的段相聯(lián)系。

標號

一個標號指代了一個地址。

codesg:放在segment的前面,作為一個段的名稱,這個段的名稱最終將被編譯、連接程序處理為一個段的段地址。

定義一個段

segment和ends的功能是定義一個段,segment說明一個段開始,ends 說明一個段結(jié)束。

segment和ends是一對成對使用的偽指令

一個段必須有一個名稱來標識,使用格式為:

段名 segment

段名 ends

一個匯編程序是由多個段組成的,這些段被用來存放代碼、數(shù)據(jù)或當作??臻g來使用。

一個有意義的匯編程序中至少要有一個段,這個段用來存放代碼。

程序結(jié)束標記

End 是一個匯編程序的結(jié)束標記,編譯器在編譯匯編程序的過程中,如果碰到了偽指令 end,就結(jié)束對源程序的編譯。

如果程序?qū)懲炅?,要在結(jié)尾處加上偽指令end 。否則,編譯器在編譯程序時,無法知道程序在何處結(jié)束。

注意:不要搞混了end和ends。

程序返回

一個程序結(jié)束后,將CPU的控制權(quán)交還給使它得以運行的程序,我們稱這個過程為:程序返回。

如何返回

應該在程序的末尾添加返回的程序段。

mov ax,4c00H

int 21H

程序運行

DOS是一個單任務操作系統(tǒng)。

一個程序P2在可執(zhí)行文件中,則必須有一個正在運行的程序P1,將P2從可執(zhí)行文件中加載入內(nèi)存后,將CPU的控制權(quán)交給P2,P2才能得以運行。P2開始運行后,P1暫停運行。

而當P2運行完畢后,應該將CPU的控制權(quán)交還給使它得以運行的程序P1,此后,P1繼續(xù)運行。

1.2 源程序中的“程序”

匯編源程序:

偽指令 (編譯器處理)

匯編指令(編譯為機器碼)

程序:源程序中最終由計算機執(zhí)行、處理的指令或數(shù)據(jù)。

注意

我們可以將源程序文件中的所有內(nèi)容稱為源程序,將源程序中最終由計算機執(zhí)行處理的指令或數(shù)據(jù) ,成為程序。

程序最先以匯編指令的形式存在源程序中,經(jīng)編譯、連接后轉(zhuǎn)變?yōu)闄C器碼,存儲在可執(zhí)行文件中,

 

1.3 段結(jié)束、程序結(jié)束、程序返回

1.4 語法錯誤和邏輯錯誤

語法錯誤

程序在編譯時被編譯器發(fā)現(xiàn)的錯誤

邏輯錯誤

程序在編譯時不能表現(xiàn)出來的、在運行時發(fā)生的錯誤

2 程序執(zhí)行的過程

2.1 一個匯編語言程序從寫出到最終執(zhí)行的簡要過程:

2.2 連接

作用

當源程序很大時,可以將它分為多個源程序文件來編譯,每個源程序編譯成為目標文件后,再用連接程序?qū)⑺鼈冞B接到一起,生成一個可執(zhí)行文件;

程序中調(diào)用了某個庫文件中的子程序,需要將這個庫文件和該程序生成的目標文件連接到一起,生成一個可執(zhí)行文件;

一個源程序編譯后,得到了存有機器碼的目標文件,目標文件中的有些內(nèi)容還不能直接用來生成可執(zhí)行文件,連接程序?qū)⑦@此內(nèi)容處理為最終的可執(zhí)行信息。

所以,在只有一個源程序文件,而又不需要調(diào)用某個庫中的子程序的情況下,也必須用連接程序?qū)δ繕宋募M行處理,生成可執(zhí)行文件。

注意,對于連接的過程,可執(zhí)行文件是我們要得到的最終結(jié)果。

使用匯編語言編譯程序?qū)υ闯绦蛭募械脑闯绦蜻M行編譯,產(chǎn)生目標文件;再用連接程序?qū)δ繕宋募M行連接,生成可在操作系統(tǒng)中直接運行的可執(zhí)行文件。

2.3 可執(zhí)行文件

可執(zhí)行文件中包含兩部分內(nèi)容:

  •  程序(從原程序中的匯編指令翻譯過來的機器碼)和數(shù)據(jù)(源程序中定義的數(shù)據(jù))
  •  相關(guān)的描述信息(比如:程序有多大、要占多少內(nèi)存空間等)

執(zhí)行可執(zhí)行文件中的程序

  • 在操作系統(tǒng)中,執(zhí)行可執(zhí)行文件中的程序。
  • 操作系統(tǒng)依照可執(zhí)行文件中的描述信息,將可執(zhí)行文件中的機器碼和數(shù)據(jù)加載入內(nèi)存,并進行相關(guān)的初始化(比如:設(shè)置CS:IP指向第一條要執(zhí)行的指令),然后由CPU執(zhí)行程序。

 

可執(zhí)行文件中的程序裝入內(nèi)存并運行的原理

  • 在DOS中,可執(zhí)行文件中的程序P1若要運行,必須有一個正在運行的程序P2 ,將 P1 從可執(zhí)行文件中加載入內(nèi)存,將CPU的控制權(quán)交給它,P1才能得以運行;
  • 當P1運行完畢后,應該將CPU的控制權(quán)交還給使它得以運行的程序P2

exe的執(zhí)行過程

實際過程

(1)我們在提示符“C:\masm”后面輸入可執(zhí)行文件的名字“1”,按Enter鍵。

(2)1.exe中的程序運行;

(3)運行結(jié)束,返回,再次顯示提示符“C:\masm”。

操作過程

操作系統(tǒng)是由多個功能模塊組成的龐大 、復雜的軟件系統(tǒng)。任何通用的操作系統(tǒng) ,都要提供一個稱為shell(外殼)的程序 ,用戶(操作人員)使用這個程序來操作計算機系統(tǒng)工作。

DOS中有一個程序command.com ,這個程序在 DOS 中稱為命令解釋器,也就是DOS系統(tǒng)的shell。

(1)我們在DOS中直接執(zhí)行 1.exe 時,是正在運行的command將1.exe中的程序加載入內(nèi)存。

(2)command設(shè)置CPU的CS:IP指向程序的第一條指令(即程序的入口),從而使程序得以運行。

(3)程序運行結(jié)束后,返回到command中,CPU繼續(xù)運行command。

2.4 程序執(zhí)行過程的跟蹤

Debug 可以將程序加載入內(nèi)存,設(shè)置CS:IP指向程序的入口,但Debug并不放棄對CPU 的控制,這樣,我們就可以使用Debug 的相關(guān)命令來單步執(zhí)行程序 ,查看每條指令指令的執(zhí)行結(jié)果。

我們在 DOS中用 “Debug 1.exe” 運行Debug對1.exe進行跟蹤時,程序加載的順序是:command加載Debug,Debug加載1.exe。

返回的順序是:從1.exe中的程序返回到Debug,從Debug返回到command。

EXE文件中的程序的加載過程

 

總結(jié)

程序加載后,ds中存放著程序所在內(nèi)存區(qū)的段地址,這個內(nèi)存區(qū)的偏移地址為 0 ,則程序所在的內(nèi)存區(qū)的地址為:ds:0;

這個內(nèi)存區(qū)的前256 個字節(jié)中存放的是PSP,dos用來和程序進行通信。

從 256字節(jié)處向后的空間存放的是程序。

所以,我們從ds中可以得到PSP的段地址SA,PSP的偏移地址為 0,則物理地址為SA×16+0。

因為PSP占256(100H)字節(jié),所以程序的物理地址是:

SA×16+0+256= SA×16+16×16=(SA+16)×16+0

可用段地址和偏移地址表示為:SA+10:0。

3 程序編寫

3.1 兩個基本的問題

計算機是進行數(shù)據(jù)處理、運算的機器,那么有兩個基本的問題就包含在其中:

(1)處理的數(shù)據(jù)在什么地方?

(2)要處理的數(shù)據(jù)有多長?這兩個問題,在機器指令中必須給以明確或隱含的說明,否則計算機就無法工作。

為了描述上的簡潔,在以后的課程中,我們將使用兩個描述性的符號 reg來表示一個寄存器,用sreg表示一個段寄存器。

reg的集合包括:ax、bx、cx、dx、ah、al、bh、bl、ch、cl、dh、dl、sp、bp、si、di;

sreg的集合包括:ds、ss、cs、es。

3.2 數(shù)據(jù)在哪里

機器指令處理的數(shù)據(jù)所在位置

  • 絕大部分機器指令都是進行數(shù)據(jù)處理的指令,處理大致可分為三類:讀取、寫入、運算
  • 在機器指令這一層來講,并不關(guān)心數(shù)據(jù)的值是多少,而關(guān)心指令執(zhí)行前一刻,它將要處理的數(shù)據(jù)所在的位置。
  • 指令在執(zhí)行前,所要處理的數(shù)據(jù)可以在三個地方:CPU內(nèi)部、內(nèi)存、端口
  • 指令舉例

 

匯編語言中數(shù)據(jù)位置的表達

匯編語言中用三個概念來表達數(shù)據(jù)的位置。

 立即數(shù)(idata)

對于直接包含在機器指令中的數(shù)據(jù)(執(zhí)行前在cpu 的指令緩沖器中),在匯編語言中稱為:立即數(shù)(idata ) ,在匯編指令中直接給出。例如:

mov ax,1

add bx,2000h

or bx,00010000b

mov al,'a'

 

寄存器

指令要處理的數(shù)據(jù)在寄存器中,在匯編指令中給出相應的寄存器名。例如:

mov ax,bx

mov ds,ax

push bx

mov ds:[0],bx

push ds

mov ss,ax

mov sp,ax

mov ax,bx

對應機器碼:89D8

執(zhí)行結(jié)果:(ax) = (bx)

段地址(SA)和偏移地址(EA)

指令要處理的數(shù)據(jù)在內(nèi)存中,在匯編指令中可用[X]的格式給出EA,SA在某個段寄存器中。

存放段地址的寄存器可以是默認的。

mov ax,[0]

mov ax,[bx]

mov ax,[bx+8]

mov ax,[bx+si]

mov ax,[bx+si+8]

段地址默認在ds中

存放段地址的寄存器也可以顯性的給出。

mov ax,[bp]

mov ax,[bp+8]

mov ax,[bp+si]

mov ax,[bp+si+8]

段地址默認在ss中

顯性的給出存放段地址的寄存器

尋址方式

當數(shù)據(jù)存放在內(nèi)存中的時候,我們可以用多種方式來給定這個內(nèi)存單元的偏移地址,這種定位內(nèi)存單元的方法一般被稱為尋址方式。

3.3 指令處理的數(shù)據(jù)有多長

8086CPU的指令,可以處理兩種尺寸的數(shù)據(jù),byte和word。所以在機器指令中要指明,指令進行的是字操作還是字節(jié)操作

對于這個問題,匯編語言中用以下方法處理。

(1)通過寄存器名指明要處理的數(shù)據(jù)的尺寸。

(2)在沒有寄存器名存在的情況下,用操作符X ptr指明內(nèi)存單元的長度,X在匯編指令中可以為word或byte。

(3)其他方法

下面的指令中,寄存器指明了指令進行的是字節(jié)操作:

 mov al,1

mov al,bl

mov al,ds:[0]

mov ds:[0],al

inc al

add al,100

下面的指令中,寄存器指明了指令進行的是字操作:

mov ax,1

mov bx,ds:[0]

mov ds,ax

mov ds:[0],ax

inc ax add ax,1000

在沒有寄存器參與的內(nèi)存單元訪問指令中,用word ptr或byte ptr顯性地指明所要訪問的內(nèi)存單元的長度是很必要的。

否則,CPU無法得知所要訪問的單元是字單元,還是字節(jié)單元

下面的指令中,用word ptr指明了指令訪問的內(nèi)存單元是一個字單元:

mov word ptr ds:[0],1

inc word ptr [bx]

inc word ptr ds:[0]

add word ptr [bx],2

下面的指令中,用byte ptr指明了指令訪問的內(nèi)存單元是一個字節(jié)單元:

mov byte ptr ds:[0],1

inc byte ptr [bx]

inc byte ptr ds:[0]

add byte ptr [bx],2

有些指令默認了訪問的是字單元還是字節(jié)單元,

比如:push [1000H]就不用指明訪問的是字單元還是字節(jié)單元

因為push指令只進行字操作

3.4 數(shù)據(jù)處理

在代碼段中使用數(shù)據(jù)

考慮這樣一個問題,編程計算以下8個數(shù)據(jù)的和,結(jié)果存在ax 寄存器中:

0123H,0456H,0789H,0abcH,0defH,0fedH,0cbaH,0987H。

在前面的課程中,我們都是累加某些內(nèi)存單元中的數(shù)據(jù),并不關(guān)心數(shù)據(jù)本身。

可現(xiàn)在我們要累加的就是已經(jīng)給定了數(shù)值的數(shù)據(jù)。

 

程序第一行中的 “dw”的含義是定義字型數(shù)據(jù)。dw即define word。

在這里,我們使用dw定義了8個字型數(shù)據(jù)(數(shù)據(jù)之間以逗號分隔),它們所占的內(nèi)存空間的大小為16個字節(jié)。

程序中的指令就要對這8個數(shù)據(jù)進行累加,可這8個數(shù)據(jù)在哪里呢?

由于它們在代碼段中,程序在運行的時候CS中存放代碼段的段地址,所以我們可以從CS中得到它們的段地址

這8個數(shù)據(jù)的偏移地址是多少呢?

  • 因為用dw定義的數(shù)據(jù)處于代碼段的最開始,所以偏移地址為0,這8 個數(shù)據(jù)就在代碼段的偏移0、2、4、6、8、A、C、E處。
  • 程序運行時,它們的地址就是CS:0、CS:2、CS:4、CS:6、CS:8、CS:A、CS:C、CS:E。

程序中,我們用bx存放加2遞增的偏移地址,用循環(huán)來進行累加。

在循環(huán)開始前,設(shè)置(bx)=0,cs:bx指向第一個數(shù)據(jù)所在的字單元。

每次循環(huán)中(bx)=(bx)+2,cs:bx指向下一個數(shù)據(jù)所在的字單元。

如何讓這個程序在編譯后可以存系統(tǒng)中直接運行呢?我們可以在源程序中指明界序的入口所在

探討end的作用:

end 除了通知編譯器程序結(jié)束外,還可以通知編譯器程序的入口在什么地方。

有了這種方法,我們就可以這樣來安排程序的框架:

在代碼段中使用棧

完成下面的程序,利用棧,將程序中定義的數(shù)據(jù)逆序存放

 assume cs:codesg

codesgsegment

dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h

?

code ends end

程序的思路大致如下:

程序運行時,定義的數(shù)據(jù)存放在cs:0~cs:15單元中,共8個字單元。依次將這8個字單元中的數(shù)據(jù)入棧,然后再依次出棧到這 8 個字單元中,從而實現(xiàn)數(shù)據(jù)的逆序存放。

問題是,我們首先要有一段可當作棧的內(nèi)存空間。如前所述,這段空間應該由系統(tǒng)來分配。我們可以在程序中通過定義數(shù)據(jù)來取得一段空間,然后將這段空間當作??臻g來用

mov ax,cs

mov ss,ax

mov sp,32

我們要講 cs:16 ~ cs:31 的內(nèi)存空間當作棧來用,初始狀態(tài)下棧為空,所以 ss:sp要指向棧底,則設(shè)置ss:sp指向cs:32。

比如對于:

dw 0123H,0456H,0789H,0abcH,0defH,0fedH,0cbaH,0987H

我們可以說,定義了8個字型數(shù)據(jù),也可以說,開辟了8個字的內(nèi)存空間,這段空間中每個字單元中的數(shù)據(jù)依次是:

0123H,0456H,0789H,0abcH,0defH,0fedH,0cbaH,0987H。

因為它們最終的效果是一樣的

將數(shù)據(jù)、代碼、棧放入不同的段

在前面的內(nèi)容中,我們在程序中用到了數(shù)據(jù)和棧,我們將數(shù)據(jù)、棧和代碼都放到了一個段里面。我們在編程的時候要注意何處是數(shù)據(jù),何處是棧,何處是代碼。這樣做顯然有兩個問題:

(1)把它們放到一個段中使程序顯得混亂;

(2)前面程序中處理的數(shù)據(jù)很少,用到的??臻g也小,加上沒有多長的代碼,放到一個段里面沒有問題。

但如果數(shù)據(jù)、棧和代碼需要的空間超過64KB,就不能放在一個段中(一個段的容量不能大于64 KB,是我們在學習中所用的8086模式的限制,并不是所有的處理器都這樣)。

所以,我們應該考慮用多個段來存放數(shù)據(jù)、代碼和棧。

我們用和定義代碼段一樣的方法來定義多個段,然后在這些段里面定義需要的數(shù)據(jù),或通過定義數(shù)據(jù)來取得??臻g。

程序中“data”段中的數(shù)據(jù)“0abch”的地址就是:data:6。

我們要將它送入bx中,就要用如下的代碼:

 mov ax,data

mov ds,ax

mov bx,ds:[6]

我們不能用下面的指令:

mov ds,data

mov ax,ds:[6]

其中指令“mov ds,data” 是錯誤的,因為8086CPU不允許將一個數(shù)值直接送入段寄存器中。

程序中對段名的引用,如指令“mov ds,data”中的“data”,將被編譯器處理為一個表示段地址的數(shù)值。

“代碼段”、“數(shù)據(jù)段”、“棧段”完全是我們的安排

我們在源程序中用偽指令

“assume cs:code,ds:data,ss:stack”將cs、ds和ss分別和code、data、stack段相連。

這樣做了之后,CPU是否就會將 cs指向 code,ds 指向 data,ss 指向stack,從而按照我們的意圖來處理這些段呢?

當然也不是,要知道 assume 是偽指令,是由編譯器執(zhí)行的,也是僅在源程序中存在的信息,CPU并不知道它們。

若要CPU按照我們的安排行事,就要用機器指令控制它,源程序中的匯編指令是CPU要執(zhí)行的內(nèi)容

CPU如何知道去執(zhí)行它們?

我們在源程序的最后用“end start”說明了程序的入口,這個入口將被寫入可執(zhí)行文件的描述信息,可執(zhí)行文件中的程序被加載入內(nèi)存后,CPU的CS:IP被設(shè)置指向這個入口,從而開始執(zhí)行程序中的第一條指令。

標號“start”在“code”段中,這樣CPU就將code段中的內(nèi)容當作指令來執(zhí)行了。

我們在code段中,使用指令:

mov ax,stack

mov ss,ax

mov sp,16 設(shè)置ss指向stack,設(shè)置ss:sp指向stack:16, CPU 執(zhí)行這些指令后,將把stack段當做??臻g來用。 CPU若要訪問data段中的數(shù)據(jù),則可用 ds 指向 data 段,用其他的寄存器(如:bx)來存放 data段中數(shù)據(jù)的偏移地址

總之,CPU到底如何處理我們定義的段中的內(nèi)容,是當作指令執(zhí)行,當作數(shù)據(jù)訪問,還是當作棧空間,完全是靠程序中具體的匯編指令,和匯編指令對CS:IP、SS:SP、DS等寄存器的設(shè)置來決定的。

3.5 模塊化實現(xiàn):call 和 ret 指令

功能:call和ret 指令都是轉(zhuǎn)移指令,它們都修改IP,或同時修改CS和IP。

ret

 ret指令用棧中的數(shù)據(jù),修改IP的內(nèi)容,從而實現(xiàn)近轉(zhuǎn)移;

CPU執(zhí)行ret指令時,進行下面兩步操作:

(1)(IP)=((ss)*16+(sp))

(2)(sp)=(sp)+2

retf

retf指令用棧中的數(shù)據(jù),修改CS和IP的內(nèi)容,從而實現(xiàn)遠轉(zhuǎn)移;

CPU執(zhí)行retf指令時,進行下面兩步操作:

(1)(IP)=((ss)*16+(sp))

(2)(sp)=(sp)+2

(3)(CS)=((ss)*16+(sp))

(4)(sp)=(sp)+2

可以看出,如果我們用匯編語法來解釋ret和retf指令,則:

CPU執(zhí)行ret指令時,相當于進行:

pop IP

CPU執(zhí)行retf指令時,相當于進行:

pop IP

pop CS

示例

ret指令

程序中ret指令執(zhí)行后,(IP)=0,CS:IP指向代碼段的第一條指令。

retf指令

程序中retf指令執(zhí)行后,CS:IP指向代碼段的第一條指令。

call 指令

CPU執(zhí)行call指令,進行兩步操作:

(1)將當前的 IP 或 CS和IP 壓入棧中

(2)轉(zhuǎn)移

主要應用格式

call 指令不能實現(xiàn)短轉(zhuǎn)移,除此之外,call指令實現(xiàn)轉(zhuǎn)移的方法和 jmp 指令的原理相同

依據(jù)位移進行轉(zhuǎn)移的call指令

call 標號(將當前的 IP 壓棧后,轉(zhuǎn)到標號處執(zhí)行指令)

CPU執(zhí)行此種格式的call指令時,進行如下的操作:

(1) (sp) = (sp) – 2 ((ss)*16+(sp)) = (IP)

(2) (IP) = (IP) + 16位位移

call 標號

16位位移=“標號”處的地址-call指令后的第一個字節(jié)的地址;

16位位移的范圍為 -32768~32767,用補碼表示;

16位位移由編譯程序在編譯時算出。

從上面的描述中,可以看出,如果我們用匯編語法來解釋此種格式的 call指令,則: CPU 執(zhí)行指令“call 標號”時,相當于進行: push IP jmp near ptr 標號

轉(zhuǎn)移的目的地址在指令中的call指令

前面講解的call指令,其對應的機器指令中并沒有轉(zhuǎn)移的目的地址 ,而是相對于當前IP的轉(zhuǎn)移位移。

指令“call far ptr 標號”實現(xiàn)的是段間轉(zhuǎn)移。

CPU執(zhí)行“call far ptr 標號”這種格式的call指令時的操作:

(1) (sp) = (sp) – 2 ((ss) ×16+(sp)) = (CS) (sp) = (sp) – 2 ((ss) ×16+(sp)) = (IP)

(2) (CS) = 標號所在的段地址 (IP) = 標號所在的偏移地址

從上面的描述中可以看出,如果我們用匯編語法來解釋此種格式的 call 指令,則: CPU 執(zhí)行指令 “call far ptr 標號” 時,相當于進行: push CS push IP jmp far ptr 標號

轉(zhuǎn)移地址在寄存器中的call指令

指令格式:call 16位寄存器

功能:

(sp) = (sp) – 2

((ss)*16+(sp)) = (IP)

(IP) = (16位寄存器)

匯編語法解釋此種格式的 call 指令,CPU執(zhí)行call 16位reg時,相當于進行: push IP jmp 16位寄存器

轉(zhuǎn)移地址在內(nèi)存中的call指令

轉(zhuǎn)移地址在內(nèi)存中的call指令有兩種格式:

(1) call word ptr 內(nèi)存單元地址

匯編語法解釋: push IP jmp word ptr 內(nèi)存單元地址 比如下面的指令: mov sp,10h mov ax,0123h mov ds:[0],ax call word ptr ds:[0] 執(zhí)行后,(IP)=0123H,(sp)=0EH

(2) call dword ptr 內(nèi)存單元地址

匯編語法解釋: push CS push IP jmp dword ptr 內(nèi)存單元地址 比如,下面的指令: mov sp,10h mov ax,0123h mov ds:[0],ax mov word ptr ds:[2],0 call dword ptr ds:[0] 執(zhí)行后,(CS)=0,(IP)=0123H,(sp)=0CH

call 和 ret 的配合使用

我們看一下程序的主要執(zhí)行過程:

(1)前三條指令執(zhí)行后,棧的情況如下:

(2)call 指令讀入后,(IP) =000EH,CPU指令緩沖器中的代碼為 B8 05 00; CPU執(zhí)行B8 05 00,首先,棧中的情況變?yōu)椋?/p>

 

然后,(IP)=(IP)+0005=0013H。

(3)CPU從cs:0013H處(即標號s處)開始執(zhí)行。

(4)ret指令讀入后:(IP)=0016H,CPU指令緩沖器中的代碼為 C3;CPU執(zhí)行C3,相當于進行pop IP,執(zhí)行后,棧中的情況為:

 

(IP)=000EH;

(5)CPU回到 cs:000EH處(即call指令后面的指令處)繼續(xù)執(zhí)行。

我們發(fā)現(xiàn),可以寫一個具有一定功能的程序段,我們稱其為子程序,在需要的時候,用call指令轉(zhuǎn)去執(zhí)行

 call指令轉(zhuǎn)去執(zhí)行子程序之前,call指令后面的指令的地址將存儲在棧中,所以可以在子程序的后面使用 ret 指令,用棧中的數(shù)據(jù)設(shè)置IP的值,從而轉(zhuǎn)到 call 指令后面的代碼處繼續(xù)執(zhí)行。

這樣,我們可以利用call和ret來實現(xiàn)子程序的機制。

子程序的框架

標號: 指令 ret 具有子程序的源程序的框架:

參數(shù)和結(jié)果傳遞的問題

子程序一般都要根據(jù)提供的參數(shù)處理一定的事務,處理后,將結(jié)果(返回值)提供給調(diào)用者。

其實,我們討論參數(shù)和返回值傳遞的問題,實際上就是在探討,應該如何存儲子程序需要的參數(shù)和產(chǎn)生的返回值。

我們設(shè)計一個子程序,可以根據(jù)提供的N,來計算N的3次方。

這里有兩個問題:

(1)我們將參數(shù)N存儲在什么地方?

(2)計算得到的數(shù)值,我們存儲在什么地方?

很顯然,我們可以用寄存器來存儲,可以將參數(shù)放到 bx 中 ;

因為子程序中要計算 N×N×N ,可以使用多個 mul 指令,為了方便,可將結(jié)果放到 dx 和 ax中。

子程序

說明:計算N的3次方

參數(shù): (bx)=N

結(jié)果: (dx:ax)=N∧3

cube:mov ax,bx

mul bx ;用ax與bx相乘

mul bx

ret

用寄存器來存儲參數(shù)和結(jié)果是最常使用的方法。對于存放參數(shù)的寄存器和存放結(jié)果的寄存器,調(diào)用者和子程序的讀寫操作恰恰相反:

調(diào)用者將參數(shù)送入?yún)?shù)寄存器,從結(jié)果寄存器中取到返回值;

子程序從參數(shù)寄存器中取到參數(shù),將返回值送入結(jié)果寄存器。

以上就是匯編基礎(chǔ)程序編寫教程示例的詳細內(nèi)容,更多關(guān)于匯編語言基礎(chǔ)程序編寫的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 匯編語言入門教程阮一峰版

    匯編語言入門教程阮一峰版

    匯編語言是一種最低級、最古老、不具有移植性的編程語言,它能夠直接訪問計算機硬件,所以執(zhí)行效率極高,占用資源極少,一般用于嵌入式設(shè)備、驅(qū)動程序、實時應用、核心算法等
    2020-01-01
  • 匯編程序輸出“Hello world”的實現(xiàn)

    匯編程序輸出“Hello world”的實現(xiàn)

    這篇文章主要介紹了匯編程序輸出“Hello world”的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-01-01
  • 匯編語言系列之匯編實現(xiàn)字符串操作

    匯編語言系列之匯編實現(xiàn)字符串操作

    本文列出了字符串匹配和字符串輸入顯示的代碼,對匯編語言系列之匯編實現(xiàn)字符串操作相關(guān)知識感興趣的朋友跟隨小編一起看看吧
    2021-11-11
  • 一位數(shù)乘法的匯編語言實現(xiàn)方法

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

    這篇文章主要介紹了一位數(shù)乘法的匯編語言實現(xiàn)方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-02-02
  • 匯編語言軟件延時1s的實現(xiàn)方法

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

    這篇文章主要介紹了匯編語言軟件延時1s的實現(xiàn)方法,本文給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-01-01
  • VScode配置8086匯編環(huán)境的過程解析

    VScode配置8086匯編環(huán)境的過程解析

    這篇文章主要介紹了VScode配置8086匯編環(huán)境的過程解析,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-04-04
  • 匯編語言入門匯編指令及寄存器詳解教程

    匯編語言入門匯編指令及寄存器詳解教程

    這篇文章主要為大家介紹了匯編語言入門匯編指令及寄存器的詳解教程,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步
    2021-11-11
  • 匯編語言環(huán)境搭建軟件與教程

    匯編語言環(huán)境搭建軟件與教程

    這篇文章主要介紹了匯編語言環(huán)境搭建軟件與教程,需要的朋友可以參考下
    2020-01-01
  • 詳解匯編語言MOV指令

    詳解匯編語言MOV指令

    在匯編語言中,MOV指令是數(shù)據(jù)傳送指令,也是最基本的編程指令,這篇文章主要介紹了匯編語言MOV指令,需要的朋友可以參考下
    2020-01-01
  • 匯編語言顯示功能實現(xiàn)教程詳解

    匯編語言顯示功能實現(xiàn)教程詳解

    這篇文章主要為大家介紹了匯編語言顯示功能的實現(xiàn)過程,文中通過問題實例分析來為大家進行詳細的描述講解,有需要的朋友可以借鑒參考下,希望能夠有所幫助
    2021-11-11

最新評論