Assembly 控制結(jié)構(gòu)

2018-10-27 11:09 更新

高級(jí)語(yǔ)言提供高級(jí)的控制結(jié)構(gòu)(例如,if 和while語(yǔ)句)來(lái)控制執(zhí)行的順序。匯編語(yǔ)言并沒(méi)有提供像這樣的復(fù)雜控制結(jié)構(gòu)。它使用聲名狼藉的goto來(lái)替代,如果使用不恰當(dāng)可能會(huì)導(dǎo)致非常復(fù)雜的代碼。但是,它是能夠?qū)懗鼋Y(jié)構(gòu)化的匯編語(yǔ)言程序。基本的步驟是使用熟悉的高級(jí)語(yǔ)言控制結(jié)構(gòu)來(lái)設(shè)計(jì)程序的邏輯,然后將這個(gè)設(shè)計(jì)翻譯成恰當(dāng)?shù)膮R編語(yǔ)言(就像一個(gè)編譯器要做的一樣)。


比較

控制結(jié)構(gòu)決定做什么是基于數(shù)據(jù)的比較的。在匯編語(yǔ)言中,比較的結(jié)果儲(chǔ)存在FLAGS寄存器中,以便以后使用。80x86提供CMP指令來(lái)執(zhí)行比較操作。FLAGS寄存器根據(jù)CMP指令的兩個(gè)操作數(shù)的不同來(lái)設(shè)置。具體的操作是相減,然后FLAGS根據(jù)結(jié)果來(lái)設(shè)置,但是結(jié)果是不在任何地方儲(chǔ)存的。
如果你需要結(jié)果,可以使用SUB來(lái)代替CMP指令。

對(duì)于無(wú)符號(hào)整形,有兩個(gè)標(biāo)志位(在FLAGS寄存器里的位) 是非常重要的:零標(biāo)志位(zero flag(ZF)) 和進(jìn)位標(biāo)志位(carryflag(CF)) 。如果比較的結(jié)果是0的話,零標(biāo)志位將置成(1) 。進(jìn)位標(biāo)志位在減法中當(dāng)作一個(gè)借位來(lái)使用。考慮這個(gè)比較:

cmp    vleft, vright

vleft - vright的差別被計(jì)算出來(lái),然后相應(yīng)地設(shè)置標(biāo)志位。如果CMP執(zhí)行后得到差別為0,即vleft = vright那么ZF就被置位了(也就是: 1),但是CF不被置位(也就是: 0)。如果vleft > vright,那么ZF就不被置位而且CF也不被置位(沒(méi)有借位)。如果vleft < vright,那么ZF就不被置位,
而CF就被置位了(有借位)。

對(duì)于有符號(hào)整形,有三個(gè)標(biāo)志位非常重要:零標(biāo)志位(zero °ag (ZF)),溢出標(biāo)志位(over°ow °ag(OF))和符號(hào)標(biāo)志位(sign °ag (SF))。如果一個(gè)操作的結(jié)果上溢(下溢),那么溢出標(biāo)志位將被置位。如果一個(gè)操作的結(jié)果為負(fù)數(shù),那么符號(hào)標(biāo)志位將被置位。如果vleft = vright,那么ZF將被置
位(正好與無(wú)符號(hào)整形一樣)。如果vleft > vright,那么ZF不被設(shè)置,而且SF = OF。如果vleft < vright,那么ZF不被設(shè)置而且SF 6= OF。

不要忘記其它的指令同樣會(huì)改變FLAGS寄存器,不僅僅CMP可以。

分支指令

分支指令可以將執(zhí)行控制權(quán)轉(zhuǎn)移到一個(gè)程序的任意一點(diǎn)上。換言之,它們像goto一樣運(yùn)作。有兩種類(lèi)型的分支:無(wú)條件的和有條件的。一個(gè)無(wú)條件的分支就跟goto一樣,它總會(huì)產(chǎn)生分支。一個(gè)有條件分支可能也可能不產(chǎn)生分支,它取決于在FLAGS寄存器里的標(biāo)志位。如果一個(gè)有條件分支沒(méi)
有產(chǎn)生分支,控制權(quán)將傳遞到下一指令。

JMP (jump的簡(jiǎn)稱(chēng))指令產(chǎn)生無(wú)條件分支。它唯一的參數(shù)通常是一個(gè)指向分支指向的指令的代碼標(biāo)號(hào)。匯編器和連接器將用指令的正確地址來(lái)替代這個(gè)標(biāo)號(hào)。這又是一個(gè)乏味的操作數(shù),通過(guò)這個(gè),匯編器使得程序員的日子不好過(guò)。能認(rèn)識(shí)到在JMP指令后的指令不會(huì)被執(zhí)行,除非另一條分支指令
指向它,是非常重要的。

這兒有jump指令的幾個(gè)變更形式:

