嵌入式ARM架構學習3——啟動代碼

一 匯編補充:

	area reset, code, readonlycode32entry;mov r0, #4 ; r0 = 4;mov r1, r0 ; r1 = r0;mov r2, r1, lsl #1 ;r2 = r1 << 1 乘2;mov r3, r1, lsr #1 ;r3 = r1 >> 1 除2;mov r4, r1, ror #2;mov r0, #100 ;100是十進制 轉為16進制賦值給十進制;mov r1, #8;add r2, r0, #100;add r2, r0, r1;add r2, r0, #(100 << 2);;mov r0, #0xF0;mvn r0, r0;ldr r0, =0xfac0;把任意 32 位常數送進寄存器;指定位置置0;mov r0, #0xFFFFFFFF;mov r1, #1;bic r0, r0, #4 ;指定位 4:(0100)r0里4對應的1所在位置置0;bic r0, r0, r1, lsl #2 ;先把r1 左移2位 然后對應的1的位置對應于r0中 給置0;bic r0, r0, #(1 << 2);清理掉第2位;指定位置1;mov r0, #0x80000000;orr r0, r0, #(1<<31);mov r0, #0x0 ;1011;orr r0, r0, #(1 << 10);三個數之間找最大值;mov r0, #100;mov r1, #200;mov r2, #300;cmp r0, r1;movge r3, r0;movlt r3, r1;cmp r3, r2;movge r3, r3;movlt r3, r2;if分支;mov r0, #0x100;mov r1, #0x200;cmp r0, r1;bge greatr;blt less;greatr;mov r2, r0;b finish ;跳過另一個分支 跳轉到finish;less;mov r2, r1;finish;b finish;while 循環;mov r0, #0;mov r1, #0
;loop;cmp r0, #100;bge finish;add r1, r1, r0;add r0, r0, #1;b loop;finish;b finish  ;死循環;do_while循環;mov r0, #0;mov r1, #0
;loop;add r1, r1, r0;add r0, r0, #1;cmp r0, #100;bge finish;b loop
;finish;b finish  ;死循環;b main
;asm_maxTwoNum
;	mov r0, #100
;	mov r1, #200
;	cmp r0, r1
;	movge r3, r0
;	movlt r3, r1
;	mov pc, lr	 ;把返回地址賦給 PC → 立即跳回調用點繼續執行
;	bx lr ;bx 跳轉到調用點的下一行
;main
;	mov r0, #10;mov r1, #20
;	bl asm_maxTwoNum ;bl 跳轉之前保留當前地址
;	mov r2, #10
;	mov r3, #20;========= 子函數:返回 r0、r1 中的較大值 =========
asm_maxTwoNummov r0, #100 ;把參數寫成100、200(覆蓋main傳入的10/20)mov r1, #200cmp r0, r1stmfd sp!, {r0-r12, lr}  ; 先壓棧保護現場bl asm_fun0         ; 調用asm_fun0(無意義,返回后r0/r1仍保持100/200)ldmfd sp!, {r0-r12, lr}  ; 彈棧恢復現場movge r3, r0        ; 若 r0>=r1  大數→r3  (100<200,不執行)movlt r3, r1        ; 若 r0< r1  大數→r3  (執行,r3=200)mov r0, r3          ; 把結果200寫回r0作為返回值bx  lr              ; 返回;========= 另一個函數,僅演示跳轉 =========
asm_fun0mov   r0, #100mov   r1, #200bx    lr                ; 直接返回,無實質操作;========= 主函數:入口 =========
mainldr sp, =0x40001000   ; 設棧頂(裸機常用)mov r0, #10           ; 準備參數 1mov r1, #20           ; 準備參數 2stmfd sp!, {r0-r12, lr} ; 保存現場bl  asm_maxTwoNum     ; 調最大值函數ldmfd sp!, {r0-r12, lr} ; 恢復現場mov r2, #10           mov r3, #20ldr r0, =0x40000000 ;地址指針ldr r1, =0x12345678	;數據str r1,[r0],#4   ;*p = 0x12345678; p++ldr r2,[r0]	   	; r2 = *(p+1)(未初始化,值未知);ARM 是 32 位架構,一個“字(word)” = 4 字節。;地址按字節編號,因此索引寫 #4 才能指到下一個字。finishb finish            ; 死循環,程序結束end

