天天看點

【嵌入式開發】ARM 處理器工作模式 及 修改方法 ( 處理器模式 | 設定處理器模式 | 程式狀态字寄存器 CPSR SPSR | 模式設定代碼編寫 | 設定 svc 模式 )

  • ​​一. 處理器工作模式相關介紹​​
  • ​​1. 處理器模式簡介​​
  • ​​(1) 處理器工作模式分類​​
  • ​​(2) 處理器不同工作模式差別​​
  • ​​(3) Linux 系統運作的模式​​
  • ​​(4) 特權模式 說明​​
  • ​​(5) 異常模式​​
  • ​​(6) 系統模式​​
  • ​​2. 處理器模式 改變​​
  • ​​(1) 處理器工作模式 改變 的前提條件​​
  • ​​(2) 處理器工作模式 修改方式 ( 程式狀态字寄存器 工作模式修改 )​​
  • ​​(3) 程式狀态字寄存器 位 類型​​
  • ​​(4) 程式狀态字寄存器修改流程​​
  • ​​二. 處理器工作模式修改 代碼示例​​
  • ​​1. 彙編代碼編寫​​
  • ​​(1) 代碼 邏輯 分析​​
  • ​​(2) 彙編代碼示例​​
  • ​​2. 連結器腳本​​
  • ​​3. Makefile 編譯腳本​​
  • ​​4. 編譯輸出可執行檔案​​

​本部落格的參考文章及相關資料下載下傳 : 

一. 處理器工作模式相關介紹

​參考手冊 :​ ​​A2.2 Processor modes​​

  • ​1.處理器工作模式位置 :​ ​​ARM Architecture Reference Manual [ A 2.2 ] 章節​​;
  • ​2.參考手冊下載下傳位址 : ​​

1. 處理器模式簡介

(1) 處理器工作模式分類

​處理器的 七種 工作模式 :​

  • ​1.User ( 使用者模式 usr ) :​ ​​普通的應用運作的模式​​ ;
  • ​2.FIQ ( 快速中斷模式 fiq ) :​ ​​該模式下支援資料的高速傳輸​​ ;
  • ​3.IRQ ( 普通中斷模式 irq ) :​ ​​該模式常用于處理普通的中斷​​ ;
  • ​4.Supervisor ( 管理模式 svc ) :​ ​​作業系統使用的一種保護模式​​ , ​本節 BootLoader 就是需要設定這種 svc 模式​;
  • ​5.Abort ( 終止模式 abt ) :​ ​​實作虛拟記憶體 和 存儲器保護​​ ;
  • ​6.Undefined ( 未定義模式 und ) :​ ​​硬體協處理器 的 軟體仿真支援​​, 當執行的指令​​處理器不支援​​, 那麼會進入該模式;
  • ​7.System ( 系統模式 ) :​ ​​該模式用于運作具有特權的作業系統任務​​, ARMv4 以上的架構才有;

(2) 處理器不同工作模式差別

​處理器 工作模式 差別 :​

  • ​1.可運作的指令不同 :​ 不同的處理器工作模式下 可 ​​運作的 處理器指令​​ 是不同的;
  • ​2.可通路的寄存器不同 :​ 不同處理器模式下 ​​可通路的 寄存器​​ 也是有差別的;
    【嵌入式開發】ARM 處理器工作模式 及 修改方法 ( 處理器模式 | 設定處理器模式 | 程式狀态字寄存器 CPSR SPSR | 模式設定代碼編寫 | 設定 svc 模式 )
  • ​3.分級别處理​ : 7 種工作模式級别不同, 作業系統 一般在級别較高的模式下運作, 應用程式在級别較低的模式下運作;
  • ​4.使用者模式說明 :​
    • ​( 1 ) 應用運作 :​ 絕大多數 ​​應用程式都運作在使用者模式 ( User ) 下​​;
    • ​( 2 ) 資源限制 :​ 在 ​​① 使用者模式下, 應用無法通路受保護的系統資源​​ , ​​② 系統資源的使用 是在作業系統的控制下​​;
    • ​( 3 ) 無法修改模式 :​ 在 ​​使用者模式 下, 應用也無法修改 處理器 的工作模式​​ ;

