C語言與組合語言的相互調用

來源:互聯網
上載者:User
C語言是目前非常流行的一種程式設計語言,除具有進階語言使用方便靈活、資料處理能力強、 編程簡單等優點外,還可實現組合語言的大部分功能,如可直接對硬體進行操作、產生的 目標代碼品質較高且執行的速度較快等。所以在工程上對硬體處理速度要求不很高的情況下, 基本可以用C代替組合語言,編寫介面電路的控制軟體。但C也不能完全取代組合語言,如在一些對速度要求很高的即時控制系統中,以及對硬體的特殊控制方面,C有時也不能完全很好勝任,還需要組合語言來編寫。因為組合語言目標代碼更精練,對硬體直接控制能力更強和執行速度更快,但組合語言編程煩難、表達能力差也顯而易見。比較好的解決辦法是C與組合語言混合編程,即用C編寫軟體的發送器、使用者介面以及速度要求不高的控制部分,而用組合語言對速度敏感部分提供最高速度的處理模組,供C調用。這種方法提供了最佳的軟體設計方案,做到了兼顧速度效率高和靈活方便。由於本人的畢業設計需要C程式中調用彙編模組的方法來提高ARM定點指令的執行速度,故對這方面進行了學習。學習心得如下:

對於C和組合語言的介面主要有兩個問題需要解決。
     一、調用者與被調用者的參數傳遞
     這種資料傳遞通過堆棧完成,在執行調用時從調用程式參數表中的最後一個參數開始 ,自動依次壓入堆棧;將所有參數壓入堆棧後,再自動將被調用程式執行結束後的返回地址 (斷點)壓入堆棧,以使被調程式結束後能返回主調程式的正確位置而繼續執行。例如一調用名為add組譯工具模組的主函數:main(  ){...... add(dest,op1,op2,flages);......}。在此例中對主函數進行反組譯碼,主函數在調用add函數前自動組織的堆棧。
.
.
.
  lea 0xfffffffe8(%ebp),%eax   #flages數組的首地址入棧
  push %eax
  pushl 0xfffffff8(%ebp)       #OP2入棧
  pushl 0xfffffffc(%ebp)       #OP1 入棧
  pushl 0xfffffff0(%ebp)       #dest地址入棧
  call 0x80483f0 <add>      #調用add函數
.
.
執行完add調用語句後,棧內資料結果一所示。

進入彙編子程式後,為了能正確擷取主調程式並存入堆棧中的資料,被調的彙編子程式先後要做如下一些工作:
    1、 儲存esp的副本
進入彙編子程式後,子程式中免不了要有壓棧和出棧的操作,故ESP時刻在變化。為了能用 ESP訪問堆棧中的參數,安全辦法是一進入子程式後,先為ESP制副本,以後對傳遞參數的訪問 都用副本進行。一般可用EBP儲存ESP,如:
push  %ebp  
mov %ebp,%esp
     2、保留資料空間
如果彙編子程式中需要一些局部資料,可以簡單地減小ESP的值,以便在棧空間中保留出一段存貯區,用於存放局部資料,該地區須在子程式結束後恢複。如下語句可以保留一個局部資料區:
push %ebp
mov %ebp ,%esp
subl space,%esp;設space=4
movl $0x0,%ebp
movl $0x0,-2(%ebp)
     如上語句段中,space是局部資料的總位元組數。在以後的應用中,由於ESP是變化的,而 EBP是 固定的,用負位移量可以存取局部變數。上例利用EBP及位移量,將兩個字的局部數 據初始化為0。
     3、保留寄存器值
     如果在被調子程式中用到ESI、EDI等其它寄存器,則應先把它們壓入堆棧,以保留寄存器原值 。例如,下例就是將ESI和EDI寄存器的值壓棧:
pushl %ebp
movl %ebp ,%esp
subl $space ,%esp,
pushl %esi  
pushl %edi
     4、擷取傳遞參數
作完了1~3步的操作後,結合上面C程式傳送參數這一例子,現在棧結構二所示。

