ARM 匯編基礎

? ?????我們在學習 STM32 的時候幾乎沒有用到過匯編,可能在學習 UCOS FreeRTOS RTOS
類操作系統移植的時候可能會接觸到一點匯編。但是我們在進行嵌入式 Linux 開發的時候是絕
對要掌握基本的 ARM 匯編,因為 Cortex-A 芯片一上電 SP 指針還沒初始化, C 環境還沒準備
好,所以肯定不能運行 C 代碼,必須先用匯編語言設置好 C 環境,比如初始化 DDR 、設置 SP
指針等等,當匯編把 C 環境設置好了以后才可以運行 C 代碼。所以 Cortex-A 一開始肯定是匯
編代碼,其實 STM32 也一樣的,一開始也是匯編,以 STM32F103 為例,啟動文件
startup_stm32f10x_hd.s 就是匯編文件,只是這個文件 ST 已經寫好了,我們根本不用去修改,所
以大部分學習者都沒有深入的去研究。匯編的知識很龐大,本章我們只講解最常用的一些指令,
滿足我們后續學習即可。

一.GNU 匯編語法

如果大家使用過 STM32 的話就會知道 MDK IAR 下的啟動文件 startup_stm32f10x_hd.s
其中的匯編語法是有所不同的,將 MDK 下的匯編文件直接復制到 IAR 下去編譯就會出錯,因
MDK IAR 的編譯器不同,因此對于匯編的語法就有一些小區別。我們要編寫的是 ARM
匯編,編譯使用的 GCC 交叉編譯器,所以我們的匯編代碼要符合 GNU 語法。
GNU 匯編語法適用于所有的架構,并不是 ARM 獨享的, GNU 匯編由一系列的語句組成,
每行一條語句,每條語句有三個可選部分,如下:
label instruction @ comment
label 即標號,表示地址位置,有些指令前面可能會有標號,這樣就可以通過這個標號得到
指令的地址,標號也可以用來表示數據地址。注意 label 后面的“:”,任何以“:”結尾的標識
符都會被識別為一個標號。
instruction 即指令,也就是匯編指令或偽指令。
@ 符號,表示后面的是注釋,就跟 C 語言里面的“ /* ”和“ */ ”一樣,其實在 GNU 匯編文
件中我們也可以使用“ /* ”和“ */ ”來注釋。
comment 就是注釋內容。
比如如下代碼:
add:
MOVS R0, #0X12 @ 設置 R0=0X12
上面代碼中“ add: ”就是標號,“ MOVS R0,#0X12 ”就是指令,最后的“ @ 設置 R0=0X12 ”就是
注釋。
.data 初始化的數據段。
.bss 未初始化的數據段。
.rodata 只讀數據段。
我們當然可以自己使用 .section 來定義一個段,每個段以段名開始,以下一段名或者文件結
尾結束,比如:
.section .testsection @ 定義一個 testsetcion
匯編程序的默認入口標號是 _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 ,表示 num=0x12
.align 數據字節對齊,比如: .align 4 表示 4 字節對齊。
.end
表示源文件結束。
.global 定義一個全局符號,格式為: .global symbol ,比如: .global _start
GNU 匯編還有其它的偽操作,但是最常見的就是上面這些,如果想詳細的了解全部的偽操
作,可以參考《 ARM Cortex-A(armV7) 編程手冊 V4.0.pdf 》的 57 頁。
GNU 匯編同樣也支持函數,函數格式如下:
函數名 :
函數體
返回語句
GNU 匯編函數返回語句不是必須的,如下代碼就是用匯編寫的 Cortex-A7 中斷服務函數:
示例代碼 7.1.1.1 匯編函數定義
/* 未定義中斷 */
Undefined_Handler :
ldr r0 , = Undefined_Handler
bx r0
/* SVC 中斷 */
SVC_Handler :
ldr r0 , = SVC_Handler
bx r0
/* 預取終止中斷 */
PrefAbort_Handler :
ldr r0 , = PrefAbort_Handler
bx r0
上述代碼中定義了三個匯編函數: Undefined_Handler SVC_Handler
PrefAbort_Handler 。以函數 Undefined_Handler 為例我們來看一下匯編函數組成,
Undefined_Handler ”就是函數名,“ ldr r0, =Undefined_Handler ”是函數體,“ bx r0 ”是函數
返回語句,“ bx ”指令是返回指令,函數返回語句不是必須的。