(3) Linux 系統運作的模式

​Linux 作業系統運作模式 :​

  • ​1.應用程式 :​ Linux 系統的​​應用程式運作在 User 使用者模式下​​;
  • ​2.核心 :​ Linux 系統 ​​核心 運作在 Supervisor 管理模式下​​ ;

(4) 特權模式 說明

​特權模式 :​

  • ​1.特權概念 :​ ​​除 使用者模式 外, 其它的 6 種模式 都是特權模式​​ ;
  • ​2.特權模式 的 功能 :​ 特權模式 比 使用者模式 擁有更大的權限, 可 ​​① 通路系統資源​​, ​​② 修改處理器工作模式​​ ;
    • ​( 1 ) 資源通路 :​ 特權模式 ​​擁有通路系統資源的權限​​ ;
    • ​( 2 ) 模式修改 :​ 特權模式 下 可以 ​​修改 處理器的工作模式​​ ;
  • ​3.五種異常模式 :​ 在 6 種 特權模式中, 有 5 種 是 ​​異常模式 , 當對應的異常發生的時候, 就會進入對應的工作模式​​ ;
  • ​4.異常模式寄存器​ : 每種異常模式都有一些​​附加的寄存器​​, 當異常發生的時候, ​​避免影響使用者模式的狀态​​;

(5) 異常模式

​五種 處理器工作模式 ( 異常模式 ) 對應的異常類型 :​

  • ​1.FIQ ( 快速中斷模式 fiq ) :​ ​​該模式下支援資料的高速傳輸​​ , ​​對應異常類型 為 快速中斷 異常​​;
  • ​2.IRQ ( 普通中斷模式 irq ) :​ ​​該模式常用于處理普通的中斷​​ , ​​對應異常類型 為 普通中斷 異常​​ ;
  • ​3.Supervisor ( 管理模式 svc ) :​ ​​作業系統使用的一種保護模式​​ , ​本節 BootLoader 就是需要設定這種 svc 模式​, ​​對應異常類型 為 Reset 和 軟中斷 異常​​ ;
  • ​4.Abort ( 終止模式 abt ) :​ ​​實作虛拟記憶體 和 存儲器保護​​ , ​​對應異常類型 為 預取指令失敗 和 讀取資料失敗 異常​​ ;
  • ​5.Undefined ( 未定義模式 und ) :​ ​​硬體協處理器 的 軟體仿真支援​​, 當執行的指令​​處理器不支援​​, 那麼會進入該模式, ​​對應異常類型 為 無法識别指令 異常​​;
【嵌入式開發】ARM 處理器工作模式 及 修改方法 ( 處理器模式 | 設定處理器模式 | 程式狀态字寄存器 CPSR SPSR | 模式設定代碼編寫 | 設定 svc 模式 )

​七種 異常類型 對應的 處理器工作模式 :​ ARM 架構 支援 七種類型的異常,

  • ​1.Reset​ : 處理器在工作時, 突然 ​​按下重新開機鍵, 就會觸發該異常​​ , ​​該異常對應的處理器工作模式為 svc 模式​​;
  • ​2.Undefined instructions​ : 處理器​​無法識别指令的異常​​, 處理器執行的指令是有規範的, 如果 嘗試執行 不符合要求的指令, 就會進入到該異常指令對應的位址中, ​​該異常對應的處理器工作模式為 und 模式​​;
  • ​3.Software interrupt (SWI)​ : ​​軟中斷​​, 軟體中需要去打斷處理器工作, 可以使用軟中斷來執行 , ​​該異常對應的處理器工作模式為 svc 模式​​;
  • ​4.Prefetch Abort (instruction fetch memory abort)​ : ​​預取指令失敗​​, ARM 在執行指令的過程中, 要先去預取指令準備執行, 如果預取指令失敗, 就會産生該異常, ​​該異常對應的處理器工作模式為 abt 模式​​;
  • ​5.Data Abort (data access memory abort)​ : ​​讀取資料失敗​​, ​​該異常對應的處理器工作模式為 abt 模式​​;
  • ​6.IRQ (interrupt)​ : ​​普通中斷​​ , ​​該異常對應的處理器工作模式為 irq 模式​​;
  • ​7.FIQ (fast interrupt)​ : ​​快速中斷​​, 快速中斷要比普通中斷響應速度要快一些, ​​該異常對應的處理器工作模式為 fiq 模式​​;

