加入星計(jì)劃,您可以享受以下權(quán)益:

  • 創(chuàng)作內(nèi)容快速變現(xiàn)
  • 行業(yè)影響力擴(kuò)散
  • 作品版權(quán)保護(hù)
  • 300W+ 專業(yè)用戶
  • 1.5W+ 優(yōu)質(zhì)創(chuàng)作者
  • 5000+ 長(zhǎng)期合作伙伴
立即加入
  • 正文
    • 12.4  C、C++ 和 ARM 匯編語(yǔ)言之間的調(diào)用
  • 相關(guān)推薦
  • 電子產(chǎn)業(yè)圖譜
申請(qǐng)入駐 產(chǎn)業(yè)圖譜

混合使用C、C++和匯編語(yǔ)之: C、C++ 和 ARM 匯編語(yǔ)言之間的調(diào)用

2013/09/30
1
閱讀需 21 分鐘
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點(diǎn)資訊討論

 

12.4  C、C++ 和 ARM 匯編語(yǔ)言之間的調(diào)用

本節(jié)提供一些示例,顯示如何從C++調(diào)用C和匯編語(yǔ)言代碼,以及從C和匯編語(yǔ)言調(diào)用 C++ 代碼。其中包括調(diào)用約定和數(shù)據(jù)類型。主要包括下面內(nèi)容:

·  相互調(diào)用的一般規(guī)則;

·  C++語(yǔ)言的特定信息;

·  調(diào)用示例。

只要遵循正確的過(guò)程調(diào)用標(biāo)準(zhǔn)AAPCS,就可以混合調(diào)用C、C++和匯編語(yǔ)言例程。有關(guān) AAPCS 的更多信息,請(qǐng)參閱ARM相關(guān)文檔。

12.4.1  相互調(diào)用的一般規(guī)則

以下一般規(guī)則適用于C、C++和匯編語(yǔ)言之間的調(diào)用。有關(guān)的詳細(xì)信息,請(qǐng)參閱ARM開(kāi)發(fā)相關(guān)文檔。

嵌入式匯編程序以及其與ARM嵌入式應(yīng)用程序二進(jìn)制接口(BSABI,Application Binary Interface for the ARM Architecture)的兼容使得混合語(yǔ)言編程更易于實(shí)現(xiàn)。它們可提供以下功能:

·  使用__cpp關(guān)鍵字進(jìn)行名稱延伸;

·  傳遞隱含this參數(shù)的方式;

·  調(diào)用虛函數(shù)的方式;

·  引用的表示;

·  具有基類或虛成員函數(shù)的C++類的類型布局;

·  非POD(Plain Old Data)結(jié)構(gòu)的類對(duì)象傳遞。

以下一般規(guī)則適用于混合語(yǔ)言編程:

·  使用C調(diào)用約定。

·  在C++中,非成員函數(shù)可以聲明為extern "C",以指定它們有C鏈接。帶有C鏈接意味著定義函數(shù)的符號(hào)未延伸。C鏈接可以用于以一種語(yǔ)言實(shí)現(xiàn)函數(shù),然后用另一種語(yǔ)言調(diào)用它。

·  匯編語(yǔ)言模塊所必須符合的AAPCS調(diào)用標(biāo)準(zhǔn),應(yīng)當(dāng)適合于應(yīng)用程序所使用的存儲(chǔ)器模型。

以下規(guī)則適用于從C和匯編語(yǔ)言調(diào)用C++函數(shù):

·  要調(diào)用全局(非成員)C++函數(shù),應(yīng)將它聲明為extern "C",以提供C鏈接。

·  成員函數(shù)(靜態(tài)和非靜態(tài))總是有已延伸的名稱。使用嵌入式匯編程序的__cpp關(guān)鍵字,可以不必手工尋找已延伸的名稱。

·  不能從C調(diào)用C++內(nèi)聯(lián)函數(shù),除非確保C++編譯器生成了函數(shù)的外聯(lián)副本。例如,取得函數(shù)地址將導(dǎo)致生成外聯(lián)副本。

·  非靜態(tài)成員函數(shù)接受隱含this參數(shù)作為r0中的第一個(gè)自變量,或作為r1中第二個(gè)自變量(如果函數(shù)返回非int類結(jié)構(gòu))。靜態(tài)成員函數(shù)不接受隱含this參數(shù)。

12.4.2  C++的特定信息

本節(jié)主要介紹一些專門適用于C++的內(nèi)容。

(1)C++調(diào)用約定

ARM C++使用與ARM C相同的調(diào)用約定,但在下面的情況下,調(diào)用規(guī)則有所不同:

·  調(diào)用非靜態(tài)成員函數(shù)時(shí),隱含的this參數(shù)是第一個(gè)自變量,或者是第二個(gè)自變量(如果被調(diào)用函數(shù)返回非int類的struct)。這可能在將來(lái)的版本中有所變化。

