11 C语言与汇编语言的混合编程概述2

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
12
3. 通过固定存储区传递
C51的函数名转换规则、段命名规则及参数传递规则举例。 #include <STC12C5A.h> #define uchar unsigned char uchar func(uchar x,uchar y); //函数func原型声明 void main(void) //主函数 { func(0x12,0x34); //调用函数func while(1); } uchar func(uchar x,uchar y) { return (x/y); }
2
1.C51与汇编语言混合编程概述(续)
单片机程序的编译过程 无论是C语言还是汇编语言,源 程序都要被转换成目标代码 (机器语言),单片机才能识 别。 在单片机混合编程中, C 模块与汇编模块的接口简 单,分别用C51和A51对 源文件进行编译,然后经 连接定位器L51产生可下 载到程序存储器的十六进 制可执行文件。
16
3. 通过固定存储区传递
;} ; SOURCE LINE # 12 ?C0004: RET ;返回 ; END OF _func END ;结束 上面给出了一个C51程序及其编译后的程序清单,可以看出,函数func有2个 char型参数,通过R7,R5传递,所以转换成汇编函数名_func,返回值通过R7 传递回主函数。 如果在前述的DIV.C源文件中使用“#pragma NOREGPARMS”控制命令,禁止寄 存器内参数传递,则所有参数均通过固定的存储区传递。其编译后的汇编输出 文件如下:
南通开放大学
C语言与汇编语言的 混合编程概述
1.C51与汇编语言混合编程概述
在一个应用程序中,根据每个任务的具体特点和要求,用不同的编程语言 编写源程序,最后通过编译/连接器生成一个可执行的完整程序,这种编 程方式称为混合编程。
• 汇编语言特点: 优点:执行速度快、效率高、实时性强、与硬件结合紧密。 缺点:编程难度大、可读性差,不便于移植、开发时间长。 • C语言特点: 优点:编程容易、可移植性强、支持多种数据类型,能直 接对硬件进行操作,效率高。 缺点:实时处理弱于汇编语言,无法准确定时。 • 混合编程特点: 效率高、速度快、易于编程、可读性、可移植性好,使用范围广。
10
3. 通过固定存储区传递
2. 通过固定存储区传递参数的优点是传递途径非常清晰,缺点是代码效率不高, 速度较慢。 用固定存储区传递参数给汇编程序,参数段首地址通过名为“?函数名?BYTE”的 符号确定。当传递位值时,使用名为“?函数名?BIT”的符号保存位参数段首地址。 所有传递的参数存放在以首地址开始递增的存储区内,即使通过寄存器传递参数, 参数也将在这些段中分配空间,参数按声明的先后在每个段中顺序保存。 用作参数传递的固定存储区可能在内部数据区或外部数据区,由存储模式决定。 SMALL模式的参数段用内部数据区,COMPACT和LARGE模式用外部数据区。 3.函数返回值 当函数具有返回值时,也需传递参数,这种返回值的传递是通过51内核单片机内 部寄存器完成的,其传递规则如表4所示。
4
2. C51和A51程序接口基础
表1 C51中函数名的转换规则 C51函数声明 汇编符号名 说 明
void func1(void)
void func2(char)
FUNC1
_FUNC2
无参数传递或不含寄存器的函数,名称不作改 变直接转入目标文件中。
通过寄存器传递参数,函数名加前缀“_”
void func3(void) reentrant
13
//计算x/y/*------------------------- 文件名:DIV.SRC 说明:此文件是DIV.c编译后的汇编输出文件(限于篇幅,有所省略) ------------------------*/ ?PR?main?DIV SEGMENT CODE ;主函数main代码段声明 ?PR?_func?DIV SEGMENT CODE ;函数func代码段声明 EXTRN CODE (?C_STARTUP);使用其它模块中的符号?C_STARTUP PUBLIC _func;公开函数名,以便可以被其它模块调用 PUBLIC main ; #include <STC12C5A.h> ; #define uchar unsigned char ; uchar func(uchar x,uchar y); ; void main(void) RSEG ?PR?main?DIV
_?FUNC3
重入函数,通过堆栈传递参数,函数名加前缀 “_?”
5
2. C51和A51程序接口基础
一个C51源程序模块被编译后,其中的每个函数以“?PR?函数名?模块名” 为命名规则被分配到一个独立的CODE段。 例如,如果模块“FUNC51”内包含一个名为“func”的函数,则其CODE段 的名字是“?PR?FUNC?FUNC51”。 如果一个函数包含有data或bit类型的局部变量,编译器将按“?函数名? BYTE”或“?函数名?BIT”命名规则建立一个data或bit段,它们代表所要 传递参数的起始位置,其偏移量为0。这些段是公开的,因而它们的地址可以 被其它模块访问。 这些段被编译器赋予“OVERLAYABLE”标志,可被L51连接/定位器作覆盖分 析。依据所使用的存储器模式,这些段按表2所列规则命名,在相互调用时, 汇编语言必须服从C51有关段名的命名规则。
9
3. C51函数的参数传递规则(续)
func1(int a) "a"是第一个参数,在R6,R7中传递。 func2 (int b, int c, int *d ) “b”是第一个参数,在R6,R7中传递;“c”是第二个参数,在R4,R5中传 递;“d”是第三个参数,在R1,R2和R3中传递。 func3(long e , long f ) “e”是第一个参数,在R4-R7中传递;“f”是第二个参数,不能在寄存器 中传递,只能在固定存储区中传递。 func4(float g , char h ) “g”是第一个参数,在R4-R7中传递;“h”是第二个参数,必须在固定存 储区中传递
15
3. 通过固定存储区传递
; uchar func(uchar x,uchar y) RSEG ?PR?_func?DIV _func: ;函数func代码段起始 USING 0 ; SOURCE LINE # 9 ;-- Variable 'y?141' assigned to Register 'R5' --- ;-- Variable 'x?140' assigned to Register 'R7' --- ;{ ; SOURCE LINE # 10 ; return (x/y ); ; SOURCE LINE # 11 MOV A,R7 ;计算x/y MOV B,R5 DIV AB MOV R7,A ;结果经R7返回
局部bit变量
BIT
7
3. C51函数的参数传递规则
C51中调用汇编程序时参数传递有两种方式,一种是通过寄存器传递,一种是通过 固定存储区传递。 1.通过寄存器传递参数 Keil C51规定,调用函数时,通过寄存器最多可传递3个参数,余下的通过固定存 储区传递。 如果在源程序中采用了编译控制命令“#pragma NOREGPARMS”,则所有参数传递 都发生在固定的存储区域,所使用的地址空间依赖于所选择的存储模式。 用寄存器传递参数的函数在编译时被C51编译器在函数名前加了一个“_”的前缀, 用固定存储区传递参数的函数转换成的函数名没有下划线,如表1所示。 不同的参数用到的寄存器不一样,不同的数据类型用到的寄存器也不同。表3是利 用寄存器传递参数的规则。
3
2. C51 和A51程序接口基础
C语言与汇编语言程序的连接,在技术上有两个问题:一个是C语言程序与 汇编语言程序如何相互调用;另一个是C语言程序和汇编语言程序如何实 现相互之间的数据传递。 混合编程中,必须约定两个规则,即命名规则和参数传递规则。 C51函数名的转换及其命名规则 C51程序模块编译成目标文件后,其中的函数名要依据其定义的性质转换 为相应不同的函数名。因此,在C和汇编程序的相互调用中,要求汇编程 序必须服从这种函数名的转换规则,否则将无法调用到所需的函数甚至出 现错误。 C51中函数名的转换规则如表1所示,其汇编符号名全部转换为大写。
6
2. C51 和A51程序接口基础
表2 各种存储模式下C51函数段名的命名规则 数据 程序代码 段类型 CODE 段名 ?PR?函数名?模块名(所有存储器模式)
局部变量
DATA
PDATA XDATA
?DT?函数名?模块名(SMALL模式)
?PD?函数名?模块名(COMPACT模式) ?XD?函数名?模块名(LARGE模式) ?BIT?函数名?模块名(所有存储器模式)
18
3. 通过固定存储区传递
; #include <STC12C5A.h> ; #define uchar unsigned char ; #pragma NOREGPARMS ; uchar func(uchar x,uchar y); ; void main(void) RSEG ?PR?main?DIV main: ;主函数代码段起始 USING 0 ; SOURCE LINE # 5 ;{ ; SOURCE LINE # 6 ; func(0x12,0x34); ; SOURCE LINE # 7 MOV ?func? BYTE,#012H ;固定存储区首地址单元传递 第一个参数 MOV ?func? BYTE+01H,#034H ;固定存储区首地址加1单元 传递第二个参数 LCALL func ;调用函数func
14
3. 通过固定存储区传递
main: ;主函数代码段起始 USING 0 ; SOURCE LINE # 4 ;{ ; SOURCE LINE # 5 ; func(0x12,0x34); ; SOURCE LINE # 6 MOV R5,#034H;R5传递第二个char参数 MOV R7,#012H;R7传递第一个char参数 LCALL _func;调用函数func ?C0001: ; while(1); ; SOURCE LINE # 7 SJMP ?C0001 ; END OF main ;}
8
3. C51函数的参数传递规则
表3 C51利用寄存器传递参数规则
参数类型 第1个参数
第2个参数 第3个参数
char R7
R5 R3
int R6、R7
R4、R5 R2、R3
long/float R4-R7
无 无
通用指针 R1-R3
R1-R3 R1-R3
其中,int型和long型数据传递时,低地址寄存器中放数据的高位字节,高地址寄 存器中放数据的低位字节;float型数据满足IEEE格式,R4中存放阶码和符号位, 尾数按从高位到低位的顺序依次存放在寄存器R5、R6和R7中;通用指针的存储 类型存放在R3中,高位在R2,低位在R1如果某一函数的形式参数有两个或更多, 当发生寄存器冲突时,后者改为通过固定存储区传递。
17
3. 通过固定存储区传递
?PR? main? DIV SEGMENT CODE ;主函数main代码段声明 ?PR? func? DIV SEGMENT CODE ;函数func代码段声明 ?DT? func? DIV SEGMENT DATA OVERLAYABLE ;局部变量 内部数据段声明 EXTRN CODE (?C_STARTUP) ;使用外部模块?C_STARTUP PUBLIC ?func?BYTE;公开函数func中的data区的局部变量 PUBLIC func ;公开函数名,以便可以被其它模块调用 PUBLIC main RSEG ?DT?func?DIV ?func?BYTE: ;局部变量内部存储区首地址 x? 140: DS 1 ORG 1 y? 141: DS 1
11
表4 函数返回值所用寄存器分配
返回值类型 bit char,unsigned char,或1字节指针 int,unsigned int,或2字节指针 long或unsigned long float 通用指针 寄存器 CY R7 R6、R7 R4-R7 R4-R7 R1-R3 说明 进位标志 高位字节在R6,低位字节在R7 高位字节在R4,低位字节在R7 32位IEEE格式,阶码和符号位在R4, 尾数高位字节在R5,低位字节在R7 R3存放存储器类型,高位字节在R2, 低位字节在R1
相关文档
最新文档