(6) 系統模式

​系統模式 :​

  • ​1.進入方式 :​ ​​任何異常都無法進入​​ 系統 模式 ;
  • ​2.寄存器 :​ 從下面的寄存器截圖可以看出, ​​系統模式 可 使用的 寄存器​​, ​​與 使用者模式 可通路的寄存器 是一樣的​​;
    【嵌入式開發】ARM 處理器工作模式 及 修改方法 ( 處理器模式 | 設定處理器模式 | 程式狀态字寄存器 CPSR SPSR | 模式設定代碼編寫 | 設定 svc 模式 )
  • ​3.擁有特權 :​ 系統模式也是一種特權模式, ​​不受使用者模式限制影響​​,
  • ​4.模式存在的目的 :​ 系統模式 主要 ​​服務于 需要通路系統資源的 作業系統任務​​, ​​避免使用 與 異常相關的附加寄存器​​;
    • ​​( 1 ) 避免被異常幹擾 :​​ 主要是為了 ​​保證 任務狀态, 避免 被 發生的異常 幹擾​​ ;

2. 處理器模式 改變

(1) 處理器工作模式 改變 的前提條件

​修改 處理器 工作模式 的 前提條件 :​

  • ​1.軟體控制 :​ 在 ​​軟體控制下, 可以修改處理器的工作模式​​ ;
  • ​2.外部中斷 :​ ​​外部中斷也會改變處理器的工作模式​​;
  • ​3.異常處理 :​ 當​​異常發生的時候, 也會修改處理器的工作模式​​ ;
  • ​4.BootLoader 工作模式 :​ ​​BootLoader 工作在 svc 模式 下​​, 該模式比較進階, 可以 ​​通路較多的寄存器資源​​ , ​​執行更多的處理器指令​​ ;
  • ​5.如何修改工作模式 :​ 修改 ​​程式狀态 寄存器 ( CPSR ) 中的 0 ~ 4 位 即可改變處理器工作模式​​;
    【嵌入式開發】ARM 處理器工作模式 及 修改方法 ( 處理器模式 | 設定處理器模式 | 程式狀态字寄存器 CPSR SPSR | 模式設定代碼編寫 | 設定 svc 模式 )
  • ​6.修改CPSR值 :​ 修改的 ​​程式狀态寄存器 0 ~ 4 位的值​​ 為, 下面表中的 模式代碼. 即 ​​每行 第三列的 二進制碼​​ ;
    【嵌入式開發】ARM 處理器工作模式 及 修改方法 ( 處理器模式 | 設定處理器模式 | 程式狀态字寄存器 CPSR SPSR | 模式設定代碼編寫 | 設定 svc 模式 )
  • ​7.處理器工作模式 對應的 M 位 ( CPRS 0 : 4 ) 值 以及其對應的 可使用的寄存器 :​
    【嵌入式開發】ARM 處理器工作模式 及 修改方法 ( 處理器模式 | 設定處理器模式 | 程式狀态字寄存器 CPSR SPSR | 模式設定代碼編寫 | 設定 svc 模式 )

(2) 處理器工作模式 修改方式 ( 程式狀态字寄存器 工作模式修改 )

