ARM彙編基礎(Cortex-A7)

隨手把今天學的東西記錄一下吧,不然老是覺得空空的感覺什麼都記不住

爲什麼要學習彙編?
因爲Cortex-A芯片一上電的時候SP指針還沒有初始化,C語言環境還沒有準備好,所以不能運行C代碼,所以必須先用彙編語言設置好C環境,比如初始化DDR、設置SP指針等。所謂C語言環境就是能夠保證C語言能夠正常運行。C語言中的函數調用涉及到出棧和入棧,出棧入棧就是對棧頂進行操作,堆棧其實就是一段內存,這段內存比較特殊,由SP指針訪問,SP指針指向棧頂。芯片一上電SP指針還沒有初始化,所以C語言沒法運行。對於有些芯片需要初始化DDR,用戶代碼需要在DDR中運行,所以一開始要用匯編來初始化DDR控制器。

1. GNU彙編語法

GNU 彙編語法適用於所有的架構,並不是 ARM 獨享的

GNU彙編由一系列的語句組成,每條語句包括
label:instrution @comment
label:即標號,表示地址位置
instrution:指令,彙編指令或者僞代碼

用戶可以使用.section僞操作來定義一個段,彙編系統中預定義了一些段名:
.text 表示代碼段。
.data 初始化的數據段。
.bss 未初始化的數據段。
.rodata 只讀數據段。

彙編程序的默認入口標號是_start,不過我們也可以在鏈接腳本中使用ENTRY來指明其它的入口點,下面的代碼就是使用_start作爲入口標號:

.global _start

_start:
	ldr r0, =0x12 @r0=0x12

上面代碼中.global是僞操作,表示_start是一個全局標號,類似C語言裏面的全局變量一樣,常見的僞操作有:
.byte 定義單字節數據,比如.byte 0x12。
.short 定義雙字節數據,比如.short 0x1234。
.long 定義一個 4 字節數據,比如.long 0x12345678。
.equ 賦值語句,格式爲: .equ 變量名,表達式,比如.equ num, 0x12,表示
.align 數據字節對齊,比如: .align 4 表示 4 字節對齊。
.end 表示源文件結束。
.global 定義一個全局符號,格式爲: .global symbol,比如: .global _start

GNU彙編也支持函數,比如:
Undefined_Handler:
ldr r0, =Undefined_Handler
bx r0

“Undefined_Handler”就是函數名,“ldr r0, =Undefined_Handler”是函數體,“bx r0”是函數
返回語句,“bx”指令是返回指令,函數返回語句不是必須的。

2. Cortex-A7常用匯編指令

處理器內部數據傳輸指令

使用處理器做的最多事情就是在處理器內部來回的傳遞數據,常見的操作有:
a.將數據從一個寄存器傳遞到另一個寄存器
b.將數據從一個寄存器傳遞到特殊寄存器,如CPSR和SPSR寄存器
c.將立即數傳遞到寄存器

常用的數據傳輸指令有三個:MOV MRS MSR,三個指令用法如下:
在這裏插入圖片描述

存儲器訪問指令

常用的存儲器訪問指令有兩種:LDR和STR。
LDR指令
LDR R0, =0X0209C004 @將寄存器地址 0X0209C004 加載到 R0 中,即 R0=0X0209C004
LDR R1, [R0] @讀取地址 0X0209C004 中的數據到 R1 寄存器中

STR指令
LDR R0, =0X0209C004 @將寄存器地址 0X0209C004 加載到 R0 中,即 R0=0X0209C004
LDR R1, =0X20000002 @R1 保存要寫入到寄存器的值,即 R1=0X20000002
STR R1, [R0] @將 R1 中的值寫入到 R0 中所保存的地址中

壓棧和出棧指令

我們通常會在A函數中調用B函數,當B函數執行完以後再回到A函數繼續執行。要想在跳回A函數以後代碼能夠接着正常運行,那就必須在跳到B函數之前將當前處理器狀態保存起來(就是保存 R0~ R15 這些寄存器值),當B函數執行完成以後再用前面保存的寄存器值恢復R0~ R15 即可。保存 R0~ R15寄存器的操作就叫做現場保護,恢復R0~R15寄存器的操作就叫做恢復現場。在進行現場保護的時候需要進行壓棧入棧操作,恢復現場就要進行出棧操作。壓棧的指令爲PUSH,出棧的指令爲POP,PUSH和POP是一種多存儲和多加載指令,即可以一次操作多個寄存器數據,他們利用當前的棧指針SP來生成地址。
在這裏插入圖片描述
PUSH和POP的另一種寫法是STMFD SP!和LDMFD SP!
因此
PUSH {R0~ R3,R12} @將R0~R3和R12壓棧
PUSH {LR} @將 LR 進行壓棧
等價於
STMFD SP!,{R0~R3,R12}
STMFD SP!,{LR} @LR 入棧

POP {LR} @先恢復LR
POP {R0~ R3,R12} @在恢復 R0~R3,R12
等價於
LDMFD SP!,{LR}
LDMFD SP!,{R0~R3,R12}

STM 和 LDM 就是多存儲和多加載,可以連續的讀寫存儲器中的多個連續數據。FD 是 Full Descending 的縮寫,即滿遞減的意思。根據 ATPCS 規則,ARM 使用的 FD 類型的堆棧,SP指向最後一個入棧的數值,堆棧是由高地址向下增長的,也就是前面說的向下增長
的堆棧,因此最常用的指令就是 STMFD 和 LDMFD。 STM 和 LDM 的指令寄存器列表中編號小的對應低地址,編號高的對應高地址。

跳轉指令

有多種跳轉操作,比如:
直接使用跳轉指令,如B、BL、BX等
直接向PC寄存器裏面寫入數據

主要使用B、BL,區別就是B跳轉了回不來了BL跳轉由於將PC寄存器中的值保存到了LR寄存器中所以還能跳轉回來,這是子程序調用的一個常用手段,並且可以用來實現線程的保護和恢復,獲取中斷號等等。

算術運算指令

在這裏插入圖片描述

邏輯運算指令

在這裏插入圖片描述

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