四.ARM彙編 2017/10/26 22:39 彙編指令:CPU指令的助記符 僞彙編指令:本質上不是指令,是編譯器環境提供的,目的是用來指導編譯過程,經過編譯後僞指令最終不會生成機器碼
ARM彙編的特點1:LDR/STR架構 ARM采用RISC架構,CPU本身不能直接讀取記憶體(CISC結構的可以直接讀取記憶體),而需要先将記憶體中内容載入CPU中通用寄存器才能被CPU執行。 l ldr (load register) 将記憶體内容加載進入通用寄存器 str (store register) 将寄存器内容存入記憶體空間
ARM彙編的特點2:8種尋址方式
類别 | 示例 |
寄存器尋址 | mov r1, r2 |
立即尋址 | mov r0, #0xFF00} |
寄存器移位尋址 | mov r0, r1, lsl #3 @(r0=r1<<3) |
寄存器間接尋址 | ldr r1, [r2] |
基址變址尋址 | ldr r1,[r2,#4] @r1 = r2+4 |
多寄存器尋址 | ldmia r1!,{r2-r7,r12} |
堆棧尋址 | stmfd sp!, {r1-r7,lr} |
相對尋址 | beq flag |
ARM彙編的特點3:指令字尾 同一指令經常附帶不同字尾,變成不同的指令。經常使用的字尾有:
字尾 | 功能 |
B (byte) | 功能不變,操作長度變為8位 |
H (half word) | 功能不變,長度變為16位 |
S (signed) | 功能不變,操作數變為有符号 如 ldr ldrb ldrh ldrsb ldrsh |
S (S标志) | 功能不變,影響CPSR标志位 如 mov和movs |
ARM彙編的特點3:條件執行字尾
如果字尾條件滿足才執行。 例如: mov r0, r1 @r0 = r1 moveq r0,r1 @ if(eq) r0 =r1 條件字尾執行注意:條件字尾是否成立,不是取決于本句代碼,而是取決于這句代碼之前的代碼運作後的結果。
ARM彙編的特點4:多級指令流水線 S5PV210使用13級流水線。PC指向正被取值的指令,而非正在執行的指令。 多級指令流水線與一級一條指令執行的過程比較說明 簡單來說,執行某條指令至少要通過取指、譯碼、執行三個步驟。這就好像盲人在吃飯,第一步是用筷子夾出要吃的東西(從記憶體中取出指令),第二步是把吃的東西舉到鼻子底下聞一下看看是否能吃(分析該指令),第三步是放到嘴裡吃(執行指令)。即盲人最少要浪費3秒鐘。如果CPU也采取同樣的方法,執行一條指令,那就意味着 CPU需消耗3個指令周期才能完成一個動作,可見其運作效率的低下 為了彌補這個問題,ARM采用了一種多級流水線的指令執行方式,即是利用多個時鐘周期的時間去執行多條指令,進而大大提高了代碼運作效率。 這就好像一位樂于助人的科學家,知道了盲人吃飯的故事之後,給這位盲人制作了兩隻機械手,現在盲人已經有三隻手了,那麼他會怎樣吃飯呢?當他的第一隻手把吃的送到嘴裡吃的時候(執行指令),第二隻手已經将另外的食物湊到鼻子底下聞了(分析指令),而第三隻手此時正在從盤子裡夾第三樣東西呢。從此,盲人吃飯的效率就提高了三倍。即提高了效率。
五.資料傳輸指令 mov (move) mov r1, r0 @兩個寄存器之間資料傳遞 r1 = r0mov r1, #0xFF @将立即數指派給寄存器 r1 = 0xFF mvn 用法和mov一樣,差別是mvn是按位取反後傳遞 r1 = 0xFF,執行mov r0, r1 後 r0 = 0xFF 執行mvn r0, r1 後 r0 = 0xffffff00
算術指令 add 加法指令add r2, r0, r1 @(r2 = r0+r1) sub 減法指令sub r2, r0, r1 @(r2 = r0 - r1) rsb 逆向減法指令 adc 帶進位加法指令 sbc 帶借位減法指令 rsc 帶借位的逆向減法指令 邏輯指令 and 邏輯與 orr 邏輯或 eor 邏輯異或 bic 位清除指令 (bic r0, r1, #0x1F @将r1中的數的bit0到bit4清零後指派給r0 0x1F = 0001 1111) 比較指令 cmp cmp r0, r1 @(r0 - r1 = 0?) cmn cmn r0, r1 @(r0 + r1 = 0?) tst tst r0, 0xf @測試r0的bit0-bit3是否全為0 teq teq r0,r1, @P = r0 EOR r1 比較指令不用後加S 就能影響CPSR中的标志位。 乘法指令 mvl mla umull umlal smull smlal 都不常用,這裡隻作為知識點羅列。 前導零計數 clz 傳回操作數二進制編碼中第一個1前0的個數 CPSR通路指令 mrs & msr mrs 用來讀psr (cpsr&spsr) msr 用來寫psr mrs r0, cpsr 将cpsr的值讀入到r0中 ……………… 處理r0的值 msr cpsr, r0 将r0的值寫入到cpsr中 cpsr : 程式狀态寄存器,CPU中隻有一個,記錄程式運作狀态 spsr:CPU中有五個,分别在五種異常模式下,作用是從普通模式進入異常模式時,用來儲存之前普通模式下的cpsr的,在傳回普通模式時恢複原來的cpsr。 跳轉指令 b & bl &bx b 直接跳轉(沒打算傳回) bl (branch and link) 跳轉前把傳回位址存在lr寄存器中,以便傳回。 bx 跳轉同時切換到ARM模式,一般用于異常處理的跳轉。 訪存指令 ldr/srt & ldm/stm & swp 單個字/半字/位元組通路 ldr/str 多字批量通路 ldm/stm swp r1, r2, [r0] 記憶體和寄存器交換指令,将r0所指向記憶體中的資料寫入r1,并将r2中的資料寫入到r0所指向的記憶體。 swp r1, r1, [r0] 互換 軟中斷指令 swi (software interrupt) 用來實作作業系統中的系統調用。 彙編中的立即數 ARM指令都是32位,除了指令标記和操作标記外,本身隻能附帶很少位數的立即數,是以立即數有合法和非法之分。 合法立即數:經過任意位數的移位後非零部分可以用8位辨別的即為合法立即數(非零部分少于等于8位,0x000000ff 是合法立即數,0x00ff0000是合法立即數,0xf000000f循環移位之後仍然是合法立即數,0x000001ff是非法立即數)
六.協處理器以及協處理器指令 什麼是協處理器 Soc内部另一處理核心,協助CPU實作某些功能,被主CPU調用執行一定的任務。CP15 (cooperation processor) 協處理器和MMU、cache、TLB等處理有關,功能上和作業系統的虛拟位址映射、cache等的管理有關。 協處理器通路指令 mcr & mrc mrc 用于讀取CP15中的寄存器 mcr 用于寫CP15中的寄存器 Rd:ARM的普通寄存器,不能是r15/pc Crn:cp15的寄存器,合法值為c0 - c15 Crm:cp15的寄存器,一般均為c0 mrc p15, 0, r0, c1, c0, 0 mcr p15, 0, r0, c1, c0, 0 ldm/stm與棧的處理 ldr/str每周期隻能通路4個位元組記憶體,如果需要批量讀取,寫入記憶體時太慢,這個時候就要用ldm/stm (load register mutiplt / store register mutiplt) 多寄存器通路舉例 stmia sp, {r0-r12} 将r0存入sp指向的記憶體處,然後位址+4,将r1存入記憶體,然後位址再+4……直到将r12内容存入記憶體。
- 1
- 2
棧類型 空棧:棧指針指向 空位 ,每次存入資料後,sp+4 滿棧:棧指針指向 滿位 ,每次存入資料時,先sp+4然後再存入資料 增棧:棧指針移動時向 位址增加的方向 移動 減棧:棧指針移動時向 位址減小的方向 移動 是以有四種棧類型:空增棧,空減棧,滿增棧,滿減棧。 八種字尾
stmia和stmfd用的最多,其他基本沒用過
字尾 | 意義 |
ia (increase after) | 先傳輸,再位址+4 |
ib (increase before) | 先位址+4,再傳輸 |
da (decrease after) | 先傳輸,再位址-4 |
db (decreade before) | 先位址-4,再傳輸 |
fd (full decrease) | 滿遞減棧 |
ed (empty decrease) | 空遞減棧 |
fa | 滿遞增棧 |
ea | 空遞增棧 |
操作棧的時候使用相同的字尾,就會避免出錯。 !的作用 ldmia r0, {r2-r3} @把r0指向的記憶體中的資料讀入到r2中,然後記憶體位址+4再将+4後位址中的資料讀入到r3中。指令執行完畢後r0中的值 不變 。 ldmia r0!, {r2-r3} @把r0指向的記憶體中的資料讀入到r2中,然後記憶體位址+4再将+4後位址中的資料讀入到r3中。指令執行完畢後r0中的值 變化 。 感歎号的作用就是r0的值在ldm過程中發生的增加或者減小最後寫會到r0中。 ^的作用 ldmfd sp!, {r0-r6, pc} ldmfd sp!, {r0-r6, pc}^ ^:在目标寄存器中有pc時,會同時将spsr寫入到cpsr,一般用在 異常傳回 的時候。
七.GNU彙編僞指令 僞指令和指令最大的差別是經過編譯後不會生成機器碼 僞指令是和具體的編譯器相關的,我們使用gnu工具鍊,是以學習gnu環境下的彙編僞指令。 GNU彙編中的一些符号 @ 行注釋,可以在指令後邊也可以在行首 : 以冒号結束的是标号 . 點号表示目前指令的位址 立即數前面加#或者$,表示這是個立即數 常見的gnu彙編僞指令
僞指令 | 意義 |
.globl _start | 給_start外部連結屬性 |
.section .text | 指定目前為代碼段 |
.ascii .byte .short .long .word .quad .float .string | 定義資料 |
.align 4 | 以16(2^4)位元組記憶體位址對齊 |
.balignl 16,0xABCDEF | 16位元組對齊填充 |
.equ | 類似于C中的宏定義 |
.end | 彙編檔案的結束,不加無所謂 |
.include | 頭檔案包含 |
.arm或者.code32 | 聲明以下的代碼為arm指令不是thumb指令 |
.thumb或者.code16 | 聲明以下的代碼為thumb指令 |
ldr | 大範圍的位址加載指令 |
adr | 小範圍的位址加載指令 |
adrl | 中等範圍的位址加載指令 |
nop | 空操作 |
- AAAA:.word 0xAABBFF 類似于C語言的 int AAAA = 0xAABBFF;
- .balignl 16, 0xABCDEF 對齊+填充,b表示位填充,最後的l表示long,16表示16位元組對齊,0xABCDEF表示填充的原料。
- 0x00000008 : .balignl 16, 0xABCDEF,
- 0x0000000C: 0xABCDEF
- 0x00000010: 下一條指令
- ARM中有一個ldr指令,還有一個ldr僞指令。兩者的差別:
ldr r0, #0xFF @ldr指令 ldr r0, =0xFF @ldr僞指令 涉及到合法/非法立即數,還涉及到ARM文字池 adr 和 ldr的差别: - adr編譯時會被1條sub或add指令替代,而ldr編譯時會被一條mov指令替代或者文字池方式處理; - adr總是以PC為基準來表示位址,是以指令本身和運作位址有關,可以用來檢測程式目前的運作位址在哪裡 -ldr加載的位址和連結時給定的位址有關,由連結腳本決定。