​參考手冊 :​ ​​A2.5 Program status registers​​

  • ​1.處理器工作模式位置 :​ ​​ARM Architecture Reference Manual [ A 2.5 ] 章節​​;
  • ​2.參考手冊下載下傳位址 ​​

​程式狀态字寄存器 :​

  • ​1.寄存器内容 :​ 該寄存器 中 包含 ​​① 狀态碼标志位​​, ​​② 中斷标志位​​, ​​③ 目前處理器工作模式​​ 和 其它一些 ​​④ 狀态​​ 與 ​​⑤ 控制資訊​​ ;
  • ​2.CPSR 寄存器 :​ 全稱 Current Program Status Register ( 目前程式狀态字寄存器 ), ​​儲存的是目前的程式狀态​​ ;
  • ​3.SPSR 寄存器 :​ 全稱 Saved Program Status Register ( 程式狀态儲存寄存器 ), ​​每個異常都有對應的獨立的 SPSR 寄存器​​, ​​當異常發生的時候, 先将 CPSR 寄存器中的值 儲存到 SPSR 寄存器中​​, 以便 異常處理完畢後 再回到原來斷點處 繼續運作 ;
    【嵌入式開發】ARM 處理器工作模式 及 修改方法 ( 處理器模式 | 設定處理器模式 | 程式狀态字寄存器 CPSR SPSR | 模式設定代碼編寫 | 設定 svc 模式 )
  • ​4.SPSR 寄存器分布 :​ ​​使用者模式 和 系統模式 沒有 對應的 SPSR 寄存器​​, ​​隻有 5 種 異常模式才有對應的 SPSR 寄存器​​ ;
    • ​​( 1 ) SPSR 寄存器讀寫​​ : 在 使用者模式 或 系統模式 讀寫 SPSR 指令 會出現不可預測的錯誤或行為 ;

(3) 程式狀态字寄存器 位 類型

​參考手冊 :​ ​​A2.5 Program status registers​​

  • ​1.處理器工作模式位置 :​ ​​ARM Architecture Reference Manual [ A 2.5 ] 章節​​;
  • ​2.參考手冊下載下傳位址 ​​

​程式狀态字寄存器 位 類型簡介 :​

【嵌入式開發】ARM 處理器工作模式 及 修改方法 ( 處理器模式 | 設定處理器模式 | 程式狀态字寄存器 CPSR SPSR | 模式設定代碼編寫 | 設定 svc 模式 )
  • ​1.特權位​ : 在 ​特權模式 下可進行修改​ 的 位數, ​使用者模式下不能修改特權位​, 如 ​A, I , F, 和 M ( 0 :4 )​ 位;
  • ​2.使用者可寫位 :​ ​任何模式都可以修改的 資料位​, 如 ​N, Z, C, V, Q, GE[ 3 : 0 ], E​ 資料位;
  • ​3.執行狀态位 :​ 可以從 ​​任何特權模式修改, 使用者模式不能修改​​ ; ​J 和 T 兩位 是運作狀态位​, 在 ARM 狀态下總是 0 ;
    • ​( 1 ) CPSR 運作狀态位 :​ 使用 MSR 特權指令 将通用寄存器的值 儲存到 CPSR 中, ​​J 和 T 兩位必須設定為 0​​ , 否則會出現不可預知錯誤;
    • ​( 2 ) SPSR 運作狀态位 :​ 在 上面 的 限制中, 隻針對 CPSR 寄存器, SPSR 沒有這個限制,
  • ​4.保留位 :​ ​​為之後的功能擴充保留的位數​​ ;
    • ​​( 1 ) 讀取 :​​ 保留位 讀取時 都當做 0 值;
    • ​​( 2 ) 寫入 :​​ 不能向 保留位 寫出實際資料 ;

(4) 程式狀态字寄存器修改流程

