一、创建项目并进行调试
1、创建project
- 输入project的名字,这里我输入的Func。
- 选择芯片类型,这里我选择的是
STM32F103VE
。(ps:图片是后面调试的时候在魔法棒页面截的,我做的时候忘记截图了。)
- 一些基本配置,按照图片所示选择就好。
2、添加main.c和Func.s文件
3、编写代码
- main.c:
`# include<stdio.h>
extern void Init_1(void);
int main(){
Init_1();
return 0;
}
- 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
- rebuild一下
可以从最下面看到没有错误只有一个警告。
二、C语言调用汇编函数
1、无参调用
- 调试前的一些参数设置
点击魔法棒,选择Debug页面,勾选Use Simulator
,将Dialog DLL下的属性改为DARMSTM.DLL
,将Parameter下的属性改为-pSTM32F103VE
- 进入调试界面
- 设置断点
- 按F11进行单步调试观察寄存器的变化情况
这里看到首先会进入Inint_1函数,之后会为R1,R2寄存器赋初值为0。
之后会进入LOOP函数,这里是将R1,R2寄存器中的值与10进行比较,如果小于10就加1,一直循环到等于10,该函数才end。
2、有参调用
1、修改代码
main.c:
# include<stdio.h>
extern int Init_1(int x);
int main(){
int s = Init_1(17);
printf("%d", s);
return 0;
}
Func.s:
AREA MY_FUNCTION,CODE,READONLY
EXPORT Init_1
Init_1
ADD R0,#100
MOV PC,LR
LOOP
CMP R1,#10
BHS LOOP_END
ADD R2,#1
ADD R1,#1
B LOOP
LOOP_END
NOP
END
- rebiuld一下
在ARM中,子函数的参数值传递按顺序存放在r0,r1,r2,r3里,超过4个参数值传递放栈帧里。
因此Init_1(17)传入的10放到了R0,由MOV PC,LR返回110(十六进制为0x75)。
2、进入调试
照例设置一下断点观察寄存器的变化,断点位置如下图所示。
- R0返回117(十六进制为0x75):
- main函数中s的值返回117(十六进制为0x75):
三、汇编函数调用C语言
1、改写函数
main.s:
# include<stdio.h>
extern void Init_1(void);
int svt(void);
int main(){
Init_1();
return 0;
}
int svt(){
return 17;
}
Func.s:
AREA MY_Function,CODE,READONLY
EXPORT Init_1
IMPORT svt
Init_1
MOV R1,#0
MOV R2,#0
LOOP
CMP R1,#10
BHS LOOP_END
ADD R2,#1
ADD R1,#1
BL svt
B LOOP
LOOP_END
NOP
END
- rebuild一下
- 设置断点,调试:
可发现,执行svt后,R0变为了0x11即17,即成功调用。
四、总结
本次实验是关于C语言和汇编语言的混合编程,实验中跟踪寄存器的变化,了解到函数运行过程中的参数变化与寄存器的使用情况。实验只是涵盖了一小部分,下面对寄存器的使用规则进行补充。
寄存器的使用规则:
- 子程序间通过寄存器R0 ~ R3来传递参数。
- 在子程序中,使用寄存器R4 ~ R11来保存局部变量。
- 寄存器R12用于保存SP,在函数返回时使用该寄存器出栈,记作IP。
- 寄存器R13用于数据栈指针,记作SP,寄存器SP在进入子程序时的值和退出寄存器时的值必须相等。
- 寄存器R14称为链接寄存器,记作LR,它用于保存子程序的返回地址。
- 寄存器R15是程序计数器,记作PC。