二.處理器內部數據傳輸指令

三個指令:
1 MOV 指令
MOV 指令用于將數據從一個寄存器拷貝到另外一個寄存器,或者將一個立即數傳遞到寄
存器里面,使用示例如下:
MOV R0 R1
@ 將寄存器 R1 中的數據傳遞給 R0 ,即 R0=R1
MOV R0, #0X12
@ 將立即數 0X12 傳遞給 R0 寄存器,即 R0=0X12
2 MRS 指令
MRS 指令用于將特殊寄存器 ( CPSR SPSR) 中的數據傳遞給通用寄存器,要讀取特殊
寄存器的數據只能使用 MRS 指令!使用示例如下:
MRS R0, CPSR
@ 將特殊寄存器 CPSR 里面的數據傳遞給 R0 ,即 R0=CPSR
3 MSR 指令
MSR 指令和 MRS 剛好相反, MSR 指令用來將普通寄存器的數據傳遞給特殊寄存器,也就
是寫特殊寄存器,寫特殊寄存器只能使用 MSR ,使用示例如下:
MSR CPSR, R0
@ R0 中的數據復制到 CPSR 中,即 CPSR=R0

三.存儲器訪問指令

1 LDR 指令
LDR 主要用于從存儲加載數據到寄存器 Rx 中, LDR 也可以將一個立即數加載到寄存器 Rx
中, LDR 加載立即數的時候要使用“ = ”,而不是“ # ”。在嵌入式開發中, LDR 最常用的就是讀
CPU 的寄存器值,比如 I.MX6UL 有個寄存器 GPIO1_GDIR ,其地址為 0X0209C004 ,我們
現在要讀取這個寄存器中的數據,示例代碼如下:
示例代碼 7.2.2.1 LDR 指令使用
1 LDR R0 , = 0X0209C004 @ 將寄存器地址 0X0209C004 加載到 R0 中,即 R0 = 0X0209C004
2 LDR R1 , [ R0 ] @ 讀取地址 0X0209C004 中的數據到 R1 寄存器中
上述代碼就是讀取寄存器 GPIO1_GDIR 中的值,讀取到的寄存器值保存在 R1 寄存器中,
上面代碼中 offset 0 ,也就是沒有用到 offset
2 STR 指令
LDR 是從存儲器讀取數據, STR 就是將數據寫入到存儲器中,同樣以 I.MX6UL 寄存器
GPIO1_GDIR 為例,現在我們要配置寄存器 GPIO1_GDIR 的值為 0X20000002 ,示例代碼如下:
示例代碼 7.2.2.2 STR 指令使用
1 LDR R0 , = 0X0209C004 @ 將寄存器地址 0X0209C004 加載到 R0 中,即 R0 = 0X0209C004
2 LDR R1 , = 0X20000002 @R1 保存要寫入到寄存器的值,即 R1 = 0X20000002
3 STR R1 , [ R0 ] @ R1 中的值寫入到 R0 中所保存的地址中
LDR STR 都是按照字進行讀取和寫入的,也就是操作的 32 位數據,如果要按照字節、
半字進行操作的話可以在指令“ LDR ”后面加上 B H ,比如按字節操作的指令就是 LDRB
STRB ,按半字操作的指令就是 LDRH STRH

四.?壓棧和出棧指令