​參考手冊 :​ ​​arm彙編手冊(中文版).chm​​

  • ​1.本節使用的彙編指令 :​ ​​BIC, ORR, MSR, MRS​​;
  • ​2.arm彙編手冊下載下傳位址 ​​

​修改程式狀态字寄存器 使用到的彙編指令 :​

  • ​1.将處理器工作模式位 設定 0​ : ​​将 CPRS 程式狀态字 寄存器 中的 0 ~ 4 位 設定為 0​​ , 注意 ​​CPRS 不能直接操作​​ ; 使用 BIC 指令進行設定;
    • ​( 1 ) BIC 彙編指令 文法 :​ bic 文法格式 ​

      ​bic <dest>, <op1>, <op2>​

      ​, dest 存放位清除結果, op1 是被清除的對象, op2 是掩碼;
    • ​( 2 ) BIC 指令 示例 :​ ​

      ​bic r0, r0, #0b1011​

      ​, 清除 r0 中的 第0, 1, 3 位, 其餘位保持不變, 結果放入 r0 中;
    • ​( 3 ) 使用注意點 :​ dest op1 都不能使用立即數, 必須使用寄存器, op2 可以使用立即數;
    • ​( 4 ) 立即數進制 :​ 此處的的立即數必須使用二進制形式 ;
  • ​2.為 處理器工作模式位 設定 1​ : ​将 CPRS 程式狀态字 寄存器 中的 0 ~ 4 位 設定為 指定的二進制數字​ , 注意 CPRS 不能直接操作 ; 使用 orr 指令 進行設定 ;
    • ​( 1 ) ORR 彙編指令 文法 :​ ​

      ​ORR{條件}{S} <dest>, <op 1>, <op 2>​

      ​, ​​dest 結果是 op 1 與 op 2 進行或運算的結果​​;
    • ​( 2 ) ORR 指令 說明 :​ ​​dest 必須是寄存器​​, ​​操作數 1 ( op 1 ) 必須是寄存器​​, ​​操作數 2 ( op 2 ) 可以是 ① 寄存器 ② 被移位寄存器 ③ 立即數​​;
    • ​( 3 ) ORR 示例 :​ ​

      ​ORR R0, R0, #3​

      ​, 将 立即數 3 與 R0 寄存器中的值 進行 或 運算, 然後将運算結果存放到 R0 中;
  • ​3.程式狀态字寄存器 ( CPSR 和 SPSR ) 通路指令 :​ 使用 MRS MSR 指令, ​​程式狀态字 不能使用 通用寄存器的語句 如 MOV 等通路​​, 必須使用 ​​程式狀态寄存器的 專用指令​​ 讀寫;
    • ​( 1 ) 程式狀态字寄存器 通路 流程​ : 程式狀态字寄存器不能直接通路, 需要​​先将程式狀态字寄存器内容導出到通用寄存器中, 才能進行操作​​ , 不能直接修改 CPSR 和 SPSR 中的值 ;
    • ​( 2 ) MRS 指令​ : ​

      ​MRS R0, CPSR​

      ​ , 将 CPRS 寄存器的值 複制 到 R0 寄存器中;
    • ​( 3 ) MSR 指令​ : ​

      ​MSR CPSR, R0​

      ​, 将 R0 寄存器中的值 設定 到 CPSR 寄存器中 ;
  • ​4.流程總結 :​
    • ​( 1 ) 導出 CPSR 寄存器值 :​ ​​使用 MRS 将 CPSR 寄存器的值導出到通用寄存器中​​ ;
    • ​( 2 ) 将工作模式位置 0​ : ​​将導出的 CPSR 寄存器的值的 0 ~ 4 位 設定為 0​​ ;
    • ​( 3 ) 将工作模式位置 1 :​ ​​将導出的 CPSR 寄存器的值的 0 ~ 4 位 設定 對應 的 模式代碼​​ ;
    • ​( 4 ) 将設定好的 CPSR 寄存器值設定到 寄存器中 :​ ​​使用 MSR 指令, 将 在通用寄存器中 設定好的 CPSR 寄存器值 設定回 CPSR 寄存器中​​ ;