匯編asm和c文件之間的傳參?

?preserve8

且魔術棒配置ROM地址區域

mainldr sp, =0x40001000   ; 設棧頂(裸機常用)import c_add;mov r0, #10           ; 準備參數 1;mov r1, #20           ; 準備參數 2stmfd sp!, {r0-r12, lr} ; 保存現場;bl  asm_maxTwoNum     ; 調最大值函數mov r0, #100           mov r1, #200bl c_add;r0默認接收函數返回值ldmfd sp!, {r0-r12, lr} ; 恢復現場;mov r2, #10           ;mov r3, #20ldr r0, =0x40000000 ;地址指針ldr r1, =0x12345678	;數據str r1,[r0],#4   ;*p = 0x12345678; p++ldr r2,[r0]	   	; r2 = *(p+1)(未初始化,值未知);ARM 是 32 位架構,一個“字(word)” = 4 字節。;地址按字節編號,因此索引寫 #4 才能指到下一個字。finishb finish            ; 死循環,程序結束extern c_add(int a, int b);int c_add(int a, int b)
{return a + b;
}

當傳參數大于4個——通過壓棧傳參

	b main
asm_maxTwoNummov r0, #100 ;把參數寫成100、200(覆蓋main傳入的10/20)mov r1, #200cmp r0, r1stmfd sp!, {r0-r12, lr}  ; 先壓棧保護現場bl asm_fun0         ; 調用asm_fun0(無意義,返回后r0/r1仍保持100/200)ldmfd sp!, {r0-r12, lr}  ; 彈棧恢復現場movge r3, r0        ; 若 r0>=r1  大數→r3  (100<200,不執行)movlt r3, r1        ; 若 r0< r1  大數→r3  (執行,r3=200)mov r0, r3          ; 把結果200寫回r0作為返回值bx  lr              ; 返回;========= 另一個函數,僅演示跳轉 =========
asm_fun0mov   r0, #100mov   r1, #200bx    lr                ; 直接返回,無實質操作;========= 主函數:入口 =========
mainldr sp, =0x40001000   ; 設棧頂(裸機常用)import c_addmov r0, #10           ; 準備參數 1mov r1, #20           ; 準備參數 2stmfd sp!, {r0-r12, lr} ; 保存現場;bl  asm_maxTwoNum     ; 調最大值函數mov r0, #10           mov r1, #20mov r2, #30           mov r3, #40mov r4, #50;	傳參大于4個需要通過壓棧進行傳參 stmfd sp!, {r4} ; 壓棧r4傳參         bl c_add;r0默認接收函數返回值ldmfd sp!, {r4} ; 彈棧ldmfd sp!, {r0-r12, lr} ; 恢復現場;mov r2, #10           ;mov r3, #20ldr r0, =0x40000000 ;地址指針ldr r1, =0x12345678	;數據str r1,[r0],#4   ;*p = 0x12345678; p++ldr r2,[r0]	   	; r2 = *(p+1)(未初始化,值未知);ARM 是 32 位架構,一個“字(word)” = 4 字節。;地址按字節編號,因此索引寫 #4 才能指到下一個字。finishb finish            ; 死循環,程序結束

C語言 調用匯編


extern int c_add(int a, int b, int c, int d, int e);extern  int asm_maxTwoNum(int a, int b);int c_add(int a, int b, int c, int d, int e)
{int ret;//ret = a + b + c + d + e;ret = asm_maxTwoNum(5, 10);return ret;
}b main
asm_fun0mov r0, #100mov r1, #200bx lrexport 	asm_maxTwoNum
asm_maxTwoNumcmp r0, r1movge r3, r0movlt r3, r1 mov r0, r3bx lr

