新聞中心

EEPW首頁(yè) > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > ARM匯編之合法立即數(shù)的快速判斷方法

ARM匯編之合法立即數(shù)的快速判斷方法

作者: 時(shí)間:2016-11-09 來源:網(wǎng)絡(luò) 收藏
ARM匯編的數(shù)據(jù)處理指令中經(jīng)常會(huì)使用到常數(shù),而ARM匯編中規(guī)定使用的常數(shù)必須是立即數(shù)。

在討論什么是立即數(shù),為什么有立即數(shù),如何快速判斷立即數(shù)之前,我們先來弄明白一個(gè)問題:什么不是立即數(shù)。

本文引用地址:http://m.butianyuan.cn/article/201611/317885.htm

匯編指令是對(duì)數(shù)據(jù)(指令、數(shù)據(jù))對(duì)象的操作,很關(guān)鍵的一個(gè)問題我們?nèi)绾螌ふ椅覀兊牟僮鲗?duì)象?匯編指令是一門關(guān)于尋址的藝術(shù)。ARM有九種尋址方式:1.寄存器尋址2.立即尋址3.寄存器移位尋址4.寄存器間接尋址5.基址尋址6.多寄存器尋址7.堆棧尋址8.塊拷貝尋址9.相對(duì)尋址。 九中尋址方式都是再告訴我們?nèi)绾螌ふ椅覀兊牟僮鲗?duì)象,其中立即數(shù)尋址相對(duì)于其他尋址方式有什么不同?

為了理解ARM指令是如何實(shí)現(xiàn)對(duì)數(shù)據(jù)對(duì)象操作,我們需要知道ARM指令的機(jī)器碼格式。(熟悉的可以直接跳到如何快速判斷合法立即數(shù))(ARM指令的典型編碼格式如下:)


ARM指令語法格式如下:

opcode{}{s}rd,rn,

各個(gè)部分解釋如下:

*cond(bit[31:28]):指令的條件碼助記符,默認(rèn)是al(無條件執(zhí)行)

*type(bit[27:32]):指令碼類型,根據(jù)其編碼的不同,所代表的類型:00:數(shù)據(jù)處理指令及雜類Load/Store指令;01:Load/Store指令;10:批量Load/Store指令及分支指令;11:協(xié)處理指令與軟中斷指令

*X(bit[25]):第二操作數(shù)類型標(biāo)志碼。(X=0表示第二操作數(shù)是移位寄存器,X=1表示第二操作數(shù)是立即數(shù))

*opcode(bit[24:21]):指令助記符,如mov

*S(bit[20]):指令的執(zhí)行是否影響CPSR(當(dāng)前程序狀態(tài)寄存器)的值(S:state)

*Rn(bit[19:16]):包含第一個(gè)操作數(shù)的寄存器編碼(RegisterNum)

*Rd(bit[15:12]):目標(biāo)寄存器編碼(RegisterDestination)

*opcode2(bit[11:0]):第二操作數(shù)

ARM指令的第二操作數(shù)用法比較靈活,有如下幾種情況。

* 立即數(shù)

* 寄存器

* 寄存器移位

ARM指令里有兩個(gè)操作數(shù)Rn,opcode2和一個(gè)目的寄存器Rd(用于存放操作結(jié)果),Rn為包含第一個(gè)操作數(shù)的寄存器地址,opcode2有三種形式:立即數(shù)方式、寄存器方式、寄存器移位方式,其中寄存器和寄存器位移方式也都是存儲(chǔ)的寄存器地址所以要通過寄存器間接獲得數(shù)據(jù)對(duì)象,也就是非立即,而立即數(shù)形式不同,指令中opcode2數(shù)據(jù)域不是地址而是數(shù)據(jù)本身,所以叫立即數(shù)。也就是說其它尋值方式最終操作的數(shù)據(jù)對(duì)象是放在Rn或opcode2所指向的寄存器地址中的數(shù)據(jù),顯然立即數(shù)操作對(duì)象也需要根據(jù)地址尋找,但它所在的地址比較特殊,或者說它存儲(chǔ)的位置比較特殊,因?yàn)樗苯哟鎯?chǔ)在指令opcode2中。

