zoukankan      html  css  js  c++  java
  • 关于C语言和汇编语言相互嵌套调用

    1、C嵌套汇编

          首先说一下关于GCC编译嵌有汇编语言的c语言吧,GCC编译的汇编语言不是我们上课时学的Intel x86汇编,而是AT&T汇编,两者的区别可以查看《Gcc使用的内嵌汇编语法格式小教程》。

            下面是内嵌汇编的格式:语法:__asm__(“instruction

                                                                        ……  instruction"); //Linux gcc中支持(注意asm的下划线均为两个否则GCC将会无法编译。)

    __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 ”:”+r”(a):”r”(b)

                  );

    return (c);

    }

    int main()

    {int a,b,c;

     a=2;

     b=1;

     c=plus(a,b);

     printf(“c=%d ”,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 ",a);

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

        return 0;

    }

     一定要注意例1与例2中汇编语言的语法格式。

    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: ");

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

            strcopy(dststr,srcstr);

            printf("After copying: ");

            printf("  '%s'   '%s' ",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语言中声明字符串时末尾被自动的添加了一个),这里需要注意的是,此时寄存器r0的值为指向源字符串末尾的’’的地址值,而寄存器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                ;注意!!汇编代码编写时一定要缩进,否则编译将会出错

       

    3、汇编调用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寄存器中。

  • 相关阅读:
    【转】C#中Serializable序列化实例详解
    【转】c# [Serializable]的作用
    【转】垂直分库和水平分库
    js数组歌
    好用的漂浮广告 jquery
    详解Vue 开发模式下跨域问题
    老项目用webpack中文乱码问题解决记录
    Vuex异步请求数据通过computed计算属性值
    js数组操作
    Vuex速学篇:(2)利用state保存新闻数据
  • 原文地址:https://www.cnblogs.com/getyoulove/p/3677418.html
Copyright © 2011-2022 走看看