C/C++與彙編混合編程簡介

來源:互聯網
上載者:User
1. 簡介

     當需要C/C++與彙編混合編程時,可以有以下兩種處理策略:

  • 若彙編代碼較短,則可在C/C++源檔案中直接內嵌組合語言實現混合編程。
  • 若彙編代碼較長,可以單獨寫成彙編檔案,最後以彙編檔案的形式加入項目中,通過ATPCS規定與C程式相互調用及訪問。
2. 內嵌組合語言指令

    用C/C++程式嵌入組譯工具中可以實現一些進階語言沒有的功能,提高程式執行效率。armcc編譯器的內嵌彙編器支援ARM指令集,tcc編譯器的內嵌彙編器支援Thumb指令集。

2.1 內嵌彙編指令的文法格式

      在ARM的C語言程式中可以使用關鍵字__asm來加入一段組合語言的程式,格式如下:

__asm{    指令 [;指令]      /* comments */    ...    指令}

      其中,{ }中的指令都為彙編指令,一行允許寫多條彙編指令語句,指令語句之間要用分號隔開。在彙編指令段中,備註陳述式採用C語言的注釋格式。ARM C++程式中除了可以使用關鍵字__asm來標識一段內嵌彙編指令程式外,還可以使用關鍵詞asm來表示一段內嵌彙編指令,格式如下:
asm ("指令");
     其中,asm後面的括弧中必須是一條彙編指令語句,並且不能包含備註陳述式。

2.2 使能/禁止IRQ中斷執行個體

void enable_IRQ(void) //使能中斷程式{    int tmp;              //定義臨時變數,後面使用    __asm                 //內嵌組譯工具的關鍵詞    {        MRS tmp, CPSR     //把狀態寄存器載入給tmp        BIC tmp, tmp, #80 //將IRQ控制位清0        MSR CPSR_c, tmp   //載入程式狀態寄存器    }}void disable_IRQ(void) //禁止中斷程式{    int tmp;              //定義臨時變數,後面使用    __asm                 //內嵌組譯工具的關鍵詞    {        MRS tmp, CPSR     //把狀態寄存器載入給tmp        ORR tmp, tmp, #80 //將IRQ控制位置1        MSR CPSR_c, tmp   //載入程式狀態寄存器    }}

2.3 內嵌彙編注意事項      

      尾碼.S檔案中的彙編指令是用armasm彙編器進行彙編的,而C語言程式中的內嵌彙編指令則是用內嵌彙編器進行彙編的。這兩種彙編器存在一定的差異,所以在內嵌彙編時要注意以下幾點:


2.3.1 小心使用物理寄存器

      必須小心使用物理寄存器,如R0~R3、IP(R12)、LR(R14)和CPSR中的N、Z、C、V標誌位。因為計算彙編代碼中的C運算式時,可能使用這些物理寄存器,並會修改N、Z、C、V標誌位。
      如計算y=x+x/y;

__asm{    MOV R0, x         //把x的值給R0    ADD y, R0, x/y    //計算x/y時R0的值會被修改}
2.3.2 內嵌組譯工具中允許使用C變數        

       在計算x/y時R0會被修改,從而影響R0+x/y的結果。內嵌組譯工具中允許使用C變數,用C變數來代替寄存器R0可以解決上述問題。這時內嵌彙編器將會為變數var分配合適的儲存單元,從而避免衝突的發生。如果內嵌彙編器不能分配合適的儲存單元,它將會報告錯誤。

int var;__asm{    MOV var, x      //把x的值給R0    ADD y, var, x/y //計算x/y時R0的值會被修改}

2.3.3 不需要儲存和恢複用到的寄存器

     對於在內嵌組合語言程式中用到的寄存器,編譯器在編譯時間會自動儲存和恢複這些寄存器,使用者不用儲存和恢複這些寄存器。除了CPSR和SPSR寄存器外,其他物理寄存器在讀之前必須先賦值,否則編譯器會報錯。

int fun (int x){    __asm    {        STMFD SP!, {R0}   //儲存R0,先讀後寫,彙編出錯        ADD R0, x, #1        EOR x, R0, x        LDMFD SP!, {R0}   //多餘的    }    return x;}

3. 彙編與C/C++程式的變數相互訪問3.1 組譯工具訪問C/C++程式變數

     在C/C++程式中聲明的全域變數可以被組譯工具通過地址間接訪問。具體存取方法/步驟如下:
     1) 在C/C++程式中聲明全域變數。
     2) 在組譯工具中使用IMPORT/EXTERN偽指令聲明引用該全域變數。
     3) 使用LDR偽指令讀取該全域變數的記憶體位址。
     4) 根據該資料的類型,使用相應的LDR指令讀取該全域變數;使用相應的STR指令儲存該全域變數的值。對於不同類型的變數,需要採用不同選項的LDR和STR指令,如下表所示。

C/C++語言中的變數類型
帶尾碼的LDR和STR指令
描述
unsigned char
LDRB/STRB
無符號字元型
unsigned short
LDRH/STRH
無符號短整型
unsigned int
LDR/STR
無符號整型
char
LDRSB/STRSB
字元型(8位)
short
LDRSH/STRSH
短整型(16位)

      對於結構,如果知道各個資料項目的位移量,可以通過儲存/載入指令訪問。如果結構所佔空間小於8個字,可以使用LDM和STM一次性讀寫。

     讀取C的一個全域變數,並進行修改,然後儲存新的值到全域變數中:

   AREA Example4, CODE, READONLY        EXPORT AsmAdd        IMPORT g_cVal      @聲明外部變數g_cVal,在C中定義的全域變數AsmAdd        LDR R1, =g_cVal    @裝載變數地址        LDR R0, [R1]       @從地址中讀取資料到R0        ADD R0, R0, #1     @加1操作        STR R0, [R1]       @儲存變數值        MOV PC, LR         @程式返回   END

