IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> MDK下C与汇编语言混合编程 -> 正文阅读

[嵌入式]MDK下C与汇编语言混合编程


前言

如今C语言很强大,在嵌入式编程当中应用广泛,但是为什么还要在c语言中还要嵌入汇编语言,对于没有学过汇编语言的情况下,难学又不易理解?

因为汇编语言实时性比C语言好,占用单片机资源少,生成的执行文件更小,汇编语言程序直接被转换成机器指令。执行效率更高,这对某些嵌入式领域所要求的高实时性有一定帮助,此外,有时在涉及到硬件底层操作的代码时必须使用汇编代码。

所以说,在一些性能要求比较高的情况下,通常会在c语言程序在内嵌一些汇编代码。下面让我们来体会一下,在Keil环境下C与汇编语言的混合使用。


一、在c函数中调用汇编函数

1.调用不带参数的汇编函数

  • 新建一个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导出,供工程中其他文件调用实现
		
Init_1
	MOV	R1,	#1   ;将立即数1放到寄存器R1中,即将R1寄存器初始化为1
	MOV R2,	#2	 ;将立即数2放到寄存器R2中,即将R2寄存器初始化为2
		
LOOP			 ;循环开始的地方
	CMP R1,	#10  ;比较R1与10的大小
	BHS	LOOP_END ;如果R1大于等于10,则跳转到LOOP_END,循环结束;否则,执行下一语句
	ADD R2,	#1	 ;R2=R2+1;
	ADD R1,	#1   ;R1=R1+1;
	B	LOOP     ;无条件跳转到LOOP执行下一次循环
	
LOOP_END	     ;循环结束
	NOP          ;空指令,延时等待
	
	
	END

注意:必须空格后再写END,不然会被认为是段名,表示程序结束

关于新建一个MD工程,并添加一个新项目的步骤
可参考我的另一篇博客

MDK下汇编语言调试分析

  • 开始调试
    在这里插入图片描述
  • 单步执行
    在这里插入图片描述
    程序执行到如上图所示时,可以发现R0R1寄存器的值已经变为12

2.调用带形参的汇编函数

下面由于要涉及到arm寄存器的一些分析,所以我在这先简单介绍一下。

R1~R3通常用来传递函数参数
R4~R11用来保存程序运算的中间结果或函数的局部变量
R12通常用来作为函数调用过程中的临时寄存器
R13寄存器是堆栈寄存器(SP),用来保存堆栈的当前指针
R14寄存器是链接寄存器(LR),用来保存函数的返回地址
R15寄存器是程序寄存器(PC),指向程序当前的地址

  • 修改代码

将原汇编语言 Init_1函数的类型改为 int Init_1(init) ,此函数功能修改为 传入一个整型数x,函数运行后返回整型数 x+100

修改main.c

#include <stdio.h>
extern int Init_1(int a);
int main()
{
	Init_1(66);
	return 0;
}

修改func.s

Init_1
    ADD R0,R0,#100	;R0记录传入的形参,并且执行R0=R0+100;
	BX LR           ;跳转的LR的地址执行,在这里,LR记录main函数调用子函数的返回地址
  • 初始化形参

在这里插入图片描述
在这里插入图片描述
可以看到我传入的函数参数是66,转换为16进制即为0x42,说明函数形参已被写入寄存器R0

  • 记录返回地址

在这里插入图片描述
在这里插入图片描述
我们看到在进入子函数时,一般有两个准备工作

1)初始化形参
2)R14(LR)寄存器值发生变化,记录从子函数返回当前函数的地址

  • 进入子函数、执行指令

在这里插入图片描述
我们看到,下一条指令执行是R0=R0+0x64,此时R0的值为0x42,我们可以预测执行完这步,R0的值应变为0xA6

果然R0的值变为0xA6,如下图

在这里插入图片描述

  • 返回主程序

在这里插入图片描述

当程序运行到如上图所示时,点击单步调试,注意观察到R14(LR)中的地址-1被加载到R15(PC)指针,PC指针指向该地址,即可返回主程序。

在这里插入图片描述
至此,一个函数的调用过程到此为止。

本例是以一个参数为例的,但当函数参数多于4个时,所调用的方式有所不同。前4个参数分别用R0~R3寄存器来记录,多余参数被加载到内存中使用栈来传递。

关于ARM体系下有多个函数形参的情况下,我写了一篇博客具体分析了一下

ARM体系下函数形参调用寄存器详解

二、在汇编函数中调用c函数

  • main.c中修改代码
int sum(int a,int b)
{
	int c;
	a=100;
	b=200;
	c=a+b;
	return c;


}
  • func.s中修改代码
AREA	My_Function ,CODE,READONLY  	
	IMPORT sum
	ENTRY
	EXPORT __main

__main

    BL sum
	BX LR
	
	END
  • 仿真调试

调用子函数的过程与c文件调用汇编函数的过程大同小异,有兴趣的话可以自己尝试一下仿真跟踪调试。

注意:ARM汇编指令不支持顶格写,否则不能识别;声明变量时不要有空格,不然会出现奇奇怪怪的错误。

三、汇编函数与c函数混合调用

  • 修改main.c中的代码
extern int SUM_ASM(void);
int sum(int a,int b)
{
	int c;
	a=100;
	b=200;
	c=a+b;
	return c;
}
int main(void)
{
	SUM_ASM();
	return 0;
}
  • 修改func.s中代码
 AREA	My_Function ,CODE,READONLY  	
	IMPORT sum
	EXPORT SUM_ASM
		
	ENTRY

SUM_ASM
	LDR R0,=0X3
	LDR R1,=0X4
	BL sum 
	MOV PC,LR
	
	
	END
  • 小结
    此代码实现了在c函数中调用汇编函数,再从汇编函数中调用c函数,调用方式与之前大同小异,但是了解c程序和汇编程序相互调用,混合编程还是很有帮助的。

如在MDK下stm32程序的执行过程为

先执行.s的汇编程序,再.s文件中执行以下操作

  1. 初始化堆栈指针 SP=_initial_sp
  2. 初始化 PC 指针 =Reset_Handler
  3. 初始化中断向量表
  4. 配置系统时钟
  5. 调用 C 库函数 _main 初始化用户堆栈,从而最终调用 main 函数去到 C 的世界

然后再跳转到main函数,执行一些c语言程序。
在一些对性能要求比较高的情况下,有时也会在c语言程序在内嵌一些汇编代码。


总结

无论是在汇编程序中调用c程序,还是c程序中调用(内嵌)汇编程序,往往都涉及到子程序的调用、参数的传递、子程序的返回等问题。不同的语言有着不同程度的指令集封装,在了解这些函数调用过程时,首先要初步了解ATPCS(ARM-Thumb Processor Call standard),其核心内容是子程序调用的基本规则和堆栈的使用约定等。

此外,了解了这些子程序的具体调用规则,设计程序仿真调试去验证、理解每一步如何得来,亲自实践操作对于理解子程序的调用方式是很有帮助的。

以上是我的相关学习体会,如有问题,望大家不吝指教。

参考书籍
1.嵌入式c语言自我修养 从芯片、编译器到操作系统 电子工业出版社 王利涛著

2.<STM32库开发指南–基于野火指南者开发板>

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2021-10-11 17:39:56  更:2021-10-11 17:40:49 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 4:49:12-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码