一、准备工作
1)创建一个新项目。 2)根据自身情况选择硬件,配置一些参数。 3)为 SOURCE GROUP 1 新建两个文件main.c(C程序)和Func.s(汇编程序)。
二、C语言无参数调用汇编函数
Func.s代码
AREA MY_FUNCTION,CODE,READONLY
EXPORT Init_1 ;
;
Init_1
MOV R1,#0 ;
MOV R2,#0 ;
LOOP ;
CMP R1,#10 ;
BHS LOOP_END ;
ADD R2,#1 ;
ADD R1,#1 ;
B LOOP ;
LOOP_END
NOP
END ;
main.c代码
# include<stdio.h>
extern void Init_1(void);与在汇编文件中定义的Init_1函数关联起来
int main()
{
Init_1();
return 0;
}
在图示处设置五个断点。 点击translate 、build ,然后点击debug ,选择第一个选项开始仿真调试。 点击单步运行 ,观察左边界面寄存器的变化状况。
R0、R1从0开始,每次加1直到加到10,这与编写的代码相一致。
三、C语言有参数调用汇编函数
1)函数形参小于4个
修改Func.s代码
AREA My_Function,CODE,READONLY;
EXPORT Init_1;
;
Init_1
ADD R0,#100;
END;
修改main.c代码
#include<stdio.h>
extern int Init_1(int x);
int main()
{
Init_1(10);
return 0;
}
看到这里难免有点疑惑,这里似乎没有直接的语句写明形参x的值会存放到R0,那指令ADD R0,#100 中传入的整型数x为什么可以和100相加?
设置两个断点。 然后开始仿真调试,点击单步运行 ,观察左边界面寄存器的变化状况。 可以看到传入的整型数x被传递到R0。 最后R0的值为110,返回该值。
2)函数形参多于4个
main.c代码(10个参数)
#include <stdio.h>
int fun(int n0,int n1,int n2,int n3,int n4,int n5,int n6,int n7,int n8,int n9)
{
int m;
m=n0+n1+n2+n3+n4+n5+n6+n7+n8+n9;
return m;
}
void main(void)
{
int num;
num=fun(1,2,3,4,5,6,7,8,9,10);
}
为了搞清楚此时的函数传递机制,在ubuntu18.04下安装arm-linux-gcc。安装好了后输入以下命令得到汇编文件。
arm-linux-gcc -s main.c -o main.s
输入以下命令查看汇编文件。
cat main.s
子函数的参数值传递按顺序存放在R0,R1,R2,R3里,超过4个参数值传递放栈帧里。想详细了解C语言在ARM中函数调用时栈的变化过程,可参考下面的链接。 C语言在ARM中函数调用时,栈是如何变化的?
四、总结
1)C语言在ARM中函数调用时,如果形参个数少于或等于4,则形参由R0,R1,R2,R3四个寄存器进行传递;若形参个数大于4,大于4的部分必须通过堆栈进行传递,且压入堆栈的顺序是与函数中形参的顺序相反。 2)对于X86平台,32位程序使用栈传递,而64位程序则根据参数的个数而不同。 当参数少于6个,使用寄存器传递参数;当参数大于6个,多出来的参数使用栈传递。可以参考以下链接验证看看。 C语言调用函数时参数是使用栈还是寄存器
|