3.2 C/C++程式訪問組譯工具資料

     在組譯工具中聲明的資料可以被C/C++程式所訪問。具體存取方法/步驟如下:
     1) 在組譯工具中用EXPORT/GLOBAL偽指令聲明該符號為全域標號,可以被其他檔案應用。
     2) C/C++程式中定義相應資料類型的指標變數。
     3) 對該指標變數賦值為組譯工具中的全域標號,利用該指標訪問組譯工具中的資料。

    假設在組譯工具中定義了一塊記憶體地區,並儲存一串字元,彙編代碼如下:
 

EXPORT Message        @聲明全域標號Message DCB "HELLO$"  @定義了5個有效字元,$為結束符

extern char* Message;int MessageLength(){    int Length = 0;    char *pMessage;         //定義字元指標變數    pMessage = Message;     //指標指向Message 記憶體塊的首地址        /*while迴圈,統計字串的長度*/    while(*pMessage != '$') //$為字串的結束符    {        Length++;        pMessage++;    }    return(Length); //返回字串的長度}
4. 彙編與C/C++程式的函數相互調用

    C/C++程式和ARM組譯工具之間相互調用必須遵守ATPCS(ARM/Thumb Procedure Call Standard)規則。使用ADS的C語言編譯器編譯的C語言子程式會自動滿足使用者指定的ATPCS類型。而對於組合語言來說,完全要依賴使用者來保證各個子程式滿足選定的ATPCS類型。具體來說,組譯工具必須滿足以下3個條件才能實現與C語言的相互調用。
     1) 在子程式編寫時必須遵守相應的ATPCS規則。
     2) 堆棧的使用要遵守相應的ATPCS規則。
     3) 在彙編編譯器中使用-atpcs選項。

4.1 ATPCS基本規則

      ATPCS基本規則見ATPCS。

4.2 C程式調用組譯工具

     組譯工具的設定要遵循ATPCS規則,保證程式調用時參數的正確傳遞,在這種情況下,C程式可以調用彙編子函數。C程式調用組譯工具的方法如下:
      1) 組譯工具中使用EXPORT偽指令聲明本子程式可外部使用,使其他程式可調用該子程式。
      2) 在C語言程式中使用extern關鍵字聲明外部函數(聲明要調用的彙編子程式),才可調用此彙編的子程式。

#include <stdio.h>extern void strcopy(char *d, const char *s); //聲明外部函數,即要調用的彙編子程式int main(void){    const char *srcstr = "First ource";          //定義字串常量    char dststr[] = "Second string-destination"; //定義字串變數    printf("Before copying: \n");    printf("src=%s, dst=%s\n", srcstr, dststr);  //顯示源字串和目標字串的內容    strcopy(dststr, srcstr);                     //調用彙編子程式R0=dststr, R1=srcstr    printf("After copying: \n");    printf("src=%s, dst=%s\n", srcstr, dststr);  //顯示複製後的結果    return(0);}

     strcopy實現代碼如下:

      AREA Example, CODE, READONLY @聲明程式碼片段Example           EXPORT strcopy          @聲明strcopy,以便外部函數調用strcopy     @ R0為目標字串的地址, R1為源字串的地址           LDRB R2, [R1], #1    @讀取位元組資料,源地址加1           STRB R2, [R0], #1    @儲存讀取的1位元組資料,目標地址加1           CMP R2, #0           @判斷字元是否複製完畢           BNE strcopy          @沒有複製完,繼續迴圈複製           MOV PC, LR 

4.3 組譯工具調用C程式

      組譯工具設定要遵循APTCS規則,保證程式調用時參數的正確傳遞。組譯工具調用C程式的方法如下:
      1) 在組譯工具中使用IMPORT偽指令聲明將要調用的C程式函數。
      2) 在調用C程式時,要正確設定入口參數,然後使用BL指令調用。

int sum(int a, int b, int c, int d, int e){    return(a+b+c+d+e); //返回5個變數的和}

      AREA Example, CODE, READONLY          IMPORT sum      @ 聲明外部標號sum,即C函數sum()          EXPORT CALLSUMCALLSUM          STMFD SP!, {LR}    @LR寄存器入棧          MOV R0, #1         @設定sum函數入口參數,R0為參數a          MOV R1, #2         @R1為參數b          MOV R2, #3         @R2為參數c          MOV R3, #5         @參數 e=5,儲存到堆棧中          STR R3, {SP, #-4}!          MOV R3, #4         @R3為參數d, d=4          BL sum             @調用C程式中的sum函數,結果放在R0中          ADD SP, SP, #4     @調整堆棧指標          LDMFD SP, {PC}     @程式返回     END

     以上程式使用了5個參數,分別使用寄存器R0儲存第1個參數,R1儲存第2個參數,R2儲存第3個參數,R3儲存第4個參數,第5個參數利用堆棧傳送。由於利用了堆棧傳遞參數,在程式調用結束後要調整堆棧指標。組譯工具中調用了C程式的sum子函數,實現了1+2+3+4+5,最後相加結果儲存在R0寄存器中。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.