啟動代碼:最小可運行的 ARM 裸機啟動/中斷向量表/軟中斷(SWI) 示例

上電后建立向量表 → 切到用戶模式并開 IRQ → 給 User 棧留空間 → 跳進 C 的 main();同時提供 asm_swi_fun() 讓 C 主動觸發 7 號軟中斷,異常處理完整保存/恢復現場并自動返回用戶模式

	preserve8area reset, code, readonlycode32entry;中斷向量表ldr pc, =start_hander       ; 0x00  復位ldr pc, =undefine_hander    ; 0x04  未定義指令ldr pc, =software_hander    ; 0x08  SWI(軟中斷)ldr pc, =prefetch_hander    ; 0x0C  預取指中止ldr pc, =data_hander        ; 0x10  數據中止nop                         ; 0x14  保留ldr pc, =irq_hander         ; 0x18  IRQldr pc, =fiq_hander         ; 0x1C  FIQundefine_handerb undefine_handerprefetch_handerb prefetch_handerdata_handerb data_handerirq_handerb irq_handerfiq_handerb fiq_handerimport software_vector;告訴匯編器 C 里實現該函數
software_handerstmfd sp!, {r0-r12, lr}   ; 保存用戶現場(lr = SWI 返回地址)bl software_vector        ; 調到 C 處理函數ldmfd sp!, {r0-r12, pc}^  ; 恢復寄存器 且 把保存的 lr 彈進 pc; ^ 表示 同時把 SPSR_svc → CPSR(自動返回用戶模式)export asm_swi_fun   ; 供c調用
asm_swi_funswi #7           ; 觸發 7 號軟中斷(編號任意)bx lr            ; 從 SWI 返回后再回到 Cstart_handerldr sp, =0x40001000   ; 設棧頂(裸機常用)import main			 ;引入c語言中的main函數;--- 下面 5 行 = 切到用戶模式并打開 IRQ ----------mrs r0, cpsr   ;r0 ← CPSRbic r0, r0, #(0x1F << 0) ;CPSR的M域是后五位 先清零(清模式位)bic r0, r0, #(1 << 7)	  ;清CPSR 的 I 位(允許 IRQ)orr r0, r0, #(0x10 << 0) ;設 M[4:0]=0b10000(User 模式)msr cpsr_c, r0		  ;**只把模式/中斷位寫回**;給 User 模式建棧ldr sp, =0x40001000sub sp, sp, #1024  ;; 留 1 KB 給 User 棧b main            ; 跳轉c語言的函數end

15、arm匯編調用c語言函數以及c語言函數調用匯編編寫的函數,函數參數和返回值如何處理?

核心原則:

參數和返回值主要通過 寄存器 傳遞,當寄存器不夠用時,使用

ARM匯編調用C語言函數 過程如下:

  1. 參數傳遞:

    • 前4個參數 (對于32位ARM): 如果參數是32位整型或指針類型,依次使用寄存器 R0, R1, R2, R3 來傳遞。

    • 第5個及以后的參數: 從第5個參數開始,將其壓入 (Stack) 中。調用者負責在調用前分配棧空間并壓入這些參數。

  2. 執行調用 :

    • 使用 BL (Branch with Link) 指令跳轉到C函數地址。BL 指令會將下一條指令的地址(返回地址)保存到鏈接寄存器 LR (R14) 中。

  3. 返回值獲取:

    • 32位及以下的返回值: C函數執行完畢后,返回值通過寄存器 R0 返回給匯編調用者。