而opcode2只有12位,也就是說opcode2所表示的立即數(shù)有一定限制0-4095,為了進(jìn)一步擴(kuò)大12bit數(shù)據(jù)所能表示數(shù)的范圍,ARM規(guī)定了數(shù)據(jù)的格式:也即

立即數(shù)是由一個(gè)8位的常數(shù)循環(huán)右移偶數(shù)位得到的,其中循環(huán)右移 的位數(shù)由一個(gè)4位2進(jìn)制的兩倍表示,公式如下:

immediate=immed_8<<(2*rotate_imm4) “<<”表示循環(huán)右移 簡(jiǎn)單的說一個(gè)常數(shù)如果可以由一個(gè)8位的常數(shù)循環(huán)移位偶數(shù)位得到,那么就是立即數(shù)。


為什么會(huì)有立即數(shù)這樣的規(guī)定呢?這是由于所有的ARM指令是精簡(jiǎn)指令集,指令長(zhǎng)度固定都是32位,對(duì)于ARM數(shù)據(jù)處理指令自然也是一樣。數(shù)據(jù)處理指令大致可包含3類,數(shù)據(jù)傳送指令、數(shù)據(jù)算術(shù)邏輯運(yùn)算指令和數(shù)據(jù)比較指令。在一條ARM數(shù)據(jù)處理指令中,除了要包含處理的數(shù)據(jù)值外,還要標(biāo)識(shí)ARM命令名稱,控制位,寄存器等其他信息。這樣在一條ARM數(shù)據(jù)處理指令中,能用于表示要處理的數(shù)據(jù)值的位數(shù)只能小于32位。

ARM在指令格式中設(shè)定,只能用指令機(jī)器碼32位中的低12位來表示要操作的常數(shù)。ARM處理器是按32位來處理數(shù)據(jù)的,ARM處理器處理的數(shù)據(jù)是32位,如果簡(jiǎn)單的用這12位來表示,顯然范圍太小了,為了擴(kuò)展到32位,因此使用了構(gòu)造的方法,在12位中用8位表示基本數(shù)據(jù)值,用4位表示位移值,通過用8位基本數(shù)據(jù)值往右循環(huán)移動(dòng)4位位移值*2次,來表示要操作的常數(shù)。這里要強(qiáng)調(diào)最終的循環(huán)次數(shù)是4位位移值乘以2得到的,所以得到的最終循環(huán)次數(shù)肯定是一個(gè)偶數(shù),為什么要乘以2呢,實(shí)質(zhì)還是因?yàn)榉秶粔颍?位表示位移次數(shù),最大才15次,加上8位數(shù)據(jù)還是不夠32位,這樣只能通過ALU的內(nèi)部結(jié)構(gòu)設(shè)計(jì)將4位位移次數(shù)乘以2,這樣就能用12位表示32位常數(shù)了。

通過循環(huán)偶數(shù)位得的到操作數(shù),擴(kuò)大了操作數(shù)的范圍,但也帶來了問題,并不是每個(gè)數(shù)據(jù)都能通過8位基本數(shù)據(jù)循環(huán)移動(dòng)偶數(shù)為得到,如果你在ARM數(shù)據(jù)處理指令中使用的操作數(shù),不是立即數(shù),比如MOV R1,#0x12345678,編譯器就會(huì)報(bào)錯(cuò),所以我們?cè)谑褂们氨仨氝M(jìn)行判斷,這也是很多ARM相關(guān)求職筆試中??嫉囊坏李}目。

那怎樣怎么快速判斷一個(gè)數(shù)是否是立即數(shù)?對(duì)于簡(jiǎn)單的數(shù)字我們可以直接判斷,比如小于255的數(shù)字肯定是立即數(shù)。對(duì)相對(duì)復(fù)雜的數(shù)字進(jìn)行判斷就需要先把它轉(zhuǎn)換為2進(jìn)制形式,然后根據(jù)定義進(jìn)行判斷了。我這里總結(jié)了個(gè)比較快速的方法:(簡(jiǎn)而言之,就是利用立即數(shù)的生成方法,迅速逆推到合法的8位常熟)

1、把數(shù)據(jù)轉(zhuǎn)換成二進(jìn)制形式,從低位到高位寫成4位1組的形式,最高位一組不夠四位的,在最高位前面補(bǔ)0。

2、數(shù)1的個(gè)數(shù),如果大于8個(gè)肯定不是立即數(shù),如果小于等于8進(jìn)行下面步驟。

3、如果數(shù)據(jù)中間有連續(xù)的大于等于24個(gè)0,循環(huán)左移4的倍數(shù),使高位全為0。

4、找到最高位的1,去掉前面最大偶數(shù)個(gè)0。

5、找到最低位的1,去掉后面最大偶數(shù)個(gè)0。

6、數(shù)剩下的位數(shù),如果小于等于8位,那么這個(gè)數(shù)就是立即數(shù),反之就不是立即數(shù)。

針對(duì)可能現(xiàn)的情況,舉5個(gè)典型例子:

(1)0x4FF (2)0x122 (3)0x234 (4)0xF000000F (5)0x8000007F

例1: 0x4FF

第一步:0100 1111 1111

第二步:其中1的個(gè)數(shù)是9個(gè),大于8個(gè),判定不是立即數(shù)

例2: 0x122

第一步: 0001 0010 0010

第二步: 其中1的個(gè)數(shù)4個(gè),小于8,繼續(xù)

第三步: 其中沒有連續(xù)大于等于24個(gè)0,繼續(xù)

第四部: xx01 0010 0010 (最高位前面有3個(gè)0,最大偶數(shù)2,去掉2個(gè)0)

第五步: xx10 0011 0010 (最低位后面只有1個(gè)0,最大偶數(shù)0)

第六部: 剩下10 0011 0010 共10位,大于8,判定0x122不是立即數(shù)

例3: 0x234

第一步: 0010 0011 0100

第二步: 其中1的個(gè)數(shù)4個(gè),小于8,繼續(xù)

第三步: 其中沒有連續(xù)大于等于24個(gè)0,繼續(xù)

第四部: xx10 0011 0100

第五步: xx10 0011 01xx

第六部: 剩下10 0011 01 共8位,等于8,判定0x234是立即數(shù)

例4: 0xF000000F

第一步: 1111 0000 0000 0000 0000 0000 0000 1111

第二步: 其中1的個(gè)數(shù)8個(gè),沒有大于8,繼續(xù)

第三步: 其中有連續(xù)24個(gè)0,循環(huán)左移4位,使高位全為0

0000 0000 0000 0000 0000 0000 0000 1111 1111

第四部: xxxx xxxx xxxx xxxx xxxx xxxx xxxx 1111 1111

第五步: xxxx xxxx xxxx xxxx xxxx xxxx xxxx 1111 1111

第六部: 剩下1111 1111共8位,等于8,判定0xF000000F是立即數(shù)

例5: 0x8000007F

第一步: 1000 0000 0000 0000 0000 0000 0111 1111

第二步: 其中1的個(gè)數(shù)8個(gè),沒有大于8,繼續(xù)

第三步: 其中有連續(xù)24個(gè)0,循環(huán)左移4位,使高位全為0

0000 0000 0000 0000 0000 0000 0111 1111 1000

第四部: xxxx xxxx xxxx xxxx xxxx xxxx 0111 1111 10xx

第五步: xxxx xxxx xxxx xxxx xxxx xxxx 0111 1111 10xx

第六部: 剩下0111 1111 10共10位,等于8,判定0x7000008F是立即數(shù)

問題還沒有結(jié)束,我們?cè)贏RM匯編中如何規(guī)避立即數(shù)這個(gè)問題呢,其實(shí)可以使用ARM匯編LDR偽指令,例如直接把MOV指令變?yōu)椋?LDR R1,=0x12345678這樣編譯器就不會(huì)報(bào)錯(cuò)了。但這種方法也有弊端會(huì)增加開銷和影響執(zhí)行效率。同時(shí)ARM匯編中還有有效數(shù)的概念,比如 MOV R1,#0xFFFFFFFF 指令中 0xFFFFFFFF 不是立即數(shù),但是是有效數(shù),編譯器最自動(dòng)把原指令變換為 MVN R1,#0,也不會(huì)報(bào)錯(cuò)。有效數(shù)判定:原數(shù)是立即數(shù)或者原數(shù)反碼是立即數(shù)。

希望對(duì)大家有幫助。




關(guān)鍵詞: ARM匯編合法立即

評(píng)論


技術(shù)專區(qū)

關(guān)閉