????????通常會在 A 函數中調用 B 函數,當 B 函數執行完以后再回到 A 函數繼續執行。要想
再跳回 A 函數以后代碼能夠接著正常運行,那就必須在跳到 B 函數之前將當前處理器狀態保存
起來 ( 就是保存 R0~R15 這些寄存器值 ) ,當 B 函數執行完成以后再用前面保存的寄存器值恢復
R0~R15 即可。保存 R0~R15 寄存器的操作就叫做現場保護,恢復 R0~R15 寄存器的操作就叫做
恢復現場。在進行現場保護的時候需要進行壓棧 ( 入棧 ) 操作,恢復現場就要進行出棧操作。壓棧
的指令為 PUSH ,出棧的指令為 POP PUSH POP 是一種多存儲和多加載指令,即可以一次
操作多個寄存器數據

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/163389.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/163389.shtml
英文地址,請注明出處:http://en.pswp.cn/news/163389.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

關于前端上傳

類似于 上面的傳參form-data形式,第一個參數為上傳的文件,第二個參數為json格式

一篇搞定Java注解

參考:https://blog.csdn.net/yeahPeng11/article/details/120394276 https://blog.csdn.net/yeahPeng11/article/details/120330630 https://www.cnblogs.com/CF1314/p/16580232.html 通過現有注解,明白注解是什么東東。 在 SpringBoot中,我…

G320E是一種低榮聲、固定頻率的電荷泵型DC/DC轉換器

G320E 低噪聲電荷泵DC/DC轉換器 產品概述: G320E是一種低榮聲、固定頻率的電荷泵型DC/DC轉換器,在輸入電壓范圍在2.7V到5.0V的情況下,該器件可以產生5V的輸出電壓,最大輸出電流達到300mA.G320E外部元件少,非常適合于…

IP定位揭秘:如何揪出SEM、百度競價惡意點擊

在當今的數字營銷領域,搜索引擎營銷(SEM)和百度競價成為了企業推廣的重要手段。然而,隨著這些渠道的普及,惡意點擊現象也日益嚴重。惡意點擊主要來自競爭對手,或是競價服務的提供商,他們通過點擊…

亞信安慧AntDB MTK數據同步工具之數據稽核

數據稽核是一種用于確保表數據準確性和一致性的重要方法,它涉及到檢查數據的完整性、一致性、有效性和合法性,以及與預期規范的匹配程度等多個方面。隨著大數據時代的到來,通過有效的數據稽核,組織可以提高決策的準確性和效率&…

淺談安科瑞直流電表在荷蘭光伏充電樁系統中的應用

摘要:本文介紹了安科瑞直流電表在荷蘭光伏充電樁系統中的應用。主要用于充電樁的電流電壓電能的計量。 Abstract: This article introduces the application of Acrel DC meters in PV charging pile system in Netherlands.The device is measuring current,volt…

Modbus-RTU協議講解與實戰

1、背景 工作需要,需要使用Modbus-RTU實現RS485通信,于是簡單學習并實踐了一下。 2、參考資料 一文看懂Modbus協議 3、協議說明 3.1、協議類型 當前設備采用Modbus-RTU協議,采用CRC-16_Modbus校驗算法,數據鏈路層使用用標準串口協議,物理層采用RS485進行數據傳輸。 …

python變量、常量、數據類型

一、變量 變量是存儲在內存中的值,這就意味著在創建變量時會在內存中開辟一個空間。 基于變量的數據類型,解釋器會分配指定內存,并決定什么數據可以被存儲在內存中。 因此,變量可以指定不同的數據類型,這些變量可以…

開源Flutter on Desktop項目-極擴安卓開發者工具

極擴-安卓開發者工具 他能干嘛 這個Flutter on Desktop桌面項目可以輔助你開發APP,支持分析一些運行數據以及操作APK安裝等功能,甚至我還加入了Window安卓子系統的功能。 在它的幫助下,你可以快速查看當前正在運行的Activity,給你…

ubuntu/windows/mac小問題記錄

ubuntu刪除snap,釋放dev/mapper/ubuntu–vg-ubuntu–lv使用率100%問題。 當無法用常規方式卸載snapd。粗暴: 刪除 Snap 的目錄 rm -rf ~/snap sudo rm -rf /snap sudo rm -rf /var/snap sudo rm -rf /var/lib/snapd sudo rm -rf /var/cache/snapd刪除 S…

