1. 程式人生 > >C語言與組合語言之間的函式呼叫

C語言與組合語言之間的函式呼叫

教材:嵌入式系統及應用,羅蕾、李允、陳麗蓉等,電子工業出版社

ARM 程式設計

C與彙編之間的函式呼叫

ATPCS簡介

  • ARM-Thumb 過程呼叫標準 ATPCS(ARM-Thumb Procedure Call Standard)
  • ATPCS 標準既是ARM 編譯器使用的函式呼叫規則,也是設計可被 C 程式呼叫的彙編函式的編寫規則

堆疊與暫存器在函式呼叫中的作用

  • 函式是通過暫存器和堆疊來傳遞引數和返回函式值的
  • 形參和返回值都應定義在具有暫存性質的暫存器和堆疊中

ATPCS關於堆疊和暫存器的使用規則

  • ATPCS 規定,ARM 的資料堆疊為 FD 型堆疊,即滿遞減

    堆疊
    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
    PC, LR ;複製完畢,返回 END
  • 根據引數與暫存器直接的規則,可知彙編函式 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 returntype functionname(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語言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/fscanffwrite/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庫函式中atanatan2的區別

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)普通字元