關於C語言和彙編語言相互嵌套調用

一、C嵌套匯編linux

      首先說一下關於GCC編譯嵌有彙編語言的c語言吧,GCC編譯的彙編語言不是咱們上課時學的Intel x86彙編,而是AT&T彙編,二者的區別能夠查看《Gcc使用的內嵌彙編語法格式小教程》。編程

        下面是內嵌彙編的格式:語法:__asm__(「instruction函數

                                                                    ……  instruction"); //Linux gcc中支持(注意asm的下劃線均爲兩個不然GCC將會沒法編譯。)oop

 

__asm{指針

           instruction調試

          instruction教程

         };   //ADS中支持(注意asm的下劃線均爲兩個不然GCC將會沒法編譯。)內存

 

asm(「instruction [; instruction]」);   //ARM C++中使用 開發

 

例1是我在linux環境下,編的嵌有彙編程序的c語言,並經過了GCC的編譯:字符串

例1:

#include<stdio.h>

int plus(int a,int b)

{

 

__asm__

              (

              「add %1,%0\n\t」:」+r」(a):」r」(b)

              );

return (c);

}

 

int main()

{int a,b,c;

 a=2;

 b=1;

 c=plus(a,b);

 printf(「c=%d\n」,c);

}

這個程序應該是很簡單的,但關鍵是子函數中嵌入的那段彙編程序,具體的寫法能夠參看其餘文章。

例2一樣是c語言中嵌入了彙編,與例1不一樣的是,這個程序的編譯環境爲ADS。

例2

#include <stdio.h>

void  my_strcpy(char* src, const char* dst){

         int ch;

         __asm{

loop:

       LDRB        ch, [src], #1

       STRB   ch, [dst], #1

       CMP     ch, #0

       BNE    loop

        };

}

 

int main(void){

    const char* a = "Hello World!";

    char   b[20];

    __asm{

       MOV    R0, a

       MOV    R1, b

       BL           my_strcpy, {R0, R1}

    };

    printf("Original String: %s\n",a);

    printf("Copied String: %s\n",b);

    return 0;

}

 必定要注意例1與例2中彙編語言的語法格式。

 

二、C語言調用匯編

 再說一下如何將一個c語言文件與一個彙編文件經過ADS環境編譯,並經過ATX進行DEBUG調試的。先看一下下面的例3。

例3

Cfile.c

#include <stdio.h>

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

 

int main()

{       const char *srcstr = "abcde";

        char dststr[32];

        /* dststr is an array since we're going to change it */

 

        printf("Before copying:\n");

        printf("  '%s'\n  '%s'\n",srcstr,dststr);

        strcopy(dststr,srcstr);

        printf("After copying:\n");

        printf("  '%s'\n  '%s'\n",srcstr,dststr);

        return 0;

}

 

Asmfile.s

AREA    SCopy, CODE, READONLY

 

        EXPORT strcopy

strcopy                

        ; r0 points to destination string

        ; r1 points to source string

        LDRB    r2, [r1],#1     ; load byte and update address

        STRB    r2, [r0],#1     ; store byte and update address;

        CMP     r2, #0          ; check for zero terminator

        BNE     strcopy         ; keep going if not

        MOV     pc,lr           ; Return

 

        END            ;注意!!彙編代碼編寫時必定要縮進,不然編譯將會出錯

    這是一個c語言調用匯編的例子,功能是爲了實現字符串的拷貝,其中彙編文件爲字符串拷貝的功能子函數。在這裏須要說明的是c語言調用匯編語言的一些基本規則,首先是參數傳遞的規則,c語言的函數前4個參數經過R0-R3來傳遞,其它參數經過堆棧(FD)傳遞,且這種傳遞是單項的,即彙編語言中的R0-R3的值不會再回傳給c語言。拿例3舉例來講,當在語言中調用strcopy(dststr,srcstr);時,字符串dststr的首地址將會傳給r0,srcstr的首地址將會傳給r1,當彙編語言拿到這兩個寄存器時,就會經過地址依次加1的形式進行地址內容的複製也就是字符串的複製,當複製到最後一個字母e時,經過比較r2寄存器中的值是否爲0來判斷是否調出彙編程序(由於在c語言中聲明字符串時末尾被自動的添加了一個\0),這裏須要注意的是,此時寄存器r0的值爲指向源字符串末尾的’\0’的地址值,而寄存器r1的值爲指向已經拷貝過的目的字符串中的」e」的地址值,當調出彙編程序時,r0,r1這兩個值將不會回傳給strcopy(dststr,srcstr);中的兩個參數dststr和srcstr,這兩個參數的值仍然是c語言在初始化這兩個字符串時指向字符串的首地址,這一點能夠經過ATX調試時觀察寄存器的變化狀況來證實。可是爲何地址值沒有變化,但卻實現了字符串的拷貝了呢?這主要時由於經過彙編程序,雖然沒有改變兩個指針的位置,但卻改變了兩個字符串所在內存地址中的內容,這種方式就是c語言中常說的引用方式,即dststr和r0起初指向的是同一內存空間,可是字符串複製時只是利用r0來複制的,而dststr的位置卻沒有發生變化。所以在c語言中輸出字符串時並不須要將dststr減去字符串的個數來實現指向字符串的首地址。

    這個程序中第二個須要注意的地方是,彙編程序段中的起到臨時存放字符串的r2寄存器,很奇怪的是這個地方的寄存器不能換成r4,若是換成r4的話,輸出的結果就會有問題,這一點我如今尚未找到答案,但願未來某一天能碰見高人給我指點一下。

最後須要注意的地方是在彙編程序末尾必定要加上MOV  pc, lr

    用ADS編譯後,兩個文件會被自動的連接,並在工程文件夾下生成一個.o文件,這個文件就是未來要下到開發板上的二進制文件,其中還有一個.axf的鏡像文件,這個文件是用來進行ATX調試的,默認的單步調試是在反彙編中進行的,這就會給調試程序帶來極大的不便,經過本身的摸索,發現能夠經過設置strong source實如今c語言中進行單步調試,兩外在單步調試中經過watch來觀察c語言中的形參的值和地址的變化狀況,便於程序的調試,須要強調的一點時,彙編程序與c程序的文件名不能相同,不然將沒法用ATX進行調試。

    另外,在彙編程序中訪問c程序全局變量的例子。程序中變量globvl是在c程序中聲明的全局變量。在彙編程序中首先用IMPORT僞操做聲明該變量;再將其內存地址讀入到寄存器R1中;再將其值讀入到寄存器R0中;修改後再將寄存器R0的值賦於變量globvl。請參看例4

例4

#include <stdio.h>

int  globvl;

int main(){

 globvl = 0;

    asmsub();

   printf(「globvl = %d」, globvl);

     return 0;

}

 

AREA  globals, CODE, READONLY

       EXPORT asmsub

       IMPORT globvl

       asmsub

       LDR  r1,  =globvl

       LDR  r0, [r1]

 

ADD  r0, r0, #2

       STR  r0, [r1]

       MOV  pc, lr

       END                ;注意!!彙編代碼編寫時必定要縮進,不然編譯將會出錯

 

   

三、彙編調用c

最後我再談一下如何在彙編中調用c,看一下例5

例5

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

{

return a + b + c + d + e;

}

 

;彙編程序調用c程序g()計算5個整數i, 2*i, 3*i, 4*i, 5*i的和

EXPORT f

AREA  f, CODE, READONLY

IMPORT  g                 ;使用僞操做數IMPORT聲明c程序g()

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

ADD  r1, r0, r0          ;假設進入程序f時,r0中的值爲i,r1值設爲2*i

ADD  r2, r1, r0          ;r2的值設爲3*i

ADD  r3, r1, r2        ;r3的值設爲5*i

STR  r3, [sp, # -4]!     ;第五個參數5*i經過數據棧傳遞

ADD  r3, r1, r1        ;r4值設爲4*i

BL   g        ;調用c程序g()

ADD  sp, sp, #4              ;調整數據棧指針,準備返回

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

END                 ;注意!!彙編代碼編寫時必定要縮進,不然編譯將會出錯

 

注意,c語言最終返回的五個數之和放到了r0寄存器中。

相關文章
相關標籤/搜索