(2)C++數(shù)據(jù)類型

ARM C++使用與ARM C相同的數(shù)據(jù)類型,但在以下幾種情況下,情況有所不同:

·  如果struct或class類型的C++對(duì)象沒(méi)有基類或虛函數(shù),則它們的布局與ARM C相同。如果這樣的struct沒(méi)有用戶定義的復(fù)制賦值運(yùn)算符或用戶定義的析構(gòu)函數(shù),則它是POD結(jié)構(gòu)。

·  引用表示為指針。

·  C函數(shù)指針和C++(非成員)函數(shù)指針沒(méi)有區(qū)別。

(3)符號(hào)名稱延伸

鏈接程序?qū)⑷∠畔⒅蟹?hào)名稱的延伸。

在C++程序中,C名稱必須聲明為extern "C"。ARM ISO C頭文件已經(jīng)完成此操作。詳細(xì)信息請(qǐng)參閱ARM相關(guān)文檔。

12.4.3  混合編程調(diào)用舉例

匯編程序、C程序以及C++程序相互調(diào)用時(shí),要特別注意遵守相應(yīng)的AAPCS。下面一些例子具體說(shuō)明了在這些混合調(diào)用中應(yīng)注意遵守的AAPCS規(guī)則。這些示例程序默認(rèn)為使用非軟件棧檢查的ATPCS規(guī)則,因?yàn)樗鼈儓?zhí)行棧操作時(shí)不檢查棧溢出。

(1)從C調(diào)用匯編語(yǔ)言

下面的程序顯示如何在C程序中調(diào)用匯編語(yǔ)言子程序,該段代碼實(shí)現(xiàn)了將一個(gè)字符串復(fù)制到另一個(gè)字符串。

#include <stdio.h>

extern void strcopy(char *d, const char *s);

int main()

{   const char *srcstr = "First string - source ";

    char dststr[] = "Second string - destination ";

/* 下面將dststr作為數(shù)組進(jìn)行操作 */

    printf("Before copying:n");

    printf("  %sn  %sn",srcstr,dststr);

    strcopy(dststr,srcstr);

    printf("After copying:n");

    printf("  %sn  %sn",srcstr,dststr);

    return (0);

}

下面為調(diào)用的匯編程序。

    PRESERVE8

    AREA    SCopy, CODE, READONLY

    EXPORT strcopy

Strcopy ;r0指向目的字符串

;r1指向源字符串

    LDRB r2, [r1],#1 ;加載字節(jié)并更新源字符串指針地址

    STRB r2, [r0],#1 ;存儲(chǔ)字節(jié)并更新目的字符串指針地址

    CMP r2, #0 ;判斷是否為字符串結(jié)尾

    BNE strcopy ;如果不是,程序跳轉(zhuǎn)到strcopy繼續(xù)拷貝

    MOV pc,lr ;程序返回

    END

按以下步驟從命令行編譯該示例:

① 輸入armasm -g scopy.s編譯匯編語(yǔ)言源代碼。

② 輸入armcc -c -g strtest.c編譯C源代碼。

③ 輸入armlink strtest.o scopy.o -o strtest鏈接目標(biāo)文件。

④ 將ELF/DWARF2兼容調(diào)試器與相應(yīng)調(diào)試目標(biāo)配合使用,運(yùn)行映像。

 

(2)匯編語(yǔ)言調(diào)用C程序

下面的例子顯示了如何從匯編語(yǔ)言調(diào)用C程序。

下面的子程序段定義了C語(yǔ)言函數(shù)。

int g(int a, int b, int c, int d, int e) 

{

                return a + b + c + d + e;

}

