keil C语言与汇编语言混合编程
C与汇编混合编程主要有以下几种:(1)C语言中嵌入汇编(2)无参数传递的函数调用(3)有参数传递的函数调用
一、C语言中嵌入汇编
1、在 C 文件中要嵌入汇编代码片以如下方式加入汇编代码:
#pragma ASM ; Assembler Code Here #pragma ENDASM
2、在 Project 窗口中包含汇编代码的 C 文件上右键,选择“Options for ...”,点击右边的“Generate Assembler SRC File”和“Assemble SRC File”,使检查框由灰色变成黑色(有效)状态;
3、根据选择的编译模式,把相应的库文件(如 Small 模式时,是 KeilC51LibC51S.Lib)加入工程中, 该文件必须作为工程的最后文件;
4、编译,即可生成目标代码。例:
#include void main(void) { P1=; #pragma asm MOV R7,# DEL: MOV R6,# DJNZ R6,$ DJNZ R7,DEL RET #pragma endasm }
二、无参数传递的函数调用(C51调用汇编函数)
先来个例子:其中example.c和example.a51为项目中的两个文件
***********************example.c*********************************************** extern void delay100(); main() { delay100(); }
***********************example.a51*********************************************** ?PR?DELAY100 SEGMENT CODE ;在程序存储区中定义段 PUBLIC DELAY100; ;声明函数 RSEG ?PR?DELAY100; ;函数可被连接器放置在任何地方 DELAY100: DEL: DJNZ R6,$ DJNZ R7,DEL RET END
在example.c文件中,先声明外部函数,然后直接在main中调用即可。
在example.a51中:
?PR?DELAY100 SEGMENT CODE ;作用是在程序存储区中定义段,DELAY100为段名,?PR?表示段位于程序存储区内 PUBLIC DELAY100 ;作用是声明函数为公共函数 RSEG ?PR?DELAY100 ;表示函数可被连接器放置在任何地方,RSEG是段名的属性
段名的开头为PR,是为了和C51内部命名转换兼容,命名转换规律如下:
CODE -?PR?
XDATA-?XD
DATA-?DT
BIT-?BI
PDATA-?PD
三、有参数传递的函数调用
注:c文件和A51文件不能使用同一个文件名
带参数传递的函数调用,在C51和汇编之间传递参数的方式有两种,一种是通过寄存器传递参数,C51中不同类型的实参会存入相应的寄存器,在汇编中只需对相应寄存器进行操作,即达到传递参数的目的。调用汇编的参数传递规则,见下表:
传递的参数 | char、1字节指针 | int、2字节指针 | long、float | 一般指针 |
第一个参数 | R7 | R6,R7 | R4~R7 | R1,R2,R3 |
第二个参数 | R5 | R4,R5 | R4~R7 | R1,R2,R3 |
第三个参数 | R3 | R2,R3 | 无 | R1,R2,R3 |
在C和汇编混合编程的时候,存在C语言和汇编语言的变量以及函数的接口问题。
在C程序中定义的变量,编译为.asm文件后,都被放进了.bss区,而且变量名的前面都带了一个下划线。在C程序中定义的函数,编译后在函数名前也带了一个下划线。例如:
extern int num就会变成 .bss _num, 1
extern float nums[5]就会变成.bss _nums, 5
extern void func ( )就会变成 _func,
汇编和C的相互调用可以分以下几种情况
1、汇编程序中访问c程序中的变量和函数。
在汇编程序中,用_XX就可以访问C中的变量XX了。访问数组时,可以用_XX+偏移量来访问,如_XX+3访问了数组中的XX[3]。
在汇编程序调用C函数时,如果没有参数传递,直接用_funcname 就可以了。如果有参数传递,则函数中最左边的一个参数由寄存器A给出,其他的参数按顺序由堆栈给出。返回值是返回到A寄存器或者由A寄存器给出的地址。同时注意,为了能够让汇编语言能访问到C语言中定义的变量和函数,他们必须声明为外部变量,即加extern 前缀。
2、C程序中访问汇编程序中的变量
如果需要在C程序中访问汇编程序中的变量,则汇编程序中的变量名必须以下划线为首字符,并用global使之成为全局变量。
如果需要在C程序中调用汇编程序中的过程,则过程名必须以下划线为首字符,并且,要根据C程序编译时使用的模式是stack-based model还是register argument model 来正确地编写该过程,使之能正确地取得调用参数。
3、在线汇编
在C程序中直接插入 asm(“ *** ”),内嵌汇编语句,需要注意的是这种用法要慎用,在线汇编提供了能直接读写硬件的能力,如读写中断控制允许寄存器等,但编译器并不检查和分析在线汇编语言,插入在线汇编语言改变汇编环境或可能改变C变量的值可能导致严重的错误。
汇编和C接口中寻址方式的改变
需要注意的是,在C语言中,对于局部变量的建立和访问,是通过堆栈实现的,它的寻址是通过堆栈寄存器SP实现的。而在汇编语言中,为了使程序代码变得更为精简,TI在直接寻址方式中,地址的低7位直接包含在指令中,这低7位所能寻址的具体位置可由DP寄存器或SP寄存器决定。具体实现可通过设置ST1寄存器 的CPL位实现,CPL=0,DP寻址,CPL=1,SP寻址。在DP寻址的时候,由DP提供高9位地址,与低7位组成16位地址;在SP寻址的时候,16位地址是由SP(16位)与低7位直接相加得来。
由于在C语言的环境下,局部变量的寻址必须通过SP寄存器实现,在混合编程的时候,为了使汇编语言不影响堆栈寄存器SP,通常的方式是在汇编环境中使用DP方式寻址,这样可以使二者互不干扰。编程中只要注意对CPL位正确设置即可。
汇编中参数传递约定
如果一个函数把a, b, r0-r7, psw, dptr等寄存器都使用了,这时r6, r7里面的数据将被破坏,程序将出现异常情况,那该如何是好呢?一个好的办法就是使用堆栈。在函数使用了什么寄存器,就在函数的开始把使用的寄存器入栈,在函数结束的地方再把这些寄存器恢复,听起来这是一个不错的主意。但是当使用的寄存器多时,入栈及出栈的开销可不小呢。还有一个问题是,当函数需要返回值时,它要把返回值放到哪里去呢?要知道函数破坏的寄存器是要恢复的哦!也许读者会想,既然是汇编,那么一切都由自己控制,规定一些约定就可以了。是的!但是否这个约定对每一个函数都适用,如果每个函数一种约定,那工程文件一变大,时间变长时,是否还能记下每个函数的约定。
这里将介绍一种约定形式,即C51的形式。采用这种形式将使我们只关心函数内部的实现,而不必理会函数外的任何东西(这将极大减轻脑力负担);且方便汇编写的函数与C写的函数互相调用。(重点)(这样的约定可以简化C51的实现)
这个约定是:
1,假定被调用函数会破坏ACC, B, PSW, DPTR, R0-R7等寄存器的值,因此调用函数在调用其它函数时不在这些寄存器里保存任何有用的数据。
2,函数的返回值通过R0-R7, C返回。如果数据只有1bit, 则通过C返回, 1byte -r7, 2byte - r6-r7, 4byte - r4-r7, 如果数据很大,R0-R7都放不下,则可以把数据放在固定的数据区里,通过r1-r3返回数据区的起始地址。)
根据上面的两个原理的第一个,除了在堆栈中保存数据外。C51还采用了另一个办法,把数据放在固定的数据区,这样直接访问数据速度快。这样却又带来了另外一个问题,每个函数都占用部分数据区,51那么点点大的数据空间能支持写几个函数啊,Keil公司早想到了这个问题,因此它的链接器(BL51)比其它开发工具的链接器多了一项功能,就是覆盖处理功能。
既然在固定的数据区分配空间,那现在就介绍一些分配空间的伪指令。
使用equ的一个建议是为一些常量指定一个符号,如果要为地址空间指定符号,从可维护性考虑,使用bit, data,idata, pdata, xdata, code这些专用的伪指令要明显优于equ。
每个汇编器分配空间都有其自己的伪指令,下面看看A51的伪指令。db, dw, dd,这三个伪指令用于分配并初始化空间。dbit,ds, dsb, dsw, dsd,这几个伪指令用于分配空间却并不初始化。
还有一个问题是,如果有很多文件都需要调用这个delay_nms,那么就需要在调用这个函数的文件前面声明delay_nms是外部的。即包含下面这两句代码。
extrn code (delay_nms)
extrn data (delay_reg)
如果函数的接口改变,那就需要在都个文件里修改这两代码。当然我们把上面两句声明放到一个文件里,在需要调用这个函数的文件里include这个文件就可以了,这样就不用一个一个的去修改了.
注: 统一的一个约定是,汇编文件使用.asm扩展名,汇编头文件使用.inc扩展名,C文件使用.c扩展名,C头文件使用.h扩展名。
关于参数传递的方法,具体是通过寄存器传递,或通过固定数据区传递,还有一个是方法是通过模拟栈传递。
C51默认的参数传递方法是通过寄存器传递。
keil C语言与汇编语言混合编程的更多相关文章
- 单片机C 语言与汇编语言混合编程
在单片机应用系统设计中,过去主要采用汇编语言开发程序. 汇编语言编写的程序对单片机硬件操作很方便,编写的程序代码短,效率高,但系统设计的周期长,可读性和可移植性都很差.C语言程序开发是近年来单片机系统 ...
- C语言与汇编语言混合编程实验
混合编程方法: 模块链接法 汇编指令嵌入法 1: 模块链接法则 模块链接法是指分别用汇编语言和C语言实现独立的模块(或子程序),再用链接程序把各模块生成的obj文件连接成一个可执行程序. 1:C语言调 ...
- C51与汇编语言混合编程
函数内部混合编程 若想在C语言函数内部使用汇编语言,应使用以下Cx51编译器控制命令: #pragma asm ; Assembly code #pragma endasm 功能作用:asm和end ...
- c语言环境初始化&c语言和汇编混合编程
bootloader通常会分为两个阶段:第一阶段采用汇编语言来编写,主要是一些核心的初始化工作(内存,时钟的初始化),第二阶段使用C语言来编写,主要是它会完成一些板载硬件的初始化(串口,网口)然后其启 ...
- arm:c语言和汇编混合编程
仅作演示. 1.C和汇编可相互调用,汇编子函数格式参考 汇编:普通的函数调用的汇编代码解析 http://www.cnblogs.com/mylinux/p/4139972.html 本文演示了 : ...
- C语言调用Python 混合编程
导语 Python有很多库,Qt用来编写界面,自然产生C++调用Python的需求.一路摸索,充满艰辛 添加头文件搜索路径,导入静态库 我的python头文件搜索路径:C:\Python27amd64 ...
- 【转】VxWorks中高精度实时时钟的实现及C语言汇编混合编程
最近一个项目中需要在VxWorks下使用一个高精度实时时钟,要求精度为1ms,溢 出时间大于5小时.VxWorks提供系统时钟,该时钟在操作系统启动后开始计数,精度为1个tick,可以通过tickGe ...
- Java语言与C语言混合编程(2)--在Java中调用C语言本地库
在上一篇文章中介绍了Java语言中的native关键字,以及Java语言调用C语言的编译生成本地动态链接库(DLL)实现加法运算的小例子,本文通过一个更加详细的例子,深入讲解Java语言调用C语言的函 ...
- 批处理与python代码混合编程的实现方法
批处理可以很方便地和其它各种语言混合编程,除了好玩,还有相当的实用价值, 比如windows版的ruby gem包管理器就是运用了批处理和ruby的混合编写, bathome出品的命令工具包管理器bc ...
随机推荐
- .OCX、.dll文件注册命令Regsvr32的使用
1.打开文件,打开需要注册的OCX文件或dll文件,2.然后根据需要进行OCX文件或DLL文件的注册和反注册 DLL.OCX注册方法--文件Regsvr32用法及情况介绍 使用过activex的人都知 ...
- HDU_2051——十进制到二进制转换
Problem Description Give you a number on base ten,you should output it on base two.(0 < n < 10 ...
- libvirt TLS
博客原文 http://hi.baidu.com/wwfmarcpjkbdiod/item/7b43c89e949d7fbbcd80e590 构建Libvirt的x509证书远程tls连接http:/ ...
- Javascript:splice()方法实现对数组元素的插入、删除、替换及去重
定义和用法 splice() 方法向/从数组中添加/删除项目,然后返回被删除的项目. 注释:该方法会改变原始数组. 语法: Array.prototype.splice(index,count[,el ...
- 【C#基础】实现URL Unicode编码,编码、解码相关整理
1.Unicode编码 引用系统 System.Web using System.Web; string postdata = "SAMLRequest=" + HttpUtili ...
- MATLAB获取“非免驱的相机或者摄像头”的图像数据
Image Acquisition Toolbox™ Adaptor Kit 图像採集工具箱 当要使用MATLAB获取"非免驱的相机或者摄像头"的图像数据时,须要开发一个插件,MA ...
- Linux学习笔记01:Linux下的drwxr-xr-x
1. drwxr-xr-x 第1字母:表示文件类型 d ------- 表示文件目录(directory) - ------- 表示二进制文件 l ------ ...
- NumberBox( 数值输入框) 组件
本节课重点了解 EasyUI 中 NumberBox(数值输入框)组件的使用方法,这个组件依赖于 ValidateBox(验证框)组件.一. 加载方式//class 加载方式<input typ ...
- MVC第一节 配置
1.View中的页面设置为起始页后导致404找不到文件. 解决方案:右键属性,把特定页置为空. 2.新建的MVC项目会把系统默认的浏览器作为浏览方式,如果想要改变的话.可以在项目中新建一个webFor ...
- reason: 'Could not instantiate class named MKMapView'
详细原因: 拖入MapView直接运行,结果报错 解决:在Xcode导入MapKit.framework既可