C語言函數調用ARM匯編函數 過程如下:

  1. 編寫匯編函數:

    • 匯編函數需要將自己視為一個被C代碼調用的普通函數

    • 它可以從 R0-R3 中獲取前4個傳入的參數。

    • 如果需要更多的參數,它需要從棧上的特定位置去獲取。SP寄存器指向的棧頂之后的位置就是第5、6...個參數。

  2. 保存上下文 :

    • 匯編函數如果會修改一些被調用者保存寄存器 (Callee-saved registers),如 R4-R11, SP, LR,則必須在函數開頭將它們壓棧保存 (PUSH),并在函數結束返回前出棧恢復 (POP)

    • 對于調用者保存寄存器 (Caller-saved registers),如 R0-R3, R12,則可以自由使用,無需保存(因為調用者C代碼已經假定它們可能被破壞)。

  3. 返回值設置 (Setting the Return Value):

    • 在函數返回前,將需要返回的值放入 R0(或 R0R1)。

  4. 返回 (Returning):

    • 通常使用 BX LR 指令返回到調用者(C代碼)。這條指令會跳轉到 LR 寄存器中保存的返回地址。

16. ARM內核異常、類型及工作模式切換

核心概念:

異常是CPU對內部或外部緊急事件的一種響應機制。當異常發生時,ARM內核會暫停當前執行的程序,跳轉到預先設置好的異常向量表中的特定地址去執行對應的異常處理程序,同時CPU的工作模式會自動切換到對應的特權模式,以便操作系統內核有足夠的權限來處理異常。

ARM經典架構(如ARMv7-A)中的7種異常:

異常類型觸發條件使內核進入的工作模式優先級(通常)
1. 復位 (Reset)處理器上電或按下復位鍵Supervisor (SVC)最高 (1)
2. 未定義指令 (Undefined Instruction)CPU遇到無法識別的指令Undefined6
3. 軟件中斷 (SWI) / SVC程序執行 SVCSWI 指令Supervisor (SVC)6
4. 指令預取中止 (Prefetch Abort)預取指令時發生內存訪問錯誤Abort5
5. 數據中止 (Data Abort)讀寫數據時發生內存訪問錯誤Abort2
6. 中斷請求 (IRQ)外部設備發出普通中斷請求IRQ4
7. 快速中斷請求 (FIQ)外部設備發出高優先級中斷請求FIQ3

工作模式詳解:

異常會導致內核從User等非特權模式切換到下表中的特權模式:

工作模式簡稱用途
用戶模式User正常程序執行(非異常模式)
快速中斷模式FIQ處理高速數據傳輸、DMA等 (異常模式)
中斷模式IRQ處理普通中斷 (異常模式)
管理模式SVC操作系統內核、軟件中斷、復位 (異常模式)
中止模式Abort處理內存訪問失敗 (異常模式)
未定義模式Undefined處理未定義指令異常 (異常模式)
系統模式System運行特權級操作系統任務 (ARMv4及以上,非異常模式)

重點說明:

  • 復位 (Reset) 是最高優先級異常,它讓系統從一個已知的初始狀態開始運行,直接進入SVC模式。

  • 軟件中斷 (SVC)用戶程序主動切換到內核態(SVC模式)的方式,用于請求系統服務,例如打開文件、創建線程等(類似Linux中的系統調用)。

  • IRQ和FIQ異步異常,由外部硬件觸發。FIQ的向量地址在向量表末尾,允許處理程序直接開始執行而無需跳轉,并且有更多的專用寄存器,從而可以實現更快的處理速度。

  • 中止異常 通常與內存管理單元 (MMU) 相關,用于實現虛擬內存內存保護。預取中止發生在取指階段,數據中止發生在數據訪問階段。

  • 每種異常模式都有自己獨立的棧指針 (SP)鏈接寄存器 (LR) 副本,這避免了在處理異常時破壞用戶模式下的寄存器狀態,確保了異常處理的安全和可靠。

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

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

相關文章

PNPM庫離線安裝方案

以下是幾種可行的方案&#xff0c;推薦優先使用方案一。 方案一&#xff1a;使用離線鏡像&#xff08;Offline Mirror&#xff09; - 最優雅、最PNPM的方式 這是 PNPM 官方推薦的處理離線環境的方式。它會在內網電腦上創建一個所有依賴包的壓縮文件&#xff08;tarball&#x…