二. 處理器工作模式修改 代碼示例

1. 彙編代碼編寫

(1) 代碼 邏輯 分析

​代碼 邏輯 分析 :​

  • ​1.設定 處理器工作模式 時機 :​ 進行 處理器工作模式 設定 是在 ​​開發闆上電後, 對應的 reset 異常向量處​​;
  • ​2.設定 指令标号 :​ 設定一個指令标号, 在标号下定義一組彙編指令, ​​當需要執行這一組指令的時候, 在跳轉到該标号即可​​;
    • ​( 1 ) 定義标号 :​ ​

      ​set_svc :​

      ​, 在标号下定義一組彙編指令;
  • ​3.導出 CPSR 寄存器值 :​ 使用 MRS 指令, 即 ​

    ​mrs r0 cpsr​

    ​ 将 CPSR 寄存器中的值導出到 R0 寄存器中;
  • ​4.将 R0 中的 M 位 清 0 :​ 在 R0 中将從 CPSR 中導出的寄存器值 對應的 0 ~ 4 位 清0, 使用 ​

    ​bic r0, r0, #0x1f​

    ​, ​​将 R0 寄存器的值 與 #0x1f 進行 與操作, 即 後5 位都設定成0, 然後将 與 操作的結果儲存到 R0 寄存器中​​ ;
  • ​5.将 R0 中的 M 位 設定 模式代碼 :​ 在下圖中, svc 的模式代碼時 0b10011 ( 二進制 ), 即 0x13 ( 十六進制 ), 使用 ​

    ​orr r0, r0, #0xd3​

    ​ 語句設定, ​​将 R0 寄存器中的值 與 0x13 進行 或操作, 将 或操作的結果 存放到 R0 寄存器中​​;
    【嵌入式開發】ARM 處理器工作模式 及 修改方法 ( 處理器模式 | 設定處理器模式 | 程式狀态字寄存器 CPSR SPSR | 模式設定代碼編寫 | 設定 svc 模式 )
  • ​6.将值寫回 CPSR 寄存器 :​ 使用 MSR 指令 ​

    ​msr cpsr, r0​

    ​ , 将處理完的 CPSR 寄存器值 設定給 CPSR 寄存器;

(2) 彙編代碼示例

​彙編代碼示例 :​

@****************************  
@File:start.S  
@  
@BootLoader 初始化代碼 
@****************************  

.text                                   @ 宏 指明代碼段  
.global _start                          @ 僞指令聲明全局開始符号  
_start:                                 @ 程式入口标志  
        b   reset                       @ reset 複位異常  
        ldr pc, _undefined_instruction  @ 未定義異常, 将 _undefined_instruction 值裝載到 pc 指針中  
        ldr pc, _software_interrupt     @ 軟中斷異常  
        ldr pc, _prefetch_abort         @ 預取指令異常  
        ldr pc, _data_abort             @ 資料讀取異常  
        ldr pc, _not_used               @ 占用 0x00000014 位址                            
        ldr pc, _irq                    @ 普通中斷異常  
        ldr pc, _fiq                    @ 軟中斷異常  

_undefined_instruction: .word undefined_instruction @ _undefined_instruction 标号存放了一個值, 該值是 32 位位址 undefined_instruction, undefined_instruction 是一個位址  
_software_interrupt:    .word software_interrupt    @ 軟中斷異常  
_prefetch_abort:    .word prefetch_abort            @ 預取指令異常 處理  
_data_abort:        .word data_abort                @ 資料讀取異常  
_not_used:      .word not_used                      @ 空位處理  
_irq:           .word irq                           @ 普通中斷處理  
_fiq:           .word fiq                           @ 快速中斷處理  

undefined_instruction:                              @ undefined_instruction 位址存放要執行的内容  
        nop  

