根据参数个数是否固定,子程序可分为参数个数固定的子程序和参数个数可变的子程序。 这两个子程序的参数传递规则不同。
1. 参数个数可变的子程序的参数传递规则
对于参数个数可变的子程序,当参数不超过4个时,可以使用寄存器R0~R3来传递参数。 当参数超过4个时,还可以使用数据栈来传递参数。 传递参数时,将所有参数视为存储在连续内存单元中的字数据。 然后将各个名称数据依次传送到寄存器R0、R1、R2、R3; 如果参数超过4个,则将剩余的字数据转移到数据栈中,入栈的顺序与参数的顺序相反,即最后一个字数据先入栈。 根据上述规则,浮点参数可以通过寄存器传递,也可以通过数据栈传递,也可以一半通过寄存器传递,另一半通过数据栈传递。
2. 参数数量固定的子程序的参数传递规则
对于参数数量固定的子程序,其参数传递规则与参数数量可变的子程序不同。 如果系统中包含用于浮点运算的硬件组件,则浮点参数将按照以下规则进行传输: 每个浮点参数都是顺序处理的; 为每个浮点参数分配FP寄存器; 分配方式是满足浮点参数需要的数量最小的一组连续的FP寄存器。 第一个整数参数通过寄存器R0~R3传递,其他参数通过数据堆栈传递。
子程序结果返回规则
1. 当结果为32位整数时,可以通过寄存器R0返回。
2、当结果为64位整数时,可通过R0、R1返回,以此类推。
3、当结果为浮点数时,可以通过浮点运算单元的寄存器f0、d0或s0返回。
4. 当结果为复合浮点数时,可以通过寄存器f0-fN 或d0~dN 返回。
5、对于位数较多的结果,需要通过调用内存的方式进行传输。
本文通过几个简单的例子演示了嵌入式开发中常用的C与汇编混合编程的一些方法和基本思想。 其实核心问题是如何在C和汇编之间传递值。 剩下的问题就自己处理吧。
在嵌入式系统的开发中,目前使用的主要编程语言是C和汇编。 C++已经有了相应的编译器,但是仍然很少使用。 在较大规模的嵌入式软件中,例如OS,大部分代码都是用C编写的,主要是因为C语言结构更好,更容易让人理解,并且有大量的支持库。 尽管如此,很多地方还是使用了汇编语言,比如开机时硬件系统的初始化,包括设置CPU状态、使能中断、设置主频,以及RAM控制参数和初始化,以及一些中断处理方面。 还可能涉及组装。 另一个使用汇编的地方是在一些对性能非常敏感的代码块中。 这不能依赖C编译器生成的代码,而必须手动编写汇编来达到优化的目的。 而且,汇编语言与CPU的指令集紧密相连。 作为底层嵌入式系统开发,熟练使用汇编语言也是必须的。
对于纯C或汇编编程,请参考相关书籍或手册。 这里主要讨论C和汇编的混合编程,包括相互之间的函数调用。 下面分四种情况进行讨论,C++暂时不涉及。
1.C语言嵌入式汇编
C 中嵌入的汇编指令包括大部分 ARM 和 Thumb 指令,但它们的使用与汇编文件中的指令有些不同,并且存在一些限制,主要有以下几个方面:
A。 不能直接给PC寄存器赋值。 必须使用B或BL指令跳转到程序。
b. 使用物理寄存器时,不要使用过于复杂的C表达式,以避免物理寄存器冲突。
C。 编译器可以使用 R12 和 R13 来存储中间编译结果。 在计算表达式值时,R0 至 R3、R12 和 R14 可能用于子程序调用,因此请避免直接使用这些物理寄存器。
d. 一般不直接指定物理寄存器,让编译器分配。
内联汇编中使用的标签是__asm或asm关键字,其用法如下:
__asm
[; ]
……
[]
asm(“[;]”);
下面通过一个例子来说明如何在C中嵌入汇编语言。
#
void (const char *src, char *dest)
字符ch;
__asm
环形:
ldrb ch,[源代码],#1
strb ch,[目标],#1
CMP 通道,#0
骨循环
int main()
char *a = "继续前进!";
字符b[64];
(一、二);
(“:%s”,a);
(“:%s”,b);
0;
这里,C和汇编之间的值传递是使用C指针来实现的。 因为指针对应于地址,所以也可以在汇编中访问它们。
2.在汇编中使用C定义的全局变量
内联汇编不需要编辑单独的汇编语言文件,相对简洁,但有很多限制。 当汇编代码较大时,一般放在单独的汇编文件中。 这时,需要在汇编和C之间传递一些数据。最简单的方法就是使用全局变量。
/* cfile.c
* 定义全局变量并作为调用程序
*/
#
整数=12;
(空白);
int main()
(" 的值为:%d", );
();
(" 的值为:%d", );
0;
对应的汇编语言文件
; 通过 main(C 中),到 an ,使用 C 中的 var 。
区号,
ldr r0, =
ldr r1,[r0]
莫夫r2,#2
乘 r3、r1、r2
str r3, [r0]
移动电脑,LR
结尾
3.C语言中调用汇编函数
要在 C 中调用汇编文件中的函数,有两个主要任务要做。 一是在C中声明函数原型并添加关键字; 另一种是在汇编中使用导出的函数名,并使用函数名作为汇编代码。 最后使用 mov pc, lr 返回段的标识符。 然后,就可以在C中使用该函数了。从C的角度来看,不知道该函数是用C实现的还是用汇编实现的。 更深层次的原因是C函数名的作用是指示函数代码的起始地址,与汇编标号一致。
/* cfile.c
* 在C中,调用汇编,
*2004 年 9 月 9 日
*/
#
void (const char *src, char *dest);
int main()
const char *s = "在阳光下";
字符d[32];
(s、d);
(“:%s”,s);
(“:%s”,d);
0;
;汇编
区号,
环形
ldrb r4,[r0],#1; 读后
CMP r4,#0
请求结束
strb r4,[r1],#1
b循环
超过
移动电脑,LR
结尾
这里,C与汇编之间的参数传递是通过ATPCS(ARM Thumb Call)的规定进行的。 简单来说,如果函数的参数不超过4个,则使用R0-R3来传递对应的参数。 如果参数超过4个,则使用堆栈,通过R0返回函数的返回值。
4.在汇编中调用C函数
要在汇编中调用C函数,需要汇编中对应的C函数名称,然后将C代码放在独立的C文件中进行编译,连接器处理剩下的事情。
;来自 ATPCS
;如果参数超过4个,则使用栈
区号,
乐趣
入口
移动 r0,#11
莫夫R1,#22
莫夫R2,#33
BL cFun
结尾
/*C文件,由*/
int cFun(int a, int b, int c)
a+b+c;
在汇编中调用C函数时,参数传递也是通过ATPCS实现的。 需要指出的是,当函数的参数个数大于4时,必须使用栈。 有关详细信息,请参阅 ATPCS 规范。
概括
以上通过几个简单的例子演示了嵌入式开发中常用的C与汇编混合编程的一些方法和基本思想。 其实核心问题是如何在C和汇编之间传递值。 剩下的问题就自己处理吧。 以上只是一个介绍。 更详细、复杂的使用方法应结合实际应用并参考相关资料。
阐明
上述代码在ADS 1.2工程中编译并通过相应AXD中的软件仿真。