C語言與組合語言之間的函式呼叫
教材:嵌入式系統及應用,羅蕾、李允、陳麗蓉等,電子工業出版社
ARM 程式設計
C與彙編之間的函式呼叫
ATPCS簡介
- ARM-Thumb 過程呼叫標準 ATPCS(ARM-Thumb Procedure Call Standard)
- ATPCS 標準既是ARM 編譯器使用的函式呼叫規則,也是設計可被 C 程式呼叫的彙編函式的編寫規則
堆疊與暫存器在函式呼叫中的作用
- 函式是通過暫存器和堆疊來傳遞引數和返回函式值的
- 形參和返回值都應定義在具有暫存性質的暫存器和堆疊中
ATPCS關於堆疊和暫存器的使用規則
ATPCS 規定,ARM 的資料堆疊為 FD 型堆疊,即滿遞減
對於引數個數不多於 4 的函式,編譯器必須按引數在列表中的順序,自左向右 為它們分配暫存器 R0~R3
其中函式返回時,R0 還被用來存放函式的返回值
如果函式的引數多於 4 個,那麼多餘的引數則按自右向左的順序壓入資料堆疊(引數入棧順序與引數順序相反)
一個浮點數可能幾個整數型的暫存器進行傳送
雙精度和
long long
型別的引數通過兩個連續的暫存器來傳遞,返回值通過R0和R1返回(大端系統下,R0包含高位有效字)ATPCS規定的暫存器名稱及使用
RWPI:讀寫位置無關(編譯器選項)
為確保效能,函式內部最多使用12個區域性變數
暫存器的別名和特殊名稱都是ARM編譯器和彙編器預定義的
C程式調用匯編函式例項
程式設計師代替C編譯器把C函式翻譯成彙編程式
下面是一個用匯編語言編寫的函式,該函式把 R1 指向的資料塊複製到 R0 指向的儲存塊
AREA Strcopy, CODE, READONLY EXPORT strcopy ;宣告strcopy為匯出符號 strcopy LDRB R2, [R1], #1 ;R1的值為源資料首地址 STRB R2, [R0], #1 ;R0的值為目標資料塊首地址 CMP R2, #0 BNE strcopy MOV
根據引數與暫存器直接的規則,可知彙編函式 strcopy 在C程式中原型應該為:
void strcopy(char *d, const char* s);
在C語言檔案中,呼叫 strcopy 函式的方法如下
extern void strcopy(char *d, const char * s); //宣告strcopy為外部引用符號 int main(void) { const char *src = “source”; char dest[10]; ... strcopy(dest, src); //調用匯編函式strcopy ... }
彙編程式呼叫C函式例項
現有C函式 g() 如下
int g(int a, int b, int c, int d, int e) { return a+b+c+d+e; }
彙編函式f中呼叫C函式g(),以實現下面的功能
int f(int i) { return –g(i, 2*i, 3*i, 4*i,5*i); }
整個彙編函式 f 的程式碼如下
EXPORT f AREA f, CODE, READONLY IMPORT g ;聲名g為外部引用符號 STR LR, [SP, #-4] ;斷點存入堆疊 ADD R1, R0, R0 ;(R1)= i*2 ADD R2, R1, R0 ;(R2)= i*3 ADD R3, R1, R2 ;(R3)= i*5 STR R3, [SP, #-4] ;將(R3)即第5個引數i*5存入堆疊 ADD R3, R1, R1 ;(R3)= i*4 BL g ;呼叫C函式g(),返回值在暫存器R0中 ADD SP, SP, #4 ;清棧 RSB R0, R0, #0 ;函式f的返回值(R0)=0-(R0) LDR PC, [SP], #4 ;恢復斷點並返回 END
呼叫時第5個引數放在資料堆疊段,所以呼叫C函式後需要清棧
C/C++語言和組合語言的混合程式設計
在 C 程式中內聯或嵌入式彙編程式碼,以提高程式的效率
內聯彙編
在 C 程式中直接編寫彙編程式段而形成一個語句塊,這個語句塊可以使用除了 BX 和 BLX之外的全部ARM指令來編寫
可以使程式實現一些不能從C獲得的底層功能
void enable_IRQ(void) { int tmp; _ _asm //聲名內聯彙編程式碼 { MRS tmp, CPSR BIC tmp, tmp, #0x80 MSR CPSR_c, tmp } }
彙編語句塊中,如果有兩條指令佔據了同一行,那麼必須用分號“ ;”將它們分隔
如果一條指令需要佔用多行,那麼必須用反斜線符號“ \ ”作為續行符
可以在內聯組合語言塊內的任意位置使用C/C++格式的註釋
內聯彙編程式碼中定義的標號可被用作跳轉或C/C++ goto 語句的目標,同樣,在C/C++程式碼中定義的標號,也可被用作內聯彙編程式碼跳轉指令的目標
內聯彙編的限制
- 它不支援 Thumb 指令;除了程式狀態暫存器 PSR 之外,不能直接訪問其他任何物理暫存器
- 如果在內聯彙編程式指令中出現了以某個暫存器名稱命名的運算元,那麼它被叫做虛擬暫存器,而不是實際的物理暫存器。編譯器在生成和優化程式碼的過程中,會給每個虛擬暫存器分配實際的物理暫存器,但這個物理暫存器可能與在指令中指定的不同。
- 在內聯彙編程式碼中不能使用暫存器 PC(R15)、LR(R14)和SP(R13)
- 更改處理器模式會禁止使用 C 運算元或對已編譯 C 程式碼的呼叫,直到將處理器模式恢復為原設定之後
狀態暫存器 PSR ,任何對 PSR 的引用總是執行指向物理 PSR
在內聯彙編語句塊中最好使用 C 或 C++ 變數作為運算元
嵌入式彙編
嵌入式彙編程式是一個編寫在C程式外的單獨彙編程式,該程式段可以像函式那樣被 C 程式呼叫
嵌入式彙編具有真實彙編的所有特性,資料交換符合 ATPCS 標準,同時支援 ARM 和Thumb,所以它可以對目標處理器進行不受限制的低階訪問
不能直接引用 C/C++ 的變數
定義一個嵌入式彙編函式的語法格式為
_ _asm return–type function–name(parameter-list) { 彙編程式段 }
- return–type:函式返回值型別,C語言中的資料型別
- function–name:函式名
- parameter-list:函式引數列表
引數名只允許使用在引數列表中,不能用在嵌入式彙編函式體內
在 C 程式中呼叫嵌入式彙編程式的方法與呼叫 C 函式的方法相同
內聯彙編與嵌入式彙編的差異
內聯彙編程式碼使用高階處理器抽象,並在程式碼生成過程中與 C 和 C++程式碼整合。因此編譯程式將 C 和 C++程式碼與彙編程式碼一起進行優化
嵌入式彙編程式碼從 C 和 C++ 程式碼中分離出來單獨進行彙編,產生與 C 和 C++ 原始碼編譯物件相結合的編譯物件
可通過編譯程式來內聯彙編程式碼,但無論是顯示還是隱式,都無法內聯嵌入式彙編程式碼
相關推薦
C語言與組合語言之間的函式呼叫
教材:嵌入式系統及應用,羅蕾、李允、陳麗蓉等,電子工業出版社 ARM 程式設計 C與彙編之間的函式呼叫 ATPCS簡介 ARM-Thumb 過程呼叫標準 ATPC
C語言與組合語言相互呼叫
在使用C語言時,要用到和組合語言的混合程式設計。若彙編程式碼較為簡潔,則可使用直接內嵌彙編的方法;否則要將彙編程式以檔案的形式加入到專案中,按照ATPCS(ARM/Thumb過程呼叫標準,ARM/Thumb Procedure Call Standard)的規定與C程
C語言中有關外部函式呼叫的問題
首先指出一點,我們通常所說的編譯器並非僅指編譯器,確切來說是編譯工具鏈,裡面包括了預編譯器、編譯器、彙編器和聯結器。 對於外部函式實體(處於呼叫函式所在原始檔之外的其他原始檔中的函式),是在連結過程中,才會被尋找和新增程序序,一旦沒有找到函式實體,就會報錯,無法成功連結。
ARM彙編與C語言混合程式設計之彙編呼叫C函式
呼叫沒有引數的函式 呼叫有引數的函式 總結 本文所用硬體平臺為S3C2440開發板。通過一個點亮數碼管的程式說明ARM彙編呼叫C函式的方法。 根據C語言中函式引數的個數,可以將彙編呼叫C函式分為兩種情況,呼叫沒有引數的函式和呼叫有引數的
C語言可變長引數函式與預設引數提升
學習本章內容的時候,首先需要知道可變引數提升相關的知識。 原文地址:https://blog.csdn.net/astrotycoon/article/details/8284501 1、概述 C標準中有一個預設引數提升(default argument promotions)規則。
軟體素材---linux C語言:拼接字串函式 strcat的用例(與char陣列聯合使用挺好)
【標頭檔案】#include <string.h> 【原型】 1 char *strcat(char *dest, const char *src); 【引數】: dest 為目標字串指標,src 為源字串指標。
C語言與matlab混合程式設計中mwArray的Get函式的簡單用法解釋
網上的通用示例: double data[4] = {1.0, 2.0, 3.0, 4.0}; double x; mwArray a(2, 2, mxDOUBLE_CLASS); a.SetData(data, 4); x = a.Get(1,1); // x = 1.0
C++知識積累:運算子過載時建構函式與解構函式呼叫次數不一致的問題
在學習運算子過載的時候自己寫了這樣一段程式: class Stu { public: Stu() { std::cout<<"Stu No parameter constructor called!"<<
C語言中變數和函式的宣告與定義
一、變數在將變數前,先解釋一下宣告和定義這兩個概念。宣告一個變數意味著向編譯器描述變數的型別,但並不為變數分配儲存空間。定義一個變數意味著在宣告變數的同時還要為變數分配儲存空間。在定義一個變數的同時還可以對變數進行初始化。 區域性變數通常只定義不宣告,而全域性變數多在原始檔中定義,在標頭檔案中宣告。 區域性變
C語言學習筆記_5函式與程式結構
/**************************************************************************** *第五章函式與程式結構 *****2016
C語言基礎教程 printf( )函式中的回車‘\r’與回車換行'\n'
今天完成了初級階段的學習,其實以前在開發微控制器的時候用過C語言,但是沒有系統的學過,所以再次學習感覺能夠查缺補漏。 C語言中的printf( )函式是一個很重要的函式。printf( )中的字元包含了三種: (1)以%開頭的格式控制字元 (2)以 \ 開頭的轉義字元 (3)普通字元 在printf
C++語言特性?虛擬函式與純虛擬函式的作用與區別?
一、C++語言的特性有哪些? 1、封裝 封裝就是將抽象得到的資料行為(或功能)相結合,形成一個有機的整體,也就是將資料與操作資料的函式程式碼進行有機地結合,形成類,其中的資料和函式都是類的組成部分,稱為類的成員。 2、繼承 繼承是從先輩處得到的屬性和行為特徵。類的繼承,是新
C語言常用檔案操作函式fprinf/fscanf與fwrite/fread
fprintf是將資料轉換為字元後再寫入檔案 fwrite是將資料不經轉換直接以二進位制的形式寫入檔案 一、fprintf函式。 fprintf(fp, "%d", buffer); 是將格式化的資料寫入檔案 fprintf(檔案指標,格式字串,輸出表列); 1.
C語言中的內部函式與外部函式
內部函式: 如果一個函式只能被本檔案中其它函式所呼叫,它稱為內部函式。在定義內部函式時,在函式名和函式型別的前面加static。即 static 型別識別符號 函式名 (形參表) 如: static int fun (int a, int b) 內部函式又稱靜態函
【C/C++】C語言math.h庫函式中atan與atan2的區別
Ref 在 math.h 標準庫中,定義了兩個反正切函式: //返回以弧度表示的 x 的反正切 double atan(double x) //返回以弧度表示的 y/x 的反正切。y 和 x 的值的符號決定了正確的象限。 double at
自動生成Jni中Java呼叫C語言實現的簽名函式名
首先編寫一個類例如HelloWorld.java類檔案 把你要在Java程式碼中宣告的呼叫C語言的native函式宣告寫在Helloworld.java程式碼中 例如: public class HelloWorld{ public native String Hello
C++建構函式與解構函式呼叫虛擬函式的注意事項
雖然可以對虛擬函式進行實呼叫,但程式設計師編寫虛擬函式的本意應該是實現動態聯編。在建構函式中呼叫虛擬函式,函式的入口地址是在編譯時靜態確定的,並未實現虛呼叫。但是為什麼在建構函式中呼叫虛擬函式,實際上沒有發生動態聯編呢? 第一個原因,在概念上,建構函式的工作是
C語言程式設計基礎-09函式與返回值及形參
函式 返回值 形參實參 函式 在大規模的程式中需要對語句進行分組管理,把相互之間聯絡比較緊密的語句合併成一組; 分組可以在多個不同層次上進行,最低一級分組的結果叫程式碼塊,程式碼塊由{}大括號包括; 在大括號前面新增 型別名 函式名()的就是函式; 函式的形式如 v
#C語言學習感悟# printf( )函式中的回車‘\r’與回車換行'\n'之我見。
今天完成了初級階段的學習,其實以前在開發微控制器的時候用過C語言,但是沒有系統的學過,所以再次學習感覺能夠查缺補漏。C語言中的printf( )函式是一個很重要的函式。printf( )中的字元包含了三種:(1)以%開頭的格式控制字元(2)以 \ 開頭的轉義字元(3)普通字元