software_interrupt:                                 @ software_interrupt 位址存放要執行的内容  
        nop  

prefetch_abort:                                     @ prefetch_abort 位址存放要執行的内容  
        nop  

data_abort:                                         @ data_abort 位址存放要執行的内容  
        nop  

not_used:                                           @ not_used 位址存放要執行的内容  
        nop  

irq:                                                @ irq 位址存放要執行的内容  
        nop  

fiq:                                                @ fiq 位址存放要執行的内容  
        nop  

reset:                                              @ reset 位址存放要執行的内容  
        bl set_svc                                  @ 跳轉到 set_svc 标号處執行

set_svc:
        mrs r0, cpsr                                @ 将 CPSR 寄存器中的值 導出到 R0 寄存器中
        bic r0, r0, #0x1f                           @ 将 R0 寄存器中的值 與 #0x1f 立即數 進行與操作, 并将結果儲存到 R0 寄存器中, 實際是将寄存器的 0 ~ 4 位 置 0
        orr r0, r0, #0xd3                           @ 将 R0 寄存器中的值 與 #0xd3 立即數 進行或操作, 并将結果儲存到 R0 寄存器中, 實際是設定 0 ~ 4 位 寄存器值 的處理器工作模式代碼
        msr cpsr, r0                                @ 将 R0 寄存器中的值 儲存到 CPSR 寄存器中      

2. 連結器腳本

​gboot.lds 連結器腳本 代碼解析 :​

  • ​1.指明輸出格式 ( 處理器架構 ) :​ 使用 ​

    ​OUTPUT_ARCH(架構名稱)​

    ​ 指明​​輸出格式, 即處理器的架構​​, 這裡是 arm 架構的, ​

    ​OUTPUT_ARCH(arm)​

    ​ ;
  • ​2.指明輸出程式的入口 :​ 設定編譯輸出的程式入口位置, 文法為 ​

    ​ENTRY(入口位置)​

    ​, 在上面的 Start.S 中設定的程式入口是 ​

    ​_start​

    ​, 代碼為 ​

    ​ENTRY(_start)​

    ​ ;
  • ​3.設定代碼段 :​ 使用 ​

    ​.text :​

    ​ 設定代碼段;
  • ​4.設定資料段 :​ 使用 ​

    ​.data :​

    ​ 設定資料段;
  • ​5.設定 BSS 段 :​ 使用 ​

    ​.bss :​

    ​ 設定 BSS 段;
    • ​( 1 ) 記錄 BSS 段的起始位址 :​ ​

      ​bss_start = .;​

      ​ ;
    • ​( 2 ) 記錄 BSS 段的結束位址 :​ ​

      ​bss_end = .;​

      ​ ;
  • ​6.對齊 :​ 每個段都需要設定記憶體的對齊格式, 使用 ​

    ​. = ALIGN(4);​

    ​ 設定四位元組對齊即可;
  • ​7.代碼示例 :​
OUTPUT_ARCH(arm)        /*指明處理器結構*/  
ENTRY(_start)           /*指明程式入口 在 _start 标号處*/  
SECTIONS {                
    . = 0x50008000;     /*整個程式連結的起始位置, 根據開發闆确定, 不同開發闆位址不一緻*/  

    . = ALIGN(4);       /*對齊處理, 每段開始之前進行 4 位元組對齊*/  
    .text :             /*代碼段*/  
    {  
    start.o (.text)     /*start.S 轉化來的代碼段*/  
    *(.text)            /*其它代碼段*/  
    }  

    . = ALIGN(4);       /*對齊處理, 每段開始之前進行 4 位元組對齊*/  
    .data :             /*資料段*/  
    {  
    *(.data)  
    }  

    . = ALIGN(4);       /*對齊處理, 每段開始之前進行 4 位元組對齊*/  
    bss_start = .;      /*記錄 bss 段起始位置*/  
    .bss :              /*bss 段*/  
    {  
    *(.bss)   
    }  
    bss_end = .;        /*記錄 bss 段結束位置*/  
}      