由此可見,EBP保留了ESP在參數傳遞完並將EBP壓棧後的一個副本,利用EBP可以很方便地訪問各參數。現假設各參數都是2位元組的整數值,在小模式編譯方式共佔用2個位元組。如果要將傳遞的參數op1、op2取出,並分別賦給ebx、ecx寄存器,可由下列陳述式完成這一功能:
movl 0x8(%ebp),%eax
movl 0xc(%ebp),%ecx
     5、子程式傳回值
     當子程式的執行結果需要返回時,根據傳回值的字長,C按如下約定接收傳回值:1位元組在AL 寄存器中;2位元組在EAX寄存器中;4位元組則高位部分在EDX中、低位部分在EAX寄存器中。C可從這些寄存器中取出傳回值。
     6、退出彙編子程式
     結束彙編子程式的步驟如下:
     1) 若ESS、EDS、ESI或EDI已被壓棧,則需按儲存它們的相反順序彈出它們。
     2) 若在過程開始時分配了局部資料空間,則以指令 mov %esp和%ebp 恢複%esp。
     3) 以指令pop %ebp 恢複%ebp ,該步是必須的。或者可以用leave語句來恢複%ebp 。它相當於movl  %ebp, %esp; popl %ebp
     4) 最後以ret結束組譯工具。
     二、 說明和建立調用者與被調用者間的連繫
     為了建立調用與被調用模組間的串連關係,被調用的組譯工具應用global,說明其可被外部模組調用;而調用程式則應預先說明要引用的外部模組名。下面通過我的例子進行說明,該例是C調用add0的彙編子程式。程式清單如下:
/*  add.c  */
#include <stdio.h>
extern void add(int *dest,int op1,int op2,short int*flages);
/*聲明調用外部的彙編函數*/
int main(void){
  int op1,op2,result;
  int *dest=&result;
  short int flages[4]={0,0,0,0};
  printf("please enter two soure operater:");
  scanf("%x%x",&op1,&op2);
  add(dest,op1,op2,flages);/*調用add0函數*/
  printf("The result of ADD is :%x/n flages N(negative) Z(zero) C(carry) V(overflow:%d,%d,%d,%d/n",*dest,flages[3],flages[2],flages[1],flages[0]);
  return 0;
}
#add.s
.text
.align 2
.global        add
.type add,function
#定義add為外部可調用的函數
add:       
            push %ebp       #ebp寄存器內容壓棧,儲存add函數的上級調用函數的棧基地址
            mov %esp,%ebp   #esp值賦給ebp,設定add函數的棧基地址
        mov 0x8(%ebp),%edx  
            mov 0x10(%ebp),%eax   
            add 0xc(%ebp),%eax   
            mov %eax,(%edx)      
            mov 0x14(%ebp),%eax   
            jo OF                  
        C:
            jc CF               
        S:
            js SF               
            jz ZF               
            jmp out              
        OF:
            movw $0x1,(%eax)  
            jmp C               
        CF:
            movw $0x1,0x2(%eax)
            jmp S                  
        SF:
            movw $0x1,0x6(%eax)
            movw $0x0,0x4(%eax)   
            jmp out               
        ZF:
            movw $0x1,0x4(%eax)
            movw $0x0,0x6(%eax)   
        out:
        leave               #將ebp值賦給esp,pop先前棧內的上級函數棧的基地址給#ebp,恢複原棧基址
            ret                 #add函數返回,回到上級的調用函數

其中.text 標誌一個程式碼片段的開始,這是AT&T的段格式;global add;/n
type add,function說明add是公用的,可以由外部其它單獨編譯模組調用。
     將C來源程式以檔案名稱add.c存檔,組合語言來源程式以add.s 存檔;通過MAKE進行編譯和串連串連代碼如下:

all: myadd
        myadd: adds.o  addc.o
             gcc –o myadd adds.o adc.o
        adds.o: add.s
             as –o adds.o add.s
        addc.o: add.c
             gcc –g –o addc.o  add.c
     由上可見,在C中調用彙編模組很方便。所以我們在實際軟體開發中,可以採用混合編程的技術,從而儘可能利用各語言的優勢。既滿足實際問題的需要,又簡化設計過程,達到事半功倍的效果。 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.