第三章 一些ARM指令
今天我們開始學習一些ARM指令,不過之前有些事情你要記住(和執行速度有關):
·對齊你的資料。使用.align命令,比如.align 4,.align 2。如果你使用了沒有對齊的地址,CPU會做一些汗死人的操作絕對把速度降下來。
·不訪問記憶體的指令總是快一些,最大限度地使用寄存器,不要從記憶體載入資料。用MOV和ADD指令載入32位立即數,不要用LDR指令。
指令LDR
指令LDR還蠻多用途的,儘管它主要的功能是從記憶體中load(讀取)一個值。它有多種定址模式,有些我都不太清楚...你去翻手冊吧。我挺走運地在一家特價書店裡淘到一本《ARM Architecture Reference Manual 2nd Edition》,GbaDev.org上也有一些手冊。LDR最簡單的形式是從ROM的“池”(或者你運行程式的什麼地方)中讀取一個值。看起來像是這樣:
ldr r0,=0x32bitnumber(0x32bitnumber是一個32位元,比如0x403, 0xCAFEBABE, 0xBAD00FED, 0x6000000...).
這個32位元是儲存在“池”中的,彙編器會自動處理。一般來說,你要明確地在每一個子程式後面(或者檔案末尾,如果程式不大的話)使用.ltorg指令告訴彙編器在哪裡放置“池”。
(譯註,這裡恐怕還是不甚明了,放一張圖給點感性認識)
下一個形式是從寄存器定址,如:
ldr r0, [r1]
它會將r1所指的地址處的32位元載入r0。(類似於C裡面的r0 = *r1;)
這裡提一個文法點,如果寄存器外面有個方括弧,代表的是寄存器指向的地址處的內容,而不是寄存器中的值本身。
下面是一些其他你需要瞭解的定址方式:(我一直使用r0,其實隨便哪個寄存器都能用。寄存器也能用在#offset處)
[r0, #offset] 地址是r0+#offset。這個叫做Pre-indexed。
如果你在閉括弧後面加個!,那麼地址還要寫入r0。這個叫做“寫回”,在迴圈的時候很有用,這樣你就不用寫另外一條更新地址指標的指令了。
[r0], #offset 地址是r0,然後r0+#offset寫入r0。這個叫做Post-Indexed。
寫回是自動進行的。
這些只是定址模式,完整的指令應該是“ldr r1, address_mode”。你可以隨便寫一些“ldr r1, [r0, r2]”、“ldr r3, [r2], #4”之類的東西。第一條的意思是“r1 = *(r0 + r2)”,第二條的意思是“r3 = *r2; r2 += 4;”。ARM指令很強大吧?相信我,你其實還沒看到什麼呢!
指令STR
指令STR用起來和LDR幾乎一樣(除了 ,=0x32bitnumber形式)。唯一的區別在於:它把一個數值store(寫入)到記憶體中。這個很簡單,就不說了。
指令MOV
指令MOV用於寄存器之間移動資料,它也包括一個位移指令。文法如下:(reg1,reg2可以是任何寄存器,reg2的值不會變化)
mov reg1, reg2 {,LSL/LSR/ASR/ROR/RRX #} 把reg2的值複製到reg1,如果有一個可選的位移參數就會對reg2位移。如:mov r0, r1, LSL #2,就是r0 = r1 << 2。
mov reg1, #0xnumber 將一個立即數儲存到reg1中,不過這個數是有限制的,它必須要能夠由一個byte大的數通過位移得到。
還能做一些如mov r0, r0之類的操作來當做NOP(不做任何事情),如果你想要位移一個寄存器值,指令MOV就是你想要的:
mov r0, r0, LSL #3,r0 = r0 << 3;ARM指令集裡面沒有單獨的位移指令。
很多指令的位移的文法是一樣的(除了算術指令,ADD,SUB,EOR,ORR,AND,BIC之類的),都和MOV一樣,所以之後我不會再提位移文法了。
我希望這些東西你都掌握了,這些指令都很重要。接下來,我們來嘗試從RAM中讀取比較小的數,然後學習分支指令,最後分析一下第二章的程式。