3. Makefile 編譯腳本

​makefile 檔案編寫 :​

  • ​1.通用規則 ( 彙編檔案編譯規則 ) :​ ​彙編檔案 編譯 成同名的 .o 檔案​, 檔案名稱相同, 字尾不同, ​

    ​%.o : %.S​

    ​, 産生過程是 ​

    ​arm-linux-gcc -g -c $^​

    ​ , 其中 ​

    ​^​

    ​ 辨別是所有的依賴檔案, 在該規則下 start.S 會被變異成 start.o ;
  • ​2.通用規則 ( C 檔案編譯規則 ) :​ C 代碼編譯成同名的 .o 檔案, ​

    ​%.o : %.c​

    ​ , 産生過程是 ​

    ​arm-linux-gcc -g -c $^​

    ​ ;
  • ​3.設定最終目标 :​ 使用 ​

    ​all:​

    ​ 設定最終編譯目标;
    • ​( 1 ) 依賴檔案 :​ ​​産生最終目标需要依賴 start.o 檔案​​, 使用 ​

      ​all: start.o​

      ​ 表示最終目标需要依賴該檔案;
    • ​( 2 ) 連結過程 :​ ​

      ​arm-linux-ld -Tgboot.lds -o gboot.elf $^​

      ​, 需要使用連結器腳本進行連接配接, ​​①連結工具是 arm-linux-ld 工具​​, ​​②使用 ​

      ​-Tgboot.lds​

      ​ 設定連結器腳本 是剛寫的 gboot.lds 連結器腳本​​, ​​③輸出檔案是 gboot.elf 這是個中間檔案​​, ​​④ 依賴檔案是 ​

      ​$^​

      ​ 代表所有的依賴​​;
    • ​( 3 ) 轉換成可執行二進制檔案 :​ ​

      ​arm-linux-objcopy -O binary gboot.elf gboot.bin​

      ​, 使用 ​

      ​-O binary​

      ​ 設定輸出二進制檔案, 依賴檔案是 ​

      ​gboot.elf​

      ​, 輸出的可執行二進制檔案 即 結果是 ​

      ​gboot.bin​

      ​ ;
  • ​4.makefile 檔案内容 :​
all: start.o #依賴于 start.o  
    arm-linux-ld -Tgboot.lds -o gboot.elf $^    #使用連結器腳本, 将 start.o 轉為 gboot.elf  
    arm-linux-objcopy -O binary gboot.elf gboot.bin #将 gboot.elf 轉化為可以直接在闆子上執行的 gboot.bin 檔案  

%.o : %.S   #通用規則, 如 start.o 是由 start.S 編譯來的, -c 是隻編譯不連結  
    arm-linux-gcc -g -c $^  

%.o : %.c   #通用規則, 如 start.o 是由 start.c 編譯來的, -c 是隻編譯不連結  
    arm-linux-gcc -g -c $^  

.PHONY: clean     
clean:              #清除編譯資訊  
    rm *.o *.elf *.bin      

4. 編譯輸出可執行檔案

​編譯過程 :​

  • ​1.檔案準備 : 将 彙編代碼 ( start.S ) 連結器腳本 ( gboot.lds ) makefile 檔案 拷貝到編譯目錄​ ;
  • ​2.執行編譯指令 :​ ​

    ​make​

    ​ ;
  • ​3.編譯結果 :​ 可以看到 生成了 編譯目标檔案 start.o, 連結檔案 gboot.elf, 可執行的二進制檔案 gboot.bin ;
    【嵌入式開發】ARM 處理器工作模式 及 修改方法 ( 處理器模式 | 設定處理器模式 | 程式狀态字寄存器 CPSR SPSR | 模式設定代碼編寫 | 設定 svc 模式 )

繼續閱讀