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

一文秒懂匯編中的循環(huán)問題

 更新時間:2023年08月02日 08:57:27   作者:cxuan  
這篇文章主要介紹了一文秒懂匯編中的循環(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

匯編更新了幾篇文章了。

匯編語言學習手把手的Debug教程

8086匯編開發(fā)環(huán)境搭建和Debug模式介紹(圖文詳解)

匯編語言Debug命令詳解教程

到此這篇關(guān)于一文秒懂匯編中的循環(huán)問題的文章就介紹到這了,更多相關(guān)匯編循環(huán)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 圖文詳解通俗易懂的匯編語言寄存器

    圖文詳解通俗易懂的匯編語言寄存器

    這篇文章主要為大家介紹了寄存器的內(nèi)容詳解,文中通過精美清晰的圖文方式讓你一看就通俗易懂,有需要的朋友可以借鑒參考學習下,希望能夠有所幫助
    2021-11-11
  • 使用匯編語言實現(xiàn)if else 循環(huán)函數(shù)調(diào)用的具體方法

    使用匯編語言實現(xiàn)if else 循環(huán)函數(shù)調(diào)用的具體方法

    這篇文章主要介紹了使用匯編語言實現(xiàn)if else 循環(huán)函數(shù)調(diào)用的具體方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-01-01
  • 匯編語言基礎(chǔ)理解計算機底層技術(shù)原理

    匯編語言基礎(chǔ)理解計算機底層技術(shù)原理

    這篇文章主要為大家介紹了匯編語言基礎(chǔ),理解計算機底層原理,想要成為高級程序員,我們必須要學會匯編語言,匯編語言是非常重要的計算機底層技術(shù),一般用于底層的編寫
    2021-11-11
  • 匯編語言入門教程(這一篇足矣)

    匯編語言入門教程(這一篇足矣)

    匯編語言是一種最低級、最古老、不具有移植性的編程語言,它能夠直接訪問計算機硬件,所以執(zhí)行效率極高,占用資源極少,想學習匯編語言的朋友不妨閱讀下本教程
    2020-01-01
  • 匯編語言學習assume的作用詳解

    匯編語言學習assume的作用詳解

    這篇文章主要為大家介紹了匯編語言學習assume的作用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2021-11-11
  • 匯編語言教程文件后綴大小寫S區(qū)別分析詳解

    匯編語言教程文件后綴大小寫S區(qū)別分析詳解

    這篇文章主要為大家介紹了匯編文件后綴.s與.S區(qū)別分析詳解,文中詳細的講解了大寫的S與小寫的s后綴在匯編語言中的作用區(qū)別,有需要的朋友可以借鑒參考下
    2021-11-11
  • ARM體系下的GCC內(nèi)聯(lián)匯編教程詳解

    ARM體系下的GCC內(nèi)聯(lián)匯編教程詳解

    在操作系統(tǒng)級的編程中,有時候,C語言并不能完全的使用硬件的功能,這時候就需要嵌入一些匯編代碼來實現(xiàn)功能。這篇文章主要介紹了ARM體系下的GCC內(nèi)聯(lián)匯編,需要的朋友可以參考下
    2020-02-02
  • Debug的基本使用()

    Debug的基本使用()

    Debug是一個通過操作系統(tǒng)(os)對cpu寄存器進行訪問用于學習匯編的程序,但是如今的win10(64位)已經(jīng)不支持cmd打開debug,但是我們可以通過DOSBOX模擬器對其進行訪問
    2023-08-08
  • 匯編語言系列之匯編實現(xiàn)各種碼制的轉(zhuǎn)換(思路詳解)

    匯編語言系列之匯編實現(xiàn)各種碼制的轉(zhuǎn)換(思路詳解)

    本文列出了十六進制轉(zhuǎn)二進制、十進制、ASCII碼及大小寫字母轉(zhuǎn)換的代碼,對匯編語言系列之實現(xiàn)各種碼制的轉(zhuǎn)換問題感興趣的朋友跟隨小編一起看看吧
    2021-11-11
  • 匯編用串檢測scasb尋找數(shù)的位置實現(xiàn)

    匯編用串檢測scasb尋找數(shù)的位置實現(xiàn)

    這篇文章主要介紹了匯編用串檢測scasb尋找數(shù)的位置實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-02-02

最新評論