一、建立项目
新建一个项目,过程与ARM汇编程序调试:基于MDK创建纯汇编语言的STM32工程类似
添加main.c和Func.s
Func.s:
```groovy
AREA MY_FUNCTION,CODE,READONLY
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,不然会被认为是段名,表示程序结束
main.c:
include<stdio.h>
extern void Init_1(void);
int main(){
Init_1();
return 0;
}
二、C语言调用汇编函数
1.无参数调用
编译并调试
运行结果
程序进入循环,R1与R2不断加1
最后R1与R2均由0加到10
2.含参数调用
修改代码如下:
main.c:
include<stdio.h>
extern int Init_1(int x);
int main(){
int xx = Init_1(10);
printf("%d", xx);
return 0;
}
Func.s:
AREA MY_Function,CODE,READONLY
EXPORT Init_1 ; 与在c文件中定义的Init_1函数关联起来
; 高级语言中的声明和使用变量其实是对板子寄存器的使用,所以我们只需要直接使用寄存器即可
Init_1
ADD R0,#100 ; 将传入的值+100
MOV PC,LR ; 返回R0
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,不然会被认为是段名,表示程序结束
由于在ARM中,子函数的参数值传递按顺序存放在r0,r1,r2,r3里,超过4个参数值传递放栈帧里。
因此Init_1(10)传入的10放到了R0,由MOV PC,LR返回110
此时,Init_1(10)的10被自动传入R0
可发现,xx的值为0x6E,即110,调用成功。
三、将原汇编语言 Init_1函数的类型改为 int Init_1(init) ,此函数功能修改为 传入一个整型数x,函数运行后返回整型数 x+100。
1.C语言调用函数传递参数的方法
C语言调用函数时,在32位程序中使用栈传递,而在64位程序中,传递方式和参数个数有关,当参数个数小于等于6个时,参数会使用寄存器被传递,当参数大于6个时,6个寄存器被分配后,会利用栈来传递多余的参数,且参数的传递都是从右到左压栈或是存入寄存器。
验证过程参考:https://blog.youkuaiyun.com/m0_55708805/article/details/117388229
2.ARM中寄存器用法
r0-r3 用作传入函数参数,传出函数返回值。在子程序调用之间,可以将 r0-r3 用于任何用途。被调用函数在返回之前不必恢复 r0-r3。—如果调用函数需要再次使用 r0-r3 的内容,则它必须保留这些内容。
r4-r11 被用来存放函数的局部变量。如果被调用函数使用了这些寄存器,它在返回之前必须恢复这些寄存器的值。r11 是栈帧指针 fp。
r12 是内部调用暂时寄存器 ip。它在过程链接胶合代码(例如,交互操作胶合代码)中用于此角色。在过程调用之间,可以将它用于任何用途。被调用函数在返回之前不必恢复
r12。
寄存器 r13 是栈指针 sp。它不能用于任何其它用途。sp 中存放的值在退出被调用函数时必须与进入时的值相同。
寄存器 r14 是链接寄存器 lr。如果您保存了返回地址,则可以在调用之间将 r14 用于其它用途,程序返回时要恢复
寄存器 r15 是程序计数器 pc。它不能用于任何其它用途。
利用寄存器传递参数时,参数值按顺序放在寄存器R0,R1,R2,R3中,当参数大于4个时,超过的参数值利用栈传递,函数返回时,若有返回值会利用寄存器R0存储返回
3.实践
修改main.c文件内容
main.c
#include<stdio.h>
extern int Init_1(int x);
int main(){
Init_1(25);
return 0;
}
Func.s
AREA My_Function,CODE,READONLY
EXPORT Init_1
ENTRY
Init_1
ADD R0,R0,#100
BX LR
END
结果
四、在汇编函数中调用一个C语言写的函数
新建Func.c文件
Func.c
#include<stdio.h>
extern int sum(int a,int b);
int sum(int a,int b){
int c;
a=100;
b=100;
c=a+b;
return c;
}
test1.s
AREA MYDATA, DATA
IMPORT sum
AREA MYCODE, CODE
ENTRY
EXPORT __main
__main
BL sum
BX LR
END
结果
成功调用
五、总结
本实验中,能够用C语言成功调用汇编函数,在其中我学到了更多的知识,收获颇丰。