Oracle時間排序字段

要用 TIMESTAMP(6) 不要用 date 因為 date只到秒 ,排序不準確

開發外賣霸王餐返利小程序的步驟有哪些?

外賣霸王餐返利小程序是一種基于社交電商模式的小程序,主要實現用戶和商家的共贏。 開發外賣霸王餐返利小程序的方案可以包括以下幾個步驟: 1、需求分析 明確外賣霸王餐返利小程序的功能和特點。確定用戶可以參與的活動類型、返利規則、用戶界面設計等…

Jmeter 分布式壓測

為什么要分布式 jmeter是100%純java開發的程序,虛擬用戶是以線程實現的,在大量并發情況下,很容易出現CPU、內存消耗過大的問題,甚至會出現java內存溢出。一般一臺電腦設置500-600線程數即可,如果超過1000線程&#xf…

vue - - - - - vue-qr插件生成二維碼

vue-qr插件生成二維碼 1. 安裝插件2. 組件使用示例圖&#xff1a;掃碼結果 1. 安裝插件 【vue-qr 官網地址】 npm install vue-qr --save // or yarn add vue-qr --save2. 組件使用 <template><vue-qr :logo-src"logoSrc":size"237":margin&qu…

php一句話木馬免殺

php一句話木馬免殺 針對于php一句話木馬做免殺&#xff1a; 利用php動態函數的特性&#xff0c;將危險函數拆分成字符&#xff0c;最終使用字符串拼接的方式&#xff0c;然后重新拼接&#xff0c;后加括號執行代碼&#xff0c;并且可以使用花指令進行包裝&#xff0c;如無限i…

Pol8891 規格書 ——圖像處理芯片/RGB轉MIPI支持圖像 90°/270°旋轉處理

一、芯片簡介 1、系統 高性能 MIPS 32bit CPU 內核&#xff1b; 高性能 DSP 內核圖像處理單元&#xff1b; 8KB 指令 Cache&#xff1b; 8KB 數據 Cache&#xff1b; 64KB OnChip SRAM&#xff1b; 內嵌 DDR3 控制器&#xff1b; 2、RGB 輸入 支持 RGB666、RGB888 輸入…

中電金信:《保險業監管研究及數字化轉型方向探索白皮書》

縱觀近二十年保險業從信息化向數字化的演進過程&#xff0c;我們感受到了數字化轉型階段性成果漸成的喜悅&#xff0c;同時也深深的體會到數字化轉型在“痛并快樂著”的歷程中的種種艱辛。當今世界正處于百年未有之大變局&#xff0c;隨著我國保險市場的供需格局演變和外部環境…

【Unity】EventSystem.current.IsPointerOverGameObject()對碰撞體起作用

本來我是用 EventSystem.current.IsPointerOverGameObject()來檢測是否點擊在UI上的&#xff0c;但是發現&#xff0c;他對我的碰撞體也是返回ture,研究半天。。。。找不出問題&#xff0c;然后發現我的相機上掛載了PhysicsRaycaster&#xff0c;去掉之后就好了&#xff0c;至于…

Mapbox中點圖層和面圖層點擊事件重疊,禁止點擊穿透方案

使用mapbox的小伙伴們可能都遇到過這個問題,就是當地圖上有兩個圖層,一個面圖層一個點圖層,二者相重合的時候。假設我們想點擊點位彈窗展示一些內容,也想點擊面圖層的時候彈窗展示一些內容,這時候一個有意思的問題就產生了,就是點擊點位彈窗的時候面圖層對應的彈窗也會彈…

計算二叉樹雙分支節點的個數(可運行)

如果對您有用&#xff0c;點個贊&#xff0c;關注一下哦&#xff01;畢竟像我這種不用付monyY的博主不多了&#xff0c;且行且珍惜吧&#xff01;俺只想要數據【偷笑】 運行環境.cpp 如果沒有輸出結果一定是建樹錯誤&#xff01;&#xff01;&#xff01;&#xff01;&#x…