资源预览内容
第1页 / 共36页
第2页 / 共36页
第3页 / 共36页
第4页 / 共36页
第5页 / 共36页
第6页 / 共36页
第7页 / 共36页
第8页 / 共36页
第9页 / 共36页
第10页 / 共36页
亲,该文档总共36页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述
本章要点本章要点混合编程是指使用两种或两种以上的程序设计 语言,通过相互调用、参数传递、共享数据结 构和数据信息而形成程序的过程。采用高级语 言与汇编语言混合编程,从而充分利用各种程 序设计语言各自的优势,即程序的大部分采用 高级语言编写,以提高程序的开发效率;在某 些部分利用汇编语言编写,以提高程序的运行 效率。 Turbo C嵌入汇编方式 Turbo C模块连接方式 汇编语言在Visual C+中的应用8.1 Turbo C嵌入汇编方式C语言与汇编语言的混合编程的第一种方法是在C语言 中嵌入汇编语言,又称嵌入式编程。其优点是内嵌的汇编代 码显得更加简洁直观,程序员不用考虑外部链接、命名以及 参数传递协议等问题,主要缺点是代码缺乏可移植性,功能 较弱。此种方法一般只用于需要插入汇编语句较少的情况。8.1.1 嵌入汇编语句格式 在Turbo C中,C程序中嵌入汇编语言语句必须以关键 字ASM开头,其格式如下: ASM /*注释*/ 在使用此种格式时,应注意以下几点: (1)ASM作为关键字不能省略,带有ASM标识的汇 编语言代码可以看成是C语言的部分程序代码。当C 语言编译器遇到ASM语句时会识别并自动调用汇编语 言编译程序,将它翻译为机器码再嵌入到C语言程序 之中。 (2)操作码可以是处理器指令(如PUSH、MOV等) ,也可以是伪指令(如DB、DW、EXTERN等)。(3)操作数是操作码可以接受的数据,可以是 指令允许的立即数、寄存器名,也可以是C程序 中的常量、变量和标号。 (4)C程序中嵌入的汇编代码后可以有分号也 可以无分号。如果汇编代码后无分号则必须以换 行符结束(嵌入的汇编语句是C语言中唯一可以 以换行结束的语句);如果汇编代码后有分号, 则一行中可以有多条嵌入的汇编语句,但一条汇 编语句不能跨越两行。(5)嵌入的汇编语句的注释方式必须采用C语言的 注释方式,即必须用“/*”标识注释的开始,用“*/” 来标识注释的结束,绝不能像纯汇编那样使用“;” 来作为一条注释的开始。 (6)如果要在C语言程序中嵌入连续多条汇编语句 ,可以在每行前面都加上“ASM”关键字,更简单的 办法是输入一个ASM关键字后,使用括号“和“将 这些汇编语句括起来。8.1.2 汇编语句访问C语言的数据内嵌的汇编语句除可以使用指令允许的立即数、寄存器名外 ,还可以使用C语言程序中的任何符号(标识符),包括变量、 常量、标号、函数名、寄存器变量、函数参数等;C编译程序自 动将它们转换成相应汇编语言指令的操作数,并在标识符名前加 下划线。一般来说,只要汇编语句能够使用存储器操作数(地址 操作数),就可以采用一个C语言程序中的符号;同样,只要汇 编语句可以用寄存器作为合法的操作数,就可以使用一个寄存器 变量。对于具有内嵌汇编语句的C程序,C编译器要调用汇编程序 进行汇编。汇编程序在分析一条嵌入式汇编指令的操作数时,若 遇到了一个标识符,它将在C程序的符号表中搜索该标识符,但 8086寄存器名不在搜索范围之内,而且大小写形式的寄存器名都 可以使用。在C语言程序中使用嵌入式汇编语句时,还应注意以下几个 问题: (1)Turbo C语言中可以直接使用通用寄存器和段寄存器, 只要在寄存器名前加一个下划线就可以了。另外,C语言中 使用SI和DI指针寄存器作为寄存器变量,利用AX和DX传递返 回参数。 如果C语言函数中没有寄存器说明,嵌入式汇编语句可以自 由地把SI、DI用做暂存寄存器;如果C函数有寄存器说明,嵌 入式汇编语句仍可以使用SI、DI,但最好采用C语言寄存器变 量名形式。嵌入式汇编语句可以任意使用AX/BX/CX/DX寄 存器,以及它们的8位形式。(2)内嵌汇编指令可以使用转移指令和LOOP循环指 令,但是它们只能在函数体内有效,不允许进行段间 转移。由于ASM语句中不能给出标号,因而转移指令 只能使用C语言程序中标号(在C语言程序中通常是 定义给GOTO语句使用的)。 (3)行内汇编语句的操作数也可以是C语言结构中的 某个成员(字段),引用方法仍然采用下面的形式: 结构变量名.结构成员名 另一种引用方法是把结构变量的首地址送往某一地址 寄存器,然后用该寄存器名(加方括号)再加成员名 ,中间用圆点隔开。 8.1.3 嵌入汇编的编译过程C语言程序中含有嵌入式汇编语言语句时,C编译器首先将 C代码的源程序(.c)编译成汇编语言源文件(.asm), 然后调用汇编程序Turbo Assembler将产生的汇编语言源 文件编译成目标文件(.obj),最后调用Tlink程序将目标 文件链接成可执行文件(.exe)。 Turbo C 2.0在编译含内嵌汇编语句的程序时,只能采用命 令行TCC方式,并且如果C源程序没有使用#pragma inline预处理,必须使用-B命令行选项编译连接。Turbo C 2.0在处理汇编语句时要调用TASM.EXE。如果没有 TASM汇编器,可以用Microsoft公司的MASM.EXE来替代。具 体的方法有3种: (1)用pctools或debug在tcc.exe中查找到TASM,并替 换成MASM。 (2)把MASM.EXE拷贝或改名为TASM.EXE,放到Turbo C 子目录中。 (3)在命令行输入以下内容:tcc b e /path/masm/exec语言源文件名,其中,-b是使用汇编开 关,-e是使用另一个汇编器开关,path是MASM或其他的汇 编器所在的目录路径。模块连接方式是汇编语言和C语言连接时最常用的方法 。模块连接是指分别编制汇编语言程序和C语言程序,C语 言程序和汇编语言程序分别编译后产生各自的目标程序.obj 文件,然后通过连接程序LINK将几个.obj目标文件合并,建 立一个单独的.exe可执行文件。在这一过程中,汇编语言程序被看做是C语言可以调用 的函数,汇编语言的程序名就是函数名。C语言像调用其他 C函数一样,通过汇编语言程序名调用汇编程序。简单来说 ,就是将汇编语言程序作为C语言的外部子过程调用。8.2 Turbo C模块连接方式8.2.1 混合编程的约定规则 1)命名约定C编译器对C源程序编译时要将其中的变量名、过程名、函 数名等标识符前加下划线,而汇编程序在汇编时直接使用,所 以被C语言调用的汇编程序的所有标识符前都要加下划线,以 保持两者标识符一致。需要指出的是,如果是汇编语言设置采 用C语言类型,则不必在标识符前加下划线。 此外,C语言对标识符长度的要求是不超过8个字符,并且区分大 小写;而汇编语言则要求标识符长度不超过31个字符,且不区 分大小写。因此,在相互调用时,汇编源程序中的标识符最好 不超过8个字符(由于Turbo C在PC上支持标识符长度达到32 个字符,所以无此限制),并遵循C语言习惯采用小写。2)声明约定在C语言程序中,C对所要调用的外部过程、函数、变 量均用EXTERN予以说明,并且放在主调用程序之前,一 般放在各函数体外部,说明形式如下: extern 返回值类型 函数名称(参数类型表); extern 变量类型 变量名;其中,返回值类型和变量类型是C语言中函数、变量中 所允许的任意类型,当返回值类型空缺时,默认为int型。 经过说明后,这些外部变量、过程、函数就可在C程序中 直接使用。函数的参数在传递过程中要求参数个数、类型 、顺序要一一对应。为了使汇编语言程序的标识符(子程序名和变量名)能 在其他模块可见,让C语言程序能够调用它,必须用 public操作符定义它们。3)寄存器使用约定作为一个独立的汇编语言子程序,当然要注意寄存器 的保护和恢复。对于寄存器BP、SP、DS、CS和SS,汇编语言子程序 如果要使用它们,并且有可能改变它们的值,Turbo C要求 进行保护。经保护后,这些寄存器可以使用,但退出前必 须加以恢复。寄存器AX、BX、CX、DX和ES,在汇编语言子程序中 通常可以任意使用,其中的AX和DX寄存器承担了传递返回 值的任务。标志寄存器也可以任意改变。指针寄存器SI和DI比较特殊,因为Turbo C将 它们用做了寄存器变量。如果C程序启用了寄存器 变量,则汇编语言子程序使用寄存器SI和DI前必须 保护,退出前恢复。如果C程序没有启用寄存器变 量,则汇编语言子程序不必保护寄存器SI和DI。 Turbo C编译程序提供了一个编译选择项(-r),它 可以禁止C编译程序使用寄存器变量。一般来说, 建议总是对SI和DI寄存器进行保护。4)存储模式约定存储模式处理程序、数据、堆栈在主存中的分配和存取,决 定代码和数据的默认指针类型 。存储模式在C语言中又称编译模 式或主存模式。Turbo C提供了6种存储模式,分别是:微型模式 (Tiny)、小型模式(Small)、紧凑模式(Compact)、中型 模式(Medium)、大型模式(Large)和巨型模式(Huge)。为了使汇编语言程序与Turbo C语言程序连接到一起,对于汇 编语言简化段定义格式来说,两者必须具有相同的存储模式。汇 编语言程序采用.model伪指令,Turbo C利用TCC选项-m指定各 自的存储模式。相同的存储模式将自动产生相互兼容的调用和返 回类型;同时,汇编程序的段定义伪指令.code、.data等也将产 生与Turbo C相兼容的段名称和属性。连接前,C语言与汇编语言程序都有各自的代码段、数据段 ;而连接后,它们的代码段、数据段就合二为一或者彼此相关。 需要特别说明的是,被连接的多个目标模块中,应当有一个并且 只有一个具有起始模块。也就是说,某个C语言程序中应有 main()函数,汇编语言程序不用定义起始执行点。而且由于共用 一个堆栈段,混合编程时通常汇编语言程序无须设置堆栈段。8.2.2 汇编模块的编译和连接 (1)利用汇编程序编译汇编语言程序成为.obj目标代码文件 。 (2)利用C编译程序编译C语言程序成为.obj目标代码文件 。 (3)利用连接程序将各个目标代码文件连接在一起,得到 可执行程序文件。8.2.3 混合编程的参数传递 1)利用堆栈传递参数C语言程序可以通过堆栈将参数传递给被调用函数。C程序调用函数之前,先从该函数中的最右边的参数开 始依次将参数压入堆栈,最后压入最左边的参数,参数压入 堆栈的顺序与实参表中参数的排列顺序相反。当被调用函数 运行结束后,压入堆栈中的参数已无价值,C程序会立即调 整堆栈指针SP,使之恢复压入参数以前的值,释放堆栈中为 参数保留的空间。也就是说,堆栈的平衡是主函数程序实现 的,子程序不必在返回时调整堆栈指针SP。这就是参数传递 的C语言规则。2)返回值的传递被调用函数的返回值,按下列规则传递给调用 者:如果返回值小于或等于16位,则将其存放在AX 寄存器中;如果返回值是32位,则存放在DX.AX寄 存器对中,其中,DX存储高16位,AX存储低16位 ;如果返回值大于32位,则存放在静态变量存储区 ,AX寄存器存放指向这个存储区的偏移地址;对于 32位far指针,则还利用DX存放段地址。由此可见,汇编语言子程序向C程序返回处理 结果时,是通过AX和DX完成的。但对于不同长度 的返回数据,使用寄存器的情况也不同。3)地址参数的传递C语言程序的参数传递,可采用传数值和传地址两种 方式。如果参数是传值的,可直接写出实际参数;如果 参数是传址的,则在说明中将参数类型说明为指针类型 ,调用时,用“”。 (9)一般来说,不能假定某个寄存器在_asm块开始的时候 有已知的值。在_asm块中使用C+语言应注意以下几点: (1)在嵌入汇编中可以使用C/C+变量以及很多其 他的C/C+元素,包括符号(包括标号、变量和函 数名)、常量(包括符号常量和枚举型成员)、宏 定义和预处理指示符、注释(包括“/*/”和“/”)、 类型名(包括所有MASM中合法的类型)及typedef 名称(通常使用PTR和TYPE操作符,或者使用指定的 的结构或枚举成员)。 (2)在嵌入汇编中,
网站客服QQ:2055934822
金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号