王 茹
遼寧裝備制造職業技術學院(沈陽 110161)
在嵌入式應用程序的設計中,如果所有的編程任務都由匯編語言來完成,雖然目標代碼執行效率高,但其工作量會很大且不易維護;如果全部任務由C/C++語言來完成,雖然簡潔明了,但是目標代碼執行效率低,尤其在實時性較強的應用中更會突顯C/C++的不足。因此,一個嵌入式應用程序通常是由匯編語言和 C/C++語言混合編程來實現的,除了初始化部分用匯編語言編程外,其主要的編程任務一般都由C/C++來完成。主要介紹了ARM匯編語言與C/C++語言混合編程的兩種實現方法:內嵌匯編和ATPCS規則。
ARM處理器核能通過相應的編譯器實現匯編語言與 C/C++等語言之間的調用/切換。為了這些調用能夠順利的實施,ARM規定了一套標準——ATPCS過程調用標準。
ATPCS對 ARM 通用寄存器給以了不同的命名,在進行編程時一般使用ATPCS命名寄存器。ARM寄存器與ATPCS對照表如表1所示。

表1 ARM寄存器與ATPCS對照表
ATPCS規定堆棧采用滿遞減類型(FD,Full Descending),即堆棧通過減小存儲器地址而向下增長,堆棧指針指向內含有效數據的最低地址。
整數參數的前4個使用R0~R3傳遞,其他參數使用堆棧傳遞,所以要想參數傳遞簡單,最好函數的參數個數小于等于4。
子程序的返回結果為1個32位整數時,通過R0返回;返回結果為1個64位整數時,通過R0和R1返回;依此類推。結果為浮點數時,通過浮點運算部件的寄存器F0中。
嵌入式應用程序開發一般由匯編語言完成初始化后,切換到C語言實現應用功能的開發。匯編語言中要用IMPORT偽操作聲明該C語言程序;匯編語言中通過BL實現程序的調用。
實例1 用匯編語言調用C語言方法實現字符串的復制。

在C語言程序中,用EXTERN聲明匯編程序;在匯編程序中,用EXPORT 聲明可以被調用的程序。
C++程序調用C程序時,在C++程序中使用關鍵詞 extern "C"聲明被調用的 C程序。對于C++中的類(class)或者結構(struct),如果它沒有基類和虛函數,則相應的對象的存儲結構和ARM C相同。

匯編程序調用 C++程序時,在 C++程序中使用關鍵詞 extern "C"聲明被調用的 C++程序。對于C++中的類或者結構,如果它沒有基類和虛函數,則相應的對象的存儲結構和ARM C相同。在匯編程序中使用偽操作 IMPORT聲明被調用的C++程序。在匯編程序中將參數存放在數據棧中,而存放參數的數據棧的單元地址放在r0寄存器中,這樣被調用的 C++程序就能訪問相應的參數。
在 CC++語言中內嵌匯編語句可以實現一些高級語言不能實現或者不容易實現的功能。對于時間緊迫的功能也可以通過在 CC++語言中內嵌匯編語句來實現。內嵌的匯編器支持大部分ARM指令和Thumb指令,但是不支持諸如直接修改PC實現跳轉的底層功能,也不能直接引用C語言中的變量。
在ARM C語言程序中使用關鍵詞_asm來標識一段匯編指令程序,其格式如下:

在 ARM C++程序中除了可以使用關鍵詞_asm來標識一段匯編指令程序外,還可以使用關鍵詞 asm來標識一段匯編指令程序,其格式如下: asm("instruction[; instruction]");
(1)在匯編指令中,逗號(,)用作分隔符。因此如果指令中的 C\C++表達式中包含有逗號(,),則該表達式應該被包含在括號中。例如:
asm {ADD x, y, (f(), z)}其中,(f(), z)為C\C++表達式
(2)如果在指令中使用的物理寄存器,應該保證該寄存器不會被編譯器在計算表達式值時破壞。
(3)不要使用物理寄存器去引用一個 C變量。
(4)對于內嵌匯編器可能會用到的寄存器,編譯器自己會保存和恢復這些寄存器,用戶不用保存和恢復這些寄存器。常量寄存器CPSR和寄存器SPSR外,別的寄存器必須先賦值然后再讀取,否則編譯器將會報錯。3.3 內嵌匯編指令的應用
實例3 C程序中內嵌匯編語句,實現字符串的復制。

本文主要通過幾個簡單的例子演示了嵌入式開發中常用的C/C++和ARM匯編混合編程的一些方法和基本的思路,其中內嵌匯編的方法比較簡潔,而ATPCS規則中調用方法較多。以上只是拋磚引玉,更詳細和復雜的使用方法要結合實際應用并參考相關的資料。本文涉及的實例全部在ADS集成開發環境中運行實現。
[1]杜春雷.ARM 體系結構與編程.北京:清華大學出版社,2003.
[2]史斌.ARM匯編語言與C/C++混合編程方法,電子測量技術.2006(6).
[3]孫曄.ARM 嵌入式系統及應用.南京:江蘇教育出版社,2011.