[Wit]CnOCR模型訓練全流程簡化記錄(包括排除BUG)

stepfile:step 00 創建數據集 目錄結構 yourproject -data --myset ---images #存放訓練圖片 ---dev.tsv #測試標簽 tsv格式 圖片文件名\t內容 ---train.tsv #訓練標簽 tsv格式 圖片文件名\t內容 -train_config.json -train_config_gpu.json -fix_cnocr_encoding.py step 01 創…

Sklearn(機器學習)實戰:鳶尾花數據集處理技巧

1.數據集的使用&#xff1a;先使用load導入鳶尾花數據&#xff1a;from sklearn.datasets import load_iris然后定義一個函數來查看鳶尾花數據集&#xff1a;數據集的獲取&#xff1a;iris load_iris()print(鳶尾花的數據集&#xff1a;\n,iris)使用iris[DESCR]來查看數據及里…

【企業微信】接口報錯:javax.net.ssl.SSLHandshakeException

詳細報錯信息 javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target原因 關于qyapi…

光子芯片驅動的胰腺癌早期檢測:基于光學子空間神經網絡的高效分割方法

光子芯片驅動的胰腺癌早期檢測:基于光學子空間神經網絡的高效分割方法 1 論文核心概念 本文提出了一種基于集成光子芯片的光學子空間神經網絡(Optical Subspace Neural Network, OSNN),用于胰腺癌的早期檢測與圖像分割。其核心思想是利用光子芯片的高并行性、低延遲和低能…

Scikit-learn Python機器學習 - 特征降維 壓縮數據 - 特征提取 - 主成分分析 (PCA)

鋒哥原創的Scikit-learn Python機器學習視頻教程&#xff1a; 2026版 Scikit-learn Python機器學習 視頻教程(無廢話版) 玩命更新中~_嗶哩嗶哩_bilibili 課程介紹 本課程主要講解基于Scikit-learn的Python機器學習知識&#xff0c;包括機器學習概述&#xff0c;特征工程(數據…

【Python】pytorch安裝(使用conda)

# 創建 PyTorch 虛擬環境 conda create -n pytorch_env python3.10# 激活環境 conda activate pytorch_env# 安裝 PyTorch&#xff08;CPU版本&#xff09; conda install pytorch torchvision torchaudio cpuonly -c pytorch# 或者安裝 GPU 版本&#xff08;如果有NVIDIA顯卡&…

ThreeJS骨骼示例

