C/汇编的混合编程

时间:2022-02-15 18:31:19

APTCS(arm/thumb程序调用规范)PCS规定了应用程序的函数可以如何分开地写,分开地编译,最后将它们连接在一起,所以它实际上定义了一套有关过程(函数)调用者与被调用者之间的协议。协议规定:调用函数如何传递参数(即压栈方法,以何种方式存放参数),被调用函数如何获取参数,以何种方式传递函数返回值。

 

1. APTCS使用规则

最主要的一条:子程序通过寄存器R0~R3来传递参数. 这时寄存器可以记作:A1~A4 , 被调用的子程序在返回前无需恢复寄存器R0~R3的内容.如果需要更多的参数,将使用堆栈。

 

2. 汇编调用c语言,流程如下:

1) 必须初始化栈

2) b main

3)如果要传参,r0 --->给main()的第1个参数,依次类推

4)c函数的返回值也通过r0、r1、r2依次类推返回

 

3. c语言调用汇编,流程如下:

1)汇编函数要 .global mystrcpy

2)c文件要extern intmystrcpy(char *,char*);

3)如果要传递参数

      第1个参数-----》r0

      第2个参数-----》r1

如果参数超过4个 多余的参数就压栈

4)汇编函数有返回值 通过r0返回

示例代码:

C文件代码:

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

int main(void)

{

       Mystrcpy(desr,src);

}

S文件代码:

.global mystrcopy

.text

mystrcopy:

       LDRBr2, [r1], #1

       STRBr2, [r0], #1

       CMPr2, #0

       BNEmystrcopy

       MOVpc, lr

       END

 

4. GCC 内联汇编

1gcc通过关键字“asm”来声明内联汇编

2)允许使用一些不能由编译器自动生成的指令:

MSR / MRS

新的指令

协处理器指令

3)通常在关联的内嵌函数中使用

4)使用C变量代替寄存器

5)内嵌汇编语法格式:

内嵌汇编语法如下:
   __asm__(汇编语句模板:
输出部分: 输入部分: 破坏描述部分)
    共四个部分:汇编语句模板,输出部分,输入部分,破坏描述部分,各部分使用“:”格开,汇编语句模板必不可少,其他三部分可选,如果使用了后面的部分,而前面部分为空,也需要用“:”格开,相应部分内容为空。例如:
   __asm__ __volatile__("cli": : :"memory")

1、汇编语句模板

    汇编语句模板由汇编语句序列组成,语句之间使用“;
”、“/n”或“/n/t”分开。指令中的操作数可以使用占位符引用C语言变量,操作数占位符最多10个,名称如下:%0、 %1 ...... %9。

2、输出部分
    输出部分描述输出操作数,不同的操作数描述符之间用逗号格开,每个操作数描述符由限定字符串和C 语言变量组成。每个输出操作数的限定字符串必须包含“=”表示他是一个输出操作数。

3、输入部分
    输入部分描述输入操作数,它的语法跟输出部分一样,只不过不需带“=”。

4、限制字符

 

具体来看一下示例代码学习:

    int sum,a,b;

    a = 1;

    b = 2;

 

    asmvolatile(

           "add%0,%1,%2\n\t"

           :"=r"(sum)

           :"r"(a),"r"(b)

           :"memory"

    );

    printf("sum =%d\n",sum);

    打印结果为3。

 

1volatile用于告诉编译器,这里严禁优化。

2sum对应%0a 对应%1b对应%2

3 memory 强制 gcc 编译器假设RAM 所有内存单元均被汇编指令修改,这样 cpu 中的 registers cache 中已缓存的内存单元中的数据将作废。cpu 将不得不在需要的时候重新读取内存中的数据。这就阻止了 cpu 又将 registers, cache 中的数据用于去优化指令,而避免去访问内存。