下面的程序段顯示了匯編語(yǔ)言調(diào)用。假設(shè)程序進(jìn)入f時(shí),r0中的值為i。

  ; int f(int i) { return g(i, 2*i, 3*i, 4*i, 5*i); }

  PRESERVE8

  EXPORT f

  AREA f, CODE, READONLY

  IMPORT g // 聲明C程序g()

  STR lr, [sp, #-4]! // 保存返回地址 lr

  ADD r1, r0, r0 // 計(jì)算2*i(第2個(gè)參數(shù))

  ADD r2, r1, r0 // 計(jì)算3*i(第3個(gè)參數(shù))

  ADD r3, r1, r2 // 計(jì)算5*i

  STR r3, [sp, #-4]! // 第五個(gè)參數(shù)通過(guò)堆棧傳遞

  ADD r3, r1, r1 // 計(jì)算4*i(第4個(gè)參數(shù))

  BL g // 調(diào)用C程序

  ADD sp, sp, #4 // 從堆棧中刪除第5個(gè)參數(shù)

  LDR pc, [sp], #4 // 返回

  END

(3)從C++調(diào)用C

下面的例子顯示了如何從C++程序中調(diào)用C函數(shù)。

下面的C++程序調(diào)用了C程序。

struct S { // 本結(jié)構(gòu)沒(méi)有基類和虛函數(shù)

      S(int s):i(s) { }

      int i;

};

extern "C" void cfunc(S *); 

// 被調(diào)用的C函數(shù)使用extern“C”聲明

int f(){

       S s(2); // 初始化 's'

       cfunc(&s); // 調(diào)用C函數(shù) 'cfunc' 將改變 's'

       return si*3;

}

下面顯示了被調(diào)用的C程序代碼。

struct S {

      int i;

};

void cfunc(struct S *p) {

/*定義被調(diào)用的C功能 */

      p->i += 5;

}

(4)從C++中調(diào)用匯編

下面的例子顯示了如何從C++中調(diào)用匯編程序。

下面的例子為調(diào)用匯編程序的C++代碼。

struct S { // 本結(jié)果沒(méi)有基類和虛擬函數(shù)

// 

      S(int s) : i(s) { }

      int i;

};

extern "C" void asmfunc(S *); // 聲明被調(diào)用的匯編函數(shù)

int f() {

       S s(2); // 初始化結(jié)構(gòu)體 's'

       asmfunc(&s); // 調(diào)用匯編子程序 'asmfunc' 

       return s.i * 3;

}

下面是被調(diào)用的匯編程序。

     PRESERVE8

     AREA Asm, CODE

     EXPORT asmfunc

asmfunc                // 被調(diào)用的匯編程序定義

     LDR r1, [r0]       

     ADD r1, r1, #5

     STR r1, [r0]

     MOV pc, lr

     END

(5)從C中調(diào)用C++

下面的例子顯示了如何從C++代碼中調(diào)用C程序。

下面的代碼顯示了被調(diào)用C++代碼。

struct S {        // 本結(jié)構(gòu)沒(méi)有基類和虛擬函數(shù)

      S(int s) : i(s) { }

      int i;

};

extern "C" void cppfunc(S *p) {    

// 定義被調(diào)用的C++代碼

// 連接了C功能

      p->i += 5;                //

}

調(diào)用了C++代碼的C函數(shù)。

struct S {

      int i;

};

extern void cppfunc(struct S *p); 

/* 聲明將會(huì)被調(diào)用的C++功能 */

int f(void) {

       struct S s;

       s.i = 2;                /* 初始化S */

       cppfunc(&s);            /* 調(diào)用cppfunc函數(shù),該函數(shù)可能改變S的值 */

       return s.i * 3;

}

 

(6)從匯編中調(diào)用C++程序

下面的代碼顯示了如何從匯編中調(diào)用C++程序。

下面是被調(diào)用的C++程序。

struct S {           // 本結(jié)構(gòu)沒(méi)有基類和虛擬函數(shù)

      S(int s) : i(s) { }

      int i;

};

extern "C" void cppfunc(S * p) {

// 定義被調(diào)用的C++功能

// 功能函數(shù)體

      p->i += 5;

}

在匯編語(yǔ)言中,聲明要調(diào)用的C++功能,使用帶連接的跳轉(zhuǎn)指令調(diào)用C++功能。

    AREA Asm, CODE

    IMPORT cppfunc ;聲明被調(diào)用的 C++ 函數(shù)名

    EXPORT   f

f

    STMFD  sp!,{lr}

    MOV    r0,#2

    STR    r0,[sp,#-4]! ;初始化結(jié)構(gòu)體

    MOV    r0,sp ;調(diào)用參數(shù)為指向結(jié)構(gòu)體的指針

    BL     cppfunc ;調(diào)用C++功能'cppfunc' 

    LDR    r0, [sp], #4

    ADD    r0, r0, r0,LSL #1

    LDMFD  sp!,{pc}

    END

(7)在C和C++函數(shù)間傳遞參數(shù)

下面的例子顯示了如何在C和C++函數(shù)間傳遞參數(shù)。

下面的代碼為C++函數(shù)。

extern "C" int cfunc(const int&); 

// 聲明被調(diào)用的C函數(shù)

extern "C" int cppfunc(const int& r) {

// 定義將被C調(diào)用的C++函數(shù)

      return 7 * r;

}

int f() {

      int i = 3;

      return cfunc(i); // 相C函數(shù)傳參

}

下面為C函數(shù)。

extern int cppfunc(const int*);    

/* 聲明將被調(diào)用的C++函數(shù) */

int cfunc(const int *p) {       

/*定義被C++調(diào)用的C函數(shù)*/

     int k = *p + 4;

     return cppfunc(&k);

}

(8)從C或匯編語(yǔ)言調(diào)用C++

下面的例子綜合顯示了如何從C或匯編語(yǔ)言中調(diào)用非靜態(tài)、非虛的C++成員函數(shù)??梢允褂镁幾g器編譯出的匯編程序查找已延伸的函數(shù)名。

下面是被調(diào)用的C++成員函數(shù)。

struct T {

      T(int i) : t(i) { }

      int t;

      int f(int i);

};

int T::f(int i) { return i + t; }   

// 定義將被C調(diào)用的C++功能函數(shù)

extern "C" int cfunc(T*);

// 聲明將被C++調(diào)用的C函數(shù)

int f() {

      T t(5);                    // create an object of type T

      return cfunc(&t);

}

下面為調(diào)用C++的C語(yǔ)言函數(shù)。

struct T;

extern int _ZN1T1fEi(struct T*, int);

      /* 被調(diào)用的C++函數(shù)名 */

int cfunc(struct T* t) {   

/* 定義被C++調(diào)用的C函數(shù) */

      return 3 * _ZN1T1fEi(t, 2);    /* 實(shí)現(xiàn)3乘以t->f(2)功能 */

}

下面為調(diào)用C++的匯編函數(shù)。

     EXPORT cfunc

     AREA foo, CODE

     IMPORT  _ZN1T1fEi

cfunc

     STMFD   sp!,{lr} ;此時(shí)r0已經(jīng)包含了指向?qū)ο蟮闹羔?/p>

     MOV r1, #2

     BL _ZN1T1fEi

     ADD r0, r0, r0, LSL #1 ;r0乘以3

     LDMFD sp!,{pc}

     END

下面的例子顯示了如何用嵌入式匯編語(yǔ)言實(shí)現(xiàn)上面的例子。在此例中,使用 __cpp 關(guān)鍵字引用該函數(shù)。因此,用戶不必了解已延伸的函數(shù)名。

struct T {

     T(int i) : t(i) { }

     int t;

     int f(int i);

};

int T::f(int i) { return i + t; }

// 定義被C++調(diào)用的匯編功能

__asm int asm_func(T*) {

    STMFD sp!, {lr}

    MOV r1, #2;

    BL __cpp(T::f);

    ADD r0, r0, r0, LSL #1 ;r0乘以3

    LDMFD sp!, {pc}

}

int f() {

      T t(5); // 創(chuàng)建T類型的對(duì)象

      return asm_func(&t);

}

聯(lián)系方

Arm

Arm

ARM公司是一家知識(shí)產(chǎn)權(quán)(IP)供應(yīng)商,主要為國(guó)際上其他的電子公司提供高性能RISC處理器、外設(shè)和系統(tǒng)芯片技術(shù)授權(quán)。目前,ARM公司的處理器內(nèi)核已經(jīng)成為便攜通訊、手持計(jì)算設(shè)備、多媒體數(shù)字消費(fèi)品等方案的RISC標(biāo)準(zhǔn)。公司1990年11月由Acorn、Apple和VLSI合并而成。

ARM公司是一家知識(shí)產(chǎn)權(quán)(IP)供應(yīng)商,主要為國(guó)際上其他的電子公司提供高性能RISC處理器、外設(shè)和系統(tǒng)芯片技術(shù)授權(quán)。目前,ARM公司的處理器內(nèi)核已經(jīng)成為便攜通訊、手持計(jì)算設(shè)備、多媒體數(shù)字消費(fèi)品等方案的RISC標(biāo)準(zhǔn)。公司1990年11月由Acorn、Apple和VLSI合并而成。收起

查看更多

相關(guān)推薦

電子產(chǎn)業(yè)圖譜

華清遠(yuǎn)見(jiàn)(www.farsight.com.cn)是國(guó)內(nèi)領(lǐng)先嵌入師培訓(xùn)機(jī)構(gòu),2004年注冊(cè)于中國(guó)北京海淀高科技園區(qū),除北京總部外,上海、深圳、成都、南京、武漢、西安、廣州均有直營(yíng)分公司。華清遠(yuǎn)見(jiàn)除提供嵌入式相關(guān)的長(zhǎng)期就業(yè)培訓(xùn)、短期高端培訓(xùn)、師資培訓(xùn)及企業(yè)員工內(nèi)訓(xùn)等業(yè)務(wù)外,其下屬研發(fā)中心還負(fù)責(zé)嵌入式、Android及物聯(lián)網(wǎng)方向的教學(xué)實(shí)驗(yàn)平臺(tái)的研發(fā)及培訓(xùn)教材的出版,截止目前為止已公開(kāi)出版70余本嵌入式/移動(dòng)開(kāi)發(fā)/物聯(lián)網(wǎng)相關(guān)圖書(shū)。企業(yè)理念:專業(yè)始于專注 卓識(shí)源于遠(yuǎn)見(jiàn)。企業(yè)價(jià)值觀:做良心教育、做專業(yè)教育,更要做受人尊敬的職業(yè)教育。