<html lang"zh-CN"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>骨骼動畫混合演示</title><style>body {margin: 0;padding: …

python + Flask模塊學習 1 基礎用法

目錄 Flask 的主要作用 常用擴展 Flask 基本用法 1. 安裝 Flask&#xff08;再安裝個postman用來調試測試API哈 2. 最小化應用示例 3. 運行應用 Flask 是一個輕量級的 Python Web 框架&#xff0c;它簡潔靈活&#xff0c;適合快速開發 Web 應用和 API。它被稱為 "微…

python數據可視化之Matplotlib(8)-Matplotlib樣式系統深度解析:從入門到企業級應用

作者&#xff1a;浪浪山齊天大圣 描述&#xff1a;深入探索Matplotlib樣式系統的核心機制&#xff0c;掌握從基礎樣式到企業級樣式管理的完整解決方案引言 在數據可視化的世界里&#xff0c;一個優秀的圖表不僅要準確傳達數據信息&#xff0c;更要具備專業的視覺效果。Matplotl…

3.HTTP/HTTPS:報文格式、方法、狀態碼、緩存、SSLTLS握手

HTTP/HTTPS&#xff1a;報文格式、方法、狀態碼、緩存、SSL/TLS握手 1. HTTP報文格式 1.1 HTTP請求報文(Request) GET /api/v1/users HTTP/1.1 // 請求行&#xff1a;方法、URI、協議版本 Host: api.example.com // 請求頭 (Headers) User-Agent: Mozil…

【慢教程】Ollama4:ollama命令匯總

??教程說明 Ollama 是一款輕量級本地大模型部署工具&#xff0c;使用廣泛&#xff0c;且容易上手&#xff0c;適合作為AI技術的入門。 &#x1f9e9;教程各部分鏈接&#xff1a; 第一課&#xff1a;ollama運行原理介紹及同類工具對比 ollama運行原理介紹及同類工具對比&am…

JAVA Predicate

簡單來說&#xff0c;當我明確知道此次判斷的邏輯時就可以直接使用if&#xff0c;但是我這次的判斷邏輯可能會隨著某個參數變化的時候使用Predicate比如當我想要判斷某長段文字中是否包含list<String> 中的元素&#xff0c;并且包含的元素個數大于 list<String>最后…

什么是PFC控制器

一句話概括PFC控制器是一種智能芯片&#xff0c;它通過控制電路中的電流波形&#xff0c;使其與電壓波形保持一致&#xff0c;從而減少電力浪費&#xff0c;提高電能的利用效率。PFC控制器IC的核心作用就是控制一顆功率MOSFET的開關&#xff0c;通過特定的電路拓撲&#xff08;…

【P03_AI大模型測試之_定制化 AI 應用程序開發】

git clone https://gitee.com/winner21/aigc-test.git 類似于joycoder的&#xff0c;可以安裝在vscode上的通義靈碼&#xff1a;https://lingma.aliyun.com/ 1、VSCODE上配置通義靈碼 2、創建前后端文件&#xff0c;并引用AI編碼代碼 3、指定文件&#xff0c;利用AI進行代碼優…

人工智能機器學習——決策樹、異常檢測、主成分分析(PCA)

一、決策樹(Decision Tree) 決策樹&#xff1a;一種對實例進行分類的樹形結構&#xff0c;通過多層判斷區分目標所屬類別 本質&#xff1a;通過多層判斷&#xff0c;從訓練數據集中歸納出一組分類規則 優點&#xff1a; 計算量小&#xff0c;運算速度快易于理解&#xff0c;可…

服務器文件同步用哪個工具?介紹一種安全高效的文件同步方案

服務器作為企業核心數據和應用的載體&#xff0c;服務器文件同步已成為IT運維、數據備份、業務協同中不可或缺的一環。然而&#xff0c;面對多樣的場景和嚴苛的需求&#xff0c;選擇一個既高效又安全的服務器文件同步工具并非易事。本文將首先探討服務器文件同步的常見場景、需…

LeetCode 004. 尋找兩個正序數組的中位數 - 二分切分與分治詳解

一、文章標題 LeetCode 004. 尋找兩個正序數組的中位數 - 二分切分與分治詳解 二、文章內容 1. 題目概述 題目描述&#xff1a;給定兩個已按非降序排列的整數數組 nums1、nums2&#xff0c;設它們長度分別為 m 和 n&#xff0c;要求返回這兩個數組合并后有序序列的中位數。…

預閃為什么可以用來防紅眼?

打閃拍照紅眼產生的原因 預閃可以用來防紅眼&#xff0c;是基于人眼的生理特性和紅眼現象的產生原理。在光線較暗時&#xff0c;人眼的瞳孔會放大。當使用閃光燈拍攝時&#xff0c;如果直接進行高強度閃光&#xff0c;由于瞳孔來不及縮小&#xff0c;閃光燈的光線會反射在眼球血…

Python程序使用了Ffmpeg,結束程序后,文件夾中仍然生成音頻、視頻文件

FFmpeg是一套可以用來記錄、轉換數字音頻、視頻&#xff0c;并能將其轉化為流的開源計算機程序。采用LGPL或GPL許可證。它提供了錄制、轉換以及流化音視頻的完整解決方案。它包含了非常先進的音頻/視頻編解碼庫libavcodec&#xff0c;為了保證高可移植性和編解碼質量&#xff0…