ARM中當立即數作爲第二個操作數(源操作數)時如何使用MOV指令

       原文鏈接:點擊打開鏈接

 

問題:我剛開始學習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相關的位置裝載或者用幾條指令來創建。

附:此鏈接可能有助於你對上文的理解 點擊打開鏈接

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章