SHORT 這個(gè)跳轉(zhuǎn)類(lèi)型局限在一小范圍內(nèi)。它僅僅可以在內(nèi)存中向上或向下移動(dòng)128字節(jié)。這個(gè)類(lèi)型的好處是相對(duì)于其它的,它使用較少的內(nèi)存。它使用一個(gè)有符號(hào)字節(jié)來(lái)儲(chǔ)存跳轉(zhuǎn)的位移。位移表示向前或向后移動(dòng)的字節(jié)數(shù)(位移須加上EIP)。為了指定一個(gè)短跳轉(zhuǎn),需在JMP指令里的變量之前使用關(guān)鍵字SHORT。

NEAR 這個(gè)跳轉(zhuǎn)類(lèi)型是無(wú)條件和有條件分支的缺省類(lèi)型,它可以用來(lái)跳到一段中的任意地方。事實(shí)上,80386支持兩種類(lèi)型的近跳轉(zhuǎn)。其中一個(gè)的位移使用兩個(gè)字節(jié)。它就允許你向上或向下移動(dòng)32,000個(gè)字節(jié)。另一種類(lèi)型的位移使用四個(gè)字節(jié),當(dāng)然它就允許你移動(dòng)到代碼段中的任意位置。四字節(jié)類(lèi)型是386保護(hù)模式的缺省類(lèi)型。兩個(gè)字節(jié)類(lèi)型可以通過(guò)在JMP指令里的變量之前放置關(guān)鍵字WORD來(lái)指定。

FAR 這個(gè)跳轉(zhuǎn)類(lèi)型允許控制轉(zhuǎn)移到另一個(gè)代碼段。在386保護(hù)模式下,這種事情是非常鮮見(jiàn)的。

簡(jiǎn)單條件分支

有效的代碼標(biāo)號(hào)遵守與數(shù)據(jù)變量一樣的規(guī)則。代碼標(biāo)號(hào)通過(guò)在代碼段里把它們放在它們標(biāo)記的聲明前面來(lái)定義它們。有一個(gè)冒號(hào)放在變量定義的地方的結(jié)尾處。這個(gè)冒號(hào)不是名字的一部分。條件分支有許多不同的指令。它們都使用一個(gè)代碼標(biāo)號(hào)作為它們唯一的操作數(shù)。最簡(jiǎn)單的就是看FLAGS寄存器里的一個(gè)標(biāo)志位來(lái)決定是否要分支。看表2.3得到關(guān)于這些指令的列表。(PF是奇偶標(biāo)志位(parity flag) ,它表示結(jié)果中的低8位1的位數(shù)值為奇數(shù)個(gè)或偶數(shù)個(gè)。)

下面的偽碼:

if ( EAX == 0 )
  EBX = 1;
else
  EBX = 2;
可以寫(xiě)成匯編形式,如:

匯編

其它比較使用在表2.3里的條件分支并不是很容易。為了舉例說(shuō)明,考
慮下面的偽碼:

if ( EAX >= 5 )
  EBX = 1;
else
  EBX = 2;

如果EAX大于或等于5,ZF可能被置位或不置位,而SF將等于OF。這是測(cè)試這些條件的匯編代碼(假定EAX是有符號(hào)的):

測(cè)試

有符號(hào)和無(wú)符號(hào)指令比較

上面的代碼使用起來(lái)非常不便。幸運(yùn)的是,80x86提供了額外的分支指令使這種類(lèi)型的測(cè)試條件更容易些。每個(gè)版本都分為有符號(hào)和無(wú)符號(hào)兩種。表2.4展示了這些指令。等于或不等于分支(JE和JNE)對(duì)于有符號(hào)和無(wú)符號(hào)整形是相同的。(事實(shí)上,JE和JZ,JNE和JNZ基本上完全相同。) 每個(gè)其它的分支指令都有兩個(gè)同義字。例如:看JL (jump less than)和JNGE(jump not greater than or equal to)。有相同的指令這是因?yàn)椋?br />

公式

無(wú)符號(hào)分支使用A代表大于而B(niǎo)代表小于,替換了L和G。

使用這些新的指令,上面的偽碼可以更容易地翻譯成匯編語(yǔ)言:

翻譯


循環(huán)指令

80x86提供了幾條專(zhuān)門(mén)為實(shí)現(xiàn)像for一樣的循環(huán)而設(shè)計(jì)的指令。每一個(gè)這
樣的指令帶有一個(gè)代碼標(biāo)號(hào)作為它們唯一的操作數(shù)。

LOOP ECX自減,如果ECX 6= 0,分支到代碼標(biāo)號(hào)指向的地址

LOOPE, LOOPZ ECX自減(FLAGS寄存器沒(méi)有被修改),如果ECX 6= 0
而且ZF = 1,則分支

LOOPNE, LOOPNZ ECX自減(FLAGS沒(méi)有改變),如果ECX 6= 0 
而且ZF = 0,則分支

最后兩個(gè)循環(huán)指令對(duì)于連續(xù)的查找循環(huán)是非常有用的。下面的偽碼:
sum = 0;
for( i=10; i >0; i?? )
   sum += i;

可以翻譯在匯編語(yǔ)言,如:
實(shí)例
以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)