一文秒懂匯編中的循環(huán)問題
匯編系列其實也在一直更新,只不過更新的頻率會挺慢的。。。由于白天一直忙于工作,空閑時間還要看書、學習各種技術(shù)棧,早上也要抽時間早期健身,晚上回家還要陪家人 + 學習,時間安排的滿滿當當,所以我就慢慢寫,各位讀者也別太著急,我其實真想再分一個自己出來。
之前的文章中介紹過 [0] 表示的是內(nèi)存單元,它一般存儲在 ds 寄存器中,偏移地址為 0 。比如下面的指令
mov ax,[0]
就是將一個內(nèi)存單元的內(nèi)容送入 ax,這個內(nèi)存單元的長度為 2 個字節(jié),正好存放一個字型數(shù)據(jù),偏移地址為 0 ,段地址在 ds 中。這種尋址方式相當于是直接尋址。
比如下面代碼
mov al,[0]
就是將一個內(nèi)存單元的地址送入 al 中,這個內(nèi)存單元的長度是 1 字節(jié),存放字節(jié)型數(shù)據(jù),偏移地址位 0 ,段地址在 ds 中。
所以要描述一個完整的一個內(nèi)存單元,應該需要兩種信息:即內(nèi)存單元的地址和內(nèi)存單元的長度。
比如我們要讀取一個 10000H 的數(shù)據(jù),你可能會需要下面這段代碼。
mov bx,10000H mov ds,bx mov al,[0]
上面這三條指令就把 10000H 讀取到了 al 中。
但是表示內(nèi)存地址的方式不只有直接指定其內(nèi)存地址,還可以用一種間接尋址的方式,比如 [bx],它表示的是一種寄存器間接尋址,也是一種偏移地址,同樣的,比如我們要讀取一個 10000H 的數(shù)據(jù),使用 [bx] 這種方式的代碼如下(假設(shè) ds = 1000H)
mov bx,1 mov ax,[bx]
這樣計算機就會尋找段地址為 1000H,偏移地址為 0001H 的數(shù)據(jù)放入到 ax 中。
它的中文解釋就是 把 [bx] 指向的地址中的內(nèi)容,送入 ax 寄存器中。
比如下面這段代碼
mov ax,[bx]
它表示的就是將偏移地址為 bx 的數(shù)據(jù),送入到 ax 中,送入的內(nèi)存單元地址是 2 個字節(jié),存放字型數(shù)據(jù)。
又比如下面這段代碼
mov al,[bx]
它表示的就是將偏移地址為 bx 的數(shù)據(jù),送入到 al 中,送入的內(nèi)存單元地址是 1 個字節(jié),存放字節(jié)型數(shù)據(jù)。
[bx] 這種間接尋址的好處就是每次偏移地址不是固定的,這為我們接下來的循環(huán)指令奠定了基礎(chǔ)。
為了更方便的描述后面,我們后面使用 ()
來表示一個寄存器或者內(nèi)存單元中的內(nèi)容。
這里需要注意一下,() 內(nèi)的表示的元素一般有三種類型:
寄存器名,比如 (ax) 就表示 ax 中的內(nèi)容,(al) 就表示 al 中的內(nèi)容。
段寄存器名,比如 (ds) 就表示段寄存器 ds 中的內(nèi)容。
內(nèi)存單元的物理地址,比如 ((ds) * 16 + (bx)),一個 20 位的數(shù)據(jù)。
我們知道,寄存器存儲的數(shù)據(jù)類型有兩種,字型和字節(jié)型,字型數(shù)據(jù)一般用 ax 這類寄存器來存儲,字節(jié)型數(shù)據(jù)一般用 ah 、al 這種寄存器來存儲。
同樣的,() 內(nèi)的數(shù)據(jù)類型也有兩種,字型和字節(jié)型。比如 (al)、(bl)、(cl) 這種表示的數(shù)據(jù)就是字節(jié)型,而 (ax)、(bx)、(cx) 表示的數(shù)據(jù)就是字型。
在了解完上述的這些知識點后,我們就可以來正式看一下 [bx] 了。
[BX]
再來啰嗦一下 [bx] 的尋址方式,比如下面代碼
mov ax,[bx]
bx 中存放的數(shù)據(jù)作為一個偏移地址,這里用 EA 表示(沒有其他意思,只是單純地表示偏移地址),段地址在 ds 中,用 SA 表示(同 EA 的解釋),將 SA:EA 處的數(shù)據(jù)送入 ax 中,即 (ax) = ((ds) * 16 + (bx))。
可以將內(nèi)存單元送入寄存器中,也可以將寄存器的數(shù)據(jù)送入到內(nèi)存單元中,如下代碼所示
mov [bx],ax
就是將 ax 中的數(shù)據(jù)送入到 SA:EA 處,即 ((ds) * 16 + (bx)) = (ax)。
為了讓大家加深對 [bx] 的認識,我們通過一些匯編指令來認識一下程序的執(zhí)行過程,代碼如下
mov ax,2000H mov ds,ax mov bx,1000H mov ax,[bx] inc bx inc bx mov [bx],ax inc bx inc bx mov [bx],ax inc bx mov [bx],al inc bx mov [bx],al
下面我們就按照每一行指令來分析一下
首先,mov ax,2000H 就是將 2000 送入 ax 中,mov ds,ax 就是將設(shè)置段地址為 2000 H,mov bx,1000H 就是將 1000 送入 bx 中,mov ax,[bx] 就是將 2000:1000 處的地址送入到 ax 中(因為段基址為 2000,偏移地址 dx 為 1000),2000H:1000H 處的指令是 00be,所以 ax = 00BEH ,存儲字型數(shù)據(jù),示意圖如下
inc bx 就是將寄存器 bx 的值加 1,此處有兩條 inc 指令,所以執(zhí)行完成后 bx = 1002H,此處段基址:偏移地址為 2000H:1002H。
然后下面 (第七行指令)mov [bx],ax 就是將 ax 中的數(shù)據(jù)送入到 [bx] 中,也就是 1002H 處,指令執(zhí)行后,2000:1002 單元的內(nèi)容為 BE,2000:1003 單元的內(nèi)容為 00,存放字型數(shù)據(jù),執(zhí)行完成后的示意圖如下
繼續(xù)執(zhí)行第 8、9 行的指令,inc bx ,執(zhí)行完成后 bx = 1004H,然后執(zhí)行第 10 行指令 mov [bx],ax ,指令執(zhí)行前: ds = 2000H,bx = 1004H,mov [bx],ax 相當于是把 ax 中的數(shù)據(jù)送到 2000:1004 處,指令執(zhí)行完成后,2000:1004 的單元內(nèi)容為 BE,2000:1005 的單元內(nèi)容為 00 ,如下示意圖所示
接下來執(zhí)行第 11 行指令,inc bx,執(zhí)行完成后 bx = 1005H,mov [bx],al 是把 al 中的數(shù)據(jù)送入內(nèi)存 2000:1005 處,指令執(zhí)行完成后,2000:1005 處的單元內(nèi)容為 BE,如下示意圖所示
繼續(xù)執(zhí)行指令,第13、14 行指令和 11 、12 行指令一樣,它的意思就是將 bx 的值加一之后,將 al 的值送入到指定地址處,執(zhí)行完成后的 ds = 2000H,bx = 1006H,所以 2000:1006 處的內(nèi)容是 BE(al 存儲的數(shù)據(jù)),示意圖如下
想必大家跟完上面的流程后,應該對 [bx] 這個間接尋址方式有了比較深刻的認識。
下面想個問題,使用匯編編程計算 2 * 2 ,并將結(jié)果存儲在 ax 寄存器中。
這個思路還是比較簡單的,直接將 2 放在 ax 寄存器中,然后執(zhí)行 ax 的 add 操作就可以了,下面是匯編代碼
assume cs:codesg codesg segment mov ax,2 add ax,ax mov ax,4c00h int 21h codesg ends end
上面這段代碼中的計算量還比較低,但是如果要讓你計算 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 呢,你難道要寫 n 個 add ax,ax 嗎?
assume cs:codesg codesg segment mov ax,2 add ax,ax add ax,ax add ax,ax add ax,ax 。。。 mov ax,4c00h int 21h codesg ends end
這就很繁瑣啊,所以不能這么玩,那該怎么搞呢?這里就需要一種能夠循環(huán)之星 add ax,ax 的指令了,這個指令就是 Loop
。
Loop 指令
Loop 指令能夠循環(huán)判斷是否執(zhí)行指定的指令,它的執(zhí)行流程就相當于我們 Java 中的 for 循環(huán)。
我們先來使用 Loop 改寫一下上面 n 個 2 相乘的代碼,然后再講解一下 Loop 的使用。
assume cs:codesg codesg segment mov ax,2 mov cx,8 s: add ax,ax loop s mov ax,4c00h int 21h codesg ends end
可以看到,我們使用 8 個 2 相乘的代碼被優(yōu)化的這么簡單,這就是 loop 指令的精髓所在。
其實關(guān)鍵代碼就是三條指令,即
- mov cx,8
- s: add ax,ax
- loop s
翻譯過來的意思就是將 8 放在 cx 中,然后給 add ax,ax 處設(shè)置一個標號,然后執(zhí)行 s 循環(huán)。
loop 指令的格式是:loop 標號,CPU 執(zhí)行 loop 指令的時候,要進行兩步操作,第一步:(cx) = (cx) - 1,第二步:判斷 cx 的值,不為 0 則轉(zhuǎn)至標號(上面代碼是 s)處繼續(xù)執(zhí)行指令,如果為 0 則向下執(zhí)行(上面代碼中鄉(xiāng)下繼續(xù)執(zhí)行就是 mov ax,4c00h)。上面代碼中,我們把 8 送入了 cx 中,也就是說,cx 中存儲的就是執(zhí)行次數(shù)。
下面我們詳細介紹一下上面這段程序的執(zhí)行過程,從中體會一下 cx 和 loop s 是如何配合實現(xiàn)循環(huán)的。
(1) 執(zhí)行 cx,8 ,設(shè)置 cx = 8
(2) 執(zhí)行 add ax,ax(第 1 次)
(3) 執(zhí)行 loop s 將 cx 的值 - 1,此時 (cx) = 7,(cx) != 0 ,所以轉(zhuǎn)至 s 處
(4) 執(zhí)行 add ax,ax(第 2 次)
(5) 執(zhí)行 loop s 將 cx 的值 - 1,此時 (cx) = 6,(cx) != 0 ,所以轉(zhuǎn)至 s 處
(6) 執(zhí)行 add ax,ax(第 3 次)
(7) 執(zhí)行 loop s 將 cx 的值 - 1,此時 (cx) = 5,(cx) != 0 ,所以轉(zhuǎn)至 s 處
(8) 執(zhí)行 add ax,ax(第 4 次)
(9) 執(zhí)行 loop s 將 cx 的值 - 1,此時 (cx) = 4,(cx) != 0 ,所以轉(zhuǎn)至 s 處
(10) 執(zhí)行 add ax,ax(第 5 次)
(11) 執(zhí)行 loop s 將 cx 的值 - 1,此時 (cx) = 3,(cx) != 0 ,所以轉(zhuǎn)至 s 處
(12) 執(zhí)行 add ax,ax(第 6 次)
(13) 執(zhí)行 loop s 將 cx 的值 - 1,此時 (cx) = 2,(cx) != 0 ,所以轉(zhuǎn)至 s 處
(14) 執(zhí)行 add ax,ax(第 7 次)
(15) 執(zhí)行 loop s 將 cx 的值 - 1,此時 (cx) = 1,(cx) != 0 ,所以轉(zhuǎn)至 s 處
(16) 執(zhí)行 add ax,ax(第 8 次)
(15) 執(zhí)行 loop s 將 cx 的值 - 1,此時 (cx) = 0,(cx) == 0 ,所以轉(zhuǎn)至 s 處
(16) 執(zhí)行 mov ax,4c00h(循環(huán)結(jié)束)
從上面這個過程中,我們可以總結(jié)處用 cx 和 loop 指令相配合實現(xiàn)循環(huán)功能的 3 點注意事項:
- 在 cx 中存放循環(huán)次數(shù)。
- loop 指令中的標號所標識的地址要在前面
- 要循環(huán)執(zhí)行的程序段,要寫在標號和 loop 指令的中間。
所以綜上所述,使用 Loop 和 cx 相配合實現(xiàn)的循環(huán)功能的結(jié)構(gòu)如下:
mov cx,循環(huán)次數(shù) s: 循環(huán)執(zhí)行的程序段 loop s
比如我們想用 Loop 循環(huán)計算出 123 * 456 這個值,就可以使用這種方式
assume cs:codesg codesg segment mov ax,0 mov cx,456 s:add ax,123 loop s mov ax,4c00h int 21h codesg ends end
匯編更新了幾篇文章了。
8086匯編開發(fā)環(huán)境搭建和Debug模式介紹(圖文詳解)
到此這篇關(guān)于一文秒懂匯編中的循環(huán)問題的文章就介紹到這了,更多相關(guān)匯編循環(huán)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
使用匯編語言實現(xiàn)if else 循環(huán)函數(shù)調(diào)用的具體方法
這篇文章主要介紹了使用匯編語言實現(xiàn)if else 循環(huán)函數(shù)調(diào)用的具體方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-01-01匯編語言系列之匯編實現(xiàn)各種碼制的轉(zhuǎn)換(思路詳解)
本文列出了十六進制轉(zhuǎn)二進制、十進制、ASCII碼及大小寫字母轉(zhuǎn)換的代碼,對匯編語言系列之實現(xiàn)各種碼制的轉(zhuǎn)換問題感興趣的朋友跟隨小編一起看看吧2021-11-11匯編用串檢測scasb尋找數(shù)的位置實現(xiàn)
這篇文章主要介紹了匯編用串檢測scasb尋找數(shù)的位置實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-02-02