匯編語言之?dāng)?shù)據(jù)處理的2個(gè)基本問題
1、bx、si、di和bp
Bx、si和di這3個(gè)寄存器我們已經(jīng)學(xué)過了,現(xiàn)在進(jìn)行一下總結(jié),并學(xué)一下bp。
1:在8086CPU中,只有這4個(gè)寄存器可以用在[…]中來進(jìn)行內(nèi)存單元的尋址。比如,下面的指令都是正確
的:
Mov ax, [bx]
Mov ax, [bx+si]
Mov ax, [bx+di]
Mov ax, [bp]
Mov ax, [bp+si]
Mov ax, [bp+di]
而下面的指令是錯(cuò)誤的:
Mov ax, [ax]
Mov ax, [cx]
Mov ax, [dx]
Mov ax, [ds]
2:在[…]中,這4個(gè)寄存器可以單個(gè)出現(xiàn),或只能以4種組合出現(xiàn):bx和si、bx和di、bp和si、bp和di。
比如,下面的指令是正確的:
Mov ax, [bx]
Mov ax, [si]
Mov ax, [di]
Mov ax, [bp]
Mov ax, [bx+si]
Mov ax, [bx+di]
Mov ax, [bp+si]
Mov ax, [bp+di]
Mov ax, [bx+si+idata]
Mov ax, [bx+di+idata]
Mov ax, [bp+si+idata]
Mov ax, [bp+di+idata]
而下面的指令是錯(cuò)誤的:
Mov ax, [bx+bp]
Mov ax, [si+di]
我們可以在訪問內(nèi)存單元的指令中顯式地給出內(nèi)存單元的段地址所在的段寄存器。
比如:mov ax, SS:[bx] ;段地址在SS中。
Mov ax, DS:[bp] ;段地址在DS中。
Mov ax, CS:[bp] ;段地址在CS中。
Mov ax, ES:[bp] ;段地址在ES中。
在上面的指令:mov ax, ES:[bp] 中,我們接觸到了一個(gè)新的段寄存器ES,ES叫附加段寄存器,它的功能與
DS基本相同。
如果在[…]中使用寄存器bp,而指令中沒有顯式地給出段地址,段地址就默認(rèn)在SS中。比如,下面的指令:
Mov ax, [bp+200] 內(nèi)存單元[bp+200]的段地址就在SS中。
BP被稱作基址指針寄存器,它可以作SP使用,除了BP可以作為間接尋址寄存器而SP不能外,其余功能基
本相同。
事實(shí)上,通用寄存器除了ax、bx、cx、dx這4個(gè)外,還包括sp、bp、si、di這4個(gè)16位寄存器,以及ah、
al、bh、bl、ch、cl、dh、dl這8個(gè)8位寄存器,通用寄存器一共有以上這16個(gè)。
2、機(jī)器指令處理的數(shù)據(jù)在什么地方
絕大部分機(jī)器指令都是進(jìn)行數(shù)據(jù)處理的指令,處理大致可分為3類:讀取、寫入、運(yùn)算。在機(jī)器指令這一層來
講,并不關(guān)心數(shù)據(jù)的值是多少,而關(guān)心指令執(zhí)行前一刻,它將要處理的數(shù)據(jù)所在的位置。指令在執(zhí)行前,所要處理
的數(shù)據(jù)可以在3個(gè)地方:CPU內(nèi)部、內(nèi)存、端口,比如下圖所列的指令:
3、匯編語言中的數(shù)據(jù)位置的表達(dá)
在匯編語言中如何表達(dá)數(shù)據(jù)位置?匯編語言中用3個(gè)概念來表達(dá)數(shù)據(jù)的位置,即立即數(shù)、寄存器、地址(偏移
地址和段地址)。
1. 立即數(shù)(idata)
對(duì)于直接包含在機(jī)器指令中的數(shù)據(jù)(執(zhí)行前在CPU的指令緩沖器中),在匯編語言中稱為:立即數(shù)(idata)。
例:mov ax, 136aH ;指令要處理的數(shù)據(jù)就是立即數(shù)136aH。
Add ax, 2000H ;指令要處理的數(shù)據(jù)就是立即數(shù)2000H。
Sub ax, a2c7H ;指令要處理的數(shù)據(jù)就是立即數(shù)a2c7H。
2. 寄存器
指令要處理的數(shù)據(jù)在寄存器中,在匯編指令中給出相應(yīng)的寄存器名。
例:mov ax, bx ;指令要處理的數(shù)據(jù)在bx中。
Mov ds, ax ;指令要處理的數(shù)據(jù)在ax中。
Push bx ;指令要處理的數(shù)據(jù)在bx中。
Mov DS:[123a], bx ;指令要處理的數(shù)據(jù)在bx中。
3. 段地址和偏移地址
指令要處理的數(shù)據(jù)在內(nèi)存中,在匯編指令中可用[…]的格式給出偏移地址,段地址在某個(gè)段寄存器中。比如以下
的指令:
Mov ax, [107a]
Mov ax, [di]
Mov ax, [bx+8]
Mov ax, [bx+si]
Mov ax, [bx+si+8]
指令要處理的數(shù)據(jù)偏移地址在[…]中,段地址默認(rèn)在DS中。
下面的指令:
Mov ax, [bp]
Mov ax, [bp+8]
Mov ax, [bp+si]
Mov ax, [bp+si+8]
指令要處理的數(shù)據(jù)偏移地址在[…]中,段地址默認(rèn)在SS中。
存放段地址的寄存器也可以是顯性給出的,比如以下指令:
mov ax, DS:[bp] ;指令要處理的數(shù)據(jù),段地址在DS中。
Mov ax, ES:[bx] ;指令要處理的數(shù)據(jù),段地址在ES中。
Mov ax, SS:[bx+si] ;指令要處理的數(shù)據(jù),段地址在SS中。
Mov ax, CS:[bx+si+8] ;指令要處理的數(shù)據(jù),段地址在CS中。
4、尋址方式
對(duì)尋址方式進(jìn)行一下總結(jié),見下表:表中EA=偏移地址,SA=段地址,寄存器加上一個(gè)小括號(hào),表示這個(gè)
寄存器中的數(shù)值,比如第二條含義:EA=(bx);SA=(ds),(bx)就表示bx中的數(shù)值,(ds)就表示ds中的數(shù)
值。
5、指令要處理的數(shù)據(jù)有多長
8086CPU的指令,可以處理兩種尺寸的數(shù)據(jù):byte和word。所以在機(jī)器指令中要指明,指令進(jìn)行的是字操
作還是字節(jié)操作,對(duì)于這個(gè)問題,匯編語言中用以下方式處理。
1. 通過寄存器名指明要處理的數(shù)據(jù)的尺寸。
例如,下面的指令中,寄存器指明了指令進(jìn)行的是字操作,因?yàn)檫@些寄存器是16位的。
Mov ax, 123H
Mov bx, DS:[210a]
Add ax, 1000H
Sub bx, 2ffH
下面的指令中,寄存器指明了指令進(jìn)行的是字節(jié)操作,因?yàn)檫@些寄存器是8位的。
Mov al, 12H
Mov bl, DS:[210a]
Add al, 10H
Sub bl, 2fH
2. 在沒有寄存器名存在的情況下,用操作符word prt或byte prt指明內(nèi)存單元的長度,前者為字單元,后者
為字節(jié)單元。
例如,下面的指令中,用word ptr指明了指令訪問的內(nèi)存單元是一個(gè)字單元。
Mov word ptr DS:[a017], 28H
Add word ptr [bx], 78H
下面的指令中,用byte prt指明了指令訪問的內(nèi)存單元是一個(gè)字節(jié)單元。
Mov byte ptr DS:[1a7], 1aH
Add byte ptr [bx], 62H
在沒有寄存器參與的內(nèi)存單元訪問指令中,用word ptr或byte ptr顯性地指明所要訪問的內(nèi)存單元的長度是
很必要的,否則,CPU無法得知所要訪問的單元是字單元還是字節(jié)單元,從而造成出錯(cuò)。
3. 其它方法。有些指令默認(rèn)了訪問的是字單元還是字節(jié)單元,比如:push [123a]和pop[123c]就不用指明訪
問的是字單元還是字節(jié)單元,因?yàn)閜ush和pop指令只進(jìn)行字操作。
6、mul指令
Mul為乘法指令,使用mul做乘法的時(shí)候,注意以下兩點(diǎn):
1. 兩個(gè)相乘的數(shù):這兩個(gè)相乘的數(shù),要么都是8位,要么都是16位,如果是8位,一個(gè)默認(rèn)放在al中,另一
個(gè)放在8位寄存器或內(nèi)存字節(jié)單元中;如果是16位,一個(gè)默認(rèn)放在ax中,另一個(gè)放在16位寄存器或內(nèi)存字單元
中。
2.結(jié)果:如果是8位乘法,結(jié)果默認(rèn)放在ax中,如果是16位乘法,結(jié)果高位默認(rèn)在dx中存放,低位在ax
中存放。
指令格式如下:
Mul 通用寄存器
Mul 內(nèi)存單元
內(nèi)存單元可以用不同的尋址方式給出,比如:
Mul byte ptr DS:[7102] ;8位乘法。
Mul word ptr [bx+si+8] ;16位乘法。
例1:計(jì)算100×10。
100和10都小于255,可以做8位乘法,代碼如下:
Mov al, 100
Mov bl, 10
Mul bl
結(jié)果:ax=al×bl=100×10=1000(3E8H)
例2:計(jì)算100×10000。
100小于255,可10000大于255,所以必須做16位乘法,代碼如下:
Mov ax, 100
Mov bx, 10000
Mul bx
結(jié)果:ax×bx=100×10000=1000000(F4240H)
Ax=4240H dx=FH
7、div指令
Div是除法指令,使用div做除法的時(shí)候,應(yīng)注意以下問題:
1. 除數(shù):有8位和16位兩種,在一個(gè)寄存器或內(nèi)存單元中。
2. 被除數(shù):如果除數(shù)為8位,被除數(shù)則為16位,默認(rèn)放在ax中;如果除數(shù)為16位,被除數(shù)則為32位,在
Dx和ax中存放,dx存放高16位,ax存放低16位。
3. 結(jié)果:如果除數(shù)為8位,則al存儲(chǔ)結(jié)果的商,ah存儲(chǔ)結(jié)果的余數(shù);如果除數(shù)為16位,則ax存儲(chǔ)結(jié)果的
商,dx存儲(chǔ)結(jié)果的余數(shù)。
指令格式如下:
Div 通用寄存器
Div 內(nèi)存單元
內(nèi)存單元可以用不同的尋址方式給出,比如:
Div byte ptr DS:[21a5] ;除數(shù)為8位的除法。
Div word ptr [bx+si+8] ;除數(shù)為16位的除法。
例1:計(jì)算100001÷100。
被除數(shù)100001為32位,轉(zhuǎn)化成16進(jìn)制為186a1H,低16位值86a1H放在ax中,高16位值1H放在
Dx中,除數(shù)100轉(zhuǎn)化為16進(jìn)制64H后,放在一個(gè)16位寄存器中,代碼如下:
Mov dx, 1H
Mov ax, 86a1H
Mov bx, 64H
Div bx
結(jié)果:(dx×10000H+ax)÷bx=186a1H÷64H=3E8H余1。
Ax=3e8H(1000) dx=1H
例2.計(jì)算1001÷100。
被除數(shù)1001可用ax存放,除數(shù)100可用8位寄存器存放,代碼如下:
Mov ax, 1001
Mov bl, 100
Div bl
結(jié)果:ax÷bl=1001÷100=10余1。
Al=10 ah=1
作者:chen.yu
深信服三年半工作經(jīng)驗(yàn),目前就職游戲廠商,希望能和大家交流和學(xué)習(xí),
微信公眾號(hào):編程入門到禿頭 或掃描下面二維碼
零基礎(chǔ)入門進(jìn)階人工智能(鏈接)