文章目录

  • 前言
  • 一、在c函数中调用汇编函数
    • 1.调用不带参数的汇编函数
    • 2.调用带形参的汇编函数
  • 二、在汇编函数中调用c函数
  • 三、汇编函数与c函数混合调用
  • 总结

前言

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

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

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


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

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

MDK下汇编语言调试分析

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_1MOV  R1, #1   ;将立即数1放到寄存器R1中,即将R1寄存器初始化为1MOV R2, #2   ;将立即数2放到寄存器R2中,即将R2寄存器初始化为2LOOP          ;循环开始的地方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,不然会被认为是段名,表示程序结束,还有就是

AREA My_Function ,CODE,READONLY

这个指令一定不要顶格写!
这个指令一定不要顶格写!
这个指令一定不要顶格写!


汇编指令对格式要求比较高,大家在编写代码时一定要注意!

  • 开始调试
  • 单步执行

    程序执行到如上图所示时,可以发现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_1ADD 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)中的地址0x080003D5-1被加载到R15(PC)指针,PC指针指向该地址0x080003D4,即可返回主程序。


至此,一个函数的调用过程到此为止。

本例是以一个参数为例的,但当函数参数多于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 sumENTRYEXPORT __main  ;注意这里有两个下划线,中间没空格__main ;注意这里有两个下划线,中间没空格BL sumBX LREND
  • 仿真调试

调用子函数的过程与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 sumEXPORT SUM_ASMENTRYSUM_ASMLDR R0,=0X3LDR R1,=0X4BL sum MOV PC,LREND
  • 小结
    此代码实现了在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库开发指南–基于野火指南者开发板>

keil下C与汇编语言混合编程相关推荐

  1. keil4c语言和汇编混合,keil C语言与汇编语言混合编程

    keil C语言与汇编语言混合编程 1. C语言中嵌入汇编 1.在 C 文件中要嵌入汇编代码片以如下方式加入汇编代码: #pragma ASM ; Assembler Code Here #pragm ...

  2. c语言与汇编语言混合编程实验,C语言与汇编语言混合编程实验

    混合编程方法: 模块链接法 汇编指令嵌入法 1: 模块链接法则 模块链接法是指分别用汇编语言和C语言实现独立的模块(或子程序),再用链接程序把各模块生成的obj文件连接成一个可执行程序. 1:C语言调 ...

  3. C语言数据交换算法和伪指令,补充:单片机c语言与汇编语言混合编程.ppt

    补充:单片机c语言与汇编语言混合编程 reg51.h和reg52.h:实质上是没有区别的,都是一些特殊功能寄存器的申明 sfr P0 = 0x80; sfr P1 = 0x90; sfr P2 = 0 ...

  4. 汇编c语言混合编程pdf,C语言及汇编语言混合编程的方法.pdf

    维普资讯 1993矩 化 工 电 子 计 算 第 2期 C语言与汇编语言混合编程的方法 f/1) (南京犬李葛于如丽顶吾学系) 摘 要 本文通过实例阐述了当前较为漉行的两种c语盲 (Microsoft ...

  5. c语言混合编程 pdf,C语言与汇编语言混合编程的方法.pdf

    C语言与汇编语言混合编程的方法 维普资讯 讫 梅 龄 施 扰 绝 埔 综 勿 穗 直 触 搔 拌 橱 悬 邱 舟 絮 颈 茬 辞 乏 味 绞 涡 菊 黄 宜 悄 条 搬 悄 俱 泼 洋 醚 檀 测 易 ...

  6. ARM下C语言和汇编语言混合编程

    文章目录 一. 在C语言中调用汇编语言 1. 编写代码 2. 调试验证 二. 在汇编语言中调用C语言 1. 编写代码 2. 调试验证 关于函数的传递参数以及接受返回值的原理,在另一篇博客:X86与AR ...

  7. c语言汇编混合编程方法,C语言和汇编语言混合编程方法

    摘要: C语言是一种高级的面向过程的开发语言,汇编语言是一种低级的面向机器的编程语言.两者在程序设计开发方面各有优劣,目前两者的混合编程得到了广泛的应用.本文通过具体的实例,说明了混合编程的基本方法, ...

  8. c语言与汇编语言混合编程

    如何从汇编语言过渡到c语言? 从编译过程谈起 编译小知识 源代码编译后得到目标文件 (二进制文件) 不同语言可编译得到相同格式的目标文件 链接器负责将目标文件组装得到可执行文件 老生常谈的问题... ...

  9. STM32的C与汇编语言混合编程

    本次我们要运用到汇编语言,并且将其与c混合编程.内容较多. 一.在c语言中调用汇编语言 新建一个工程 new project 芯片型号,STM32F103VE 配置如下 创建c文件 代码部分几乎相同, ...

最新文章

  1. Rocksdb 的优秀代码(二)-- 工业级 打点系统 实现分享
  2. 魔幻!2021年,6种将死的编程语言?
  3. 深入理解int a[5];
  4. 数学建模——线性规划模型详解Python代码
  5. Kubernetes 稳定性保障手册 -- 可观测性专题
  6. ceil和floor
  7. 高仿真的类-单例工厂的顶层设计
  8. 字符串得结果!Java数组模拟栈以实现中缀表达式综合计算器,字符串表达式计算器
  9. linux自动启动network服务,Windows/Linux 创建开机启动服务
  10. timer数据库总显示连接不上服务器,asp.net 上传服务器后,MSSQL数据库连接问题
  11. 关于request.getParameter(java.lang.String name)
  12. 技巧:你未必知道的IE8九大功能
  13. 最大流问题(超详细!!!)
  14. 【数据分析】如何构建指标体系 设计一份优质报表
  15. CTSCAPIOTHUPC2018颓废记
  16. Java通过名字查询缘分,姓名缘分配对 从姓名笔画看两人姻缘
  17. 如何设置网页标题图标 FavIcon
  18. ffmpeg命令:wav转pcm,pcm转wav
  19. 基于 bioMart 构建绵羊(非常见物种) OrgDb 包/数据库
  20. GBase 8a 虚拟集群

热门文章

  1. Win10蓝牙开关突然消失不见 已经解决方法2023.2.11
  2. 使用 Flutter 创建自适应应用
  3. Linux搭建samba文件共享服务器,实现基于Linux和Windows的共享文件服务
  4. 年会 司庆 主体活动 婚庆 拓展 复用抽奖软件
  5. python个人所得税怎么写分录_缴纳的个人所得税的会计分录怎么写?
  6. 超级玛丽HTML5源代码学习------(四)
  7. 【树莓派4B:安装QT5开发环境】
  8. kettle 筛选数据 并根据关键字段去重 设计
  9. 程序员能有什么好出路?前路漫漫,望长风破浪!
  10. android recyclerview 横向移动,RecyclerView实现纵向和横向滚动