原文鏈接:點擊打開鏈接
問題:我剛開始學習ARM彙編語言,不太清楚如何利用MOV指令將立即數傳入到寄存器。在ARM參考手冊及我的課本中,都說MOV指令後跟的立即數變化範圍是0~255。但是當我在ADS1.2集成開發環境中進行測試時,下述指令語句卻正常運行。
MOV R2, #0xFFFFFFFF
根據上述說法數字0xFFFFFFFF不是超出了範圍嗎?爲什麼會出現這種情況呢?
回答:ARM可以對立即數進行一些特定的操作,因爲ARM核內集成了桶形移位器,ARM操作碼可以藉此完成一些特定操作。下文介紹ARM彙編器使用了哪些技巧,從而使一個大的立即數達到ARM指令可處理的小空間的。
—————————————————————————————————————————————————
不是任意一個32位數都可以表示成32位指令字。ARM數據處理指令在指令字中有12位空間用於存數值。如下圖所示它是由4位循環移位值和8位立即數組成:
4位循環移位值保存在11-8位上,它乘以2從而得到循環移位範圍0-30。
根據這種設計原則,我們可以表示的立即數如下:
- 0x000000FF
- 0x00000FF0
- 0xFF000000
- 0xF000000F
而像下面這樣的立即數
- 0x000001FE
- 0xF000F000
- 0x55550000
是不符合ARM指令處理規範的,所以無法直接處理。
彙編器會把大的數轉化成循環移位形式,即由8位二進制數循環右移偶數次得到,循環移位範圍是0-30。不合法的立即數會產生錯誤。
有些彙編器會使用一些其它技巧,如使用MVN代替MOV得到一些數的按位取反數。例如指令MOV r0, #0xFFFFFFFF可以被彙編爲MVN r0, #0。
以上這種問題導致有些常數是ARM友好的(ARM friendly),有些則不是。所以仔細研究一下你正在使用的數,也許還有再進一步優化的餘地。
你可以使用指令序列創建一些單條指令無法操作的常數,如:
MOV r2,#0x55 ; R2 = 0x00000055
ORR r2, r2, r2, LSL #8 ; R2= 0x00005555
ORR r2, r2, r2, LSL #16 ; R2 =0x55555555
或者從存儲器中裝載數值:
LDR r2, =0x55555555
如果可能的話,僞指令LDR Rx,=const會嘗試用一條指令創建常數,否則會生成一個LDR。
—————————————————————————————————————————————————
你所提到的例子可能使用了上文討論的這些技巧,如生成了MVN操作碼來裝載立即數的按位取反值。這些操作並不適用於所有立即數,但是ARM彙編器很機智地知道該如何處理(C編譯器當然也是)。如果有些數無法用移位/取反方法表示,這些數通常會從PC相關的位置裝載或者用幾條指令來創建。
附:此鏈接可能有助於你對上文的理解 點擊打開鏈接