一、在keil上创建编译环境。
如果有不会的可以参考(按照步骤做即可) 链接: MDK创建纯汇编语言的STM32工程.
添加main.c 和test.s
main.c
#include<stdio.h>
extern void Init_1(void);
int main(){
Init_1();
return 0;
}
test.s
AREA My_Function,CODE,READONLY ;这一行必要的除了My_Function可以自己取名以外,其他的都是模板
EXPORT Init_1 ; 与在c文件中定义的Init_1函数关联起来
; 高级语言中的声明和使用变量其实是对板子寄存器的使用,所以我们只需要直接使用寄存器即可
Init_1
MOV R1,#0 ; 设R1寄存器为i
MOV R2,#0 ; 设R2寄存器为j
LOOP ; 写在最左边的是程序段的段名,执行跳转程序时用到
CMP R1,#10 ; 比较R1和10的大小
BHS LOOP_END ; 如果R1大于等于10,则跳转到LOOP_END程序段,反之忽略该语句,直接执行下面的语句
ADD R2,#1 ; j++
ADD R1,#1 ; i++
B LOOP ; 循环
LOOP_END
NOP ;空指令
END ; 必须空格后再写END,不然会被认为是段名,表示程序结束
二、编译并调试
2.1 编译
点击build开始编译结果如下:
2.2 调试
1.点击右上角的debug 2.单击最左边,设置断点 如图: 3.点击run 运行到断点处 4.进行单步调试 我这里是利用快捷键F11
跟代码编写的一样,当寄存器R1大于或等于10时退出循环。并进入Loop_end函数,执行空指令。
三、将原汇编语言 Init_1函数的类型改为 int Init_1(init)。
main.c
#include<stdio.h>
extern int Init_1(int x);
int main(){
Init_1(2);
return 0;
}
test2.s
AREA My_Function,CODE,READONLY
EXPORT Init_1
ENTRY
Init_1
ADD R0,R0,#100
NOP
END
3.1 调试
1.点击run,运行到断点处 2.单步调试 发现main函数中调用Inint_1将数字2传递给了R0 在进行下一步发现R0被赋值为R0+100 注意:其中的NOP是执行空指令,并没有什么意义,只是为了单步运行时能够运行到下一步。
四、函数参数的传递
4.1 对于X86平台
(1)32位程序使用栈传递。 (2)64位程序根据参数的个数而不同, 当参数1~6个,使用寄存器传递;参数大于6个,多出来的参数使用栈传递。
4.2 对于ARM平台
参数值传递按顺序存放在寄存器r0,r1,r2,r3里,超过4个参数值传递则放栈里。
验证
在刚刚的代码中明显能发现参数是通过寄存器传递的并先赋值给R0。 现在我们将main.c里的Init_1函数中增加参数的个数看看会怎么样。
结果:发现仅仅只有R0——R3被赋值了
总结
本次学习了在keil下c与汇编语言的混合编程,让我对汇编语言有了更深的了解,同时也感叹汇编语言的困难(PS:是真的看不懂)。同时也学习了一下c语言函数调用时的参数问题,这也是之前我所忽略的。总之还是需要不断地学习才能增长学识。
参考文章:
Keil下STM32的C与汇编语言混合编程. C语言在ARM中函数调用时,栈是如何变化的?.
|