大二上-汇编语言_第1页
大二上-汇编语言_第2页
大二上-汇编语言_第3页
大二上-汇编语言_第4页
大二上-汇编语言_第5页
已阅读5页,还剩45页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

汇编语言与C的混合编程本章结构8.2

TurboC模块连接方式8.1

TurboC嵌入汇编方式8.3汇编语言在VisualC++中的应用基础知识本章要点

混合编程是指使用两种或两种以上的程序设计语言,通过相互调用、参数传递、共享数据结构和数据信息而形成程序的过程。采用高级语言与汇编语言混合编程,从而充分利用各种程序设计语言各自的优势,即程序的大部分采用高级语言编写,以提高程序的开发效率;在某些部分利用汇编语言编写,以提高程序的运行效率。8.1TurboC嵌入编程方式8.1.1嵌入汇编语句格式8.1.2汇编语句访问C语言的数据8.1.3嵌入汇编的编译过程

8.1TurboC嵌入编程方式C语言与汇编语言的混合编程的第一种方法是在C语言中嵌入汇编语言,又称嵌入式编程。其优点是内嵌的汇编代码显得更加简洁直观,程序员不用考虑外部链接、命名以及参数传递协议等问题,主要缺点是代码缺乏可移植性,功能较弱。此种方法一般只用于需要插入汇编语句较少的情况。8.1TurboC嵌入编程方式8.1.1嵌入汇编语句格式ASM<操作码><操作数><;或回车换行>/*注释*/在TurboC中,C程序中嵌入汇编语言语句必须以关键字ASM开头,其格式如下:注

意(1)ASM作为关键字不能省略,带有ASM标识的汇编语言代码可以看成是C语言的部分程序代码。当C语言编译器遇到ASM语句时会识别并自动调用汇编语言编译程序,将它翻译为机器码再嵌入到C语言程序之中。(2)操作码可以是处理器指令(如PUSH、MOV等),也可以是伪指令(如DB、DW、EXTERN等)。8.1TurboC嵌入编程方式8.1.1嵌入汇编语句格式ASM<操作码><操作数><;或回车换行>/*注释*/注

意(3)操作数是操作码可以接受的数据,可以是指令允许的立即数、寄存器名,也可以是C程序中的常量、变量和标号。(4)C程序中嵌入的汇编代码后可以有分号也可以无分号。如果汇编代码后无分号则必须以换行符结束(嵌入的汇编语句是C语言中唯一可以以换行结束的语句);如果汇编代码后有分号,则一行中可以有多条嵌入的汇编语句,但一条汇编语句不能跨越两行。8.1TurboC嵌入编程方式8.1.1嵌入汇编语句格式ASM<操作码><操作数><;或回车换行>/*注释*/注

意(6)如果要在C语言程序中嵌入连续多条汇编语句,可以在每行前面都加上“ASM”关键字,更简单的办法是输入一个ASM关键字后,使用括号"{"和"}"将这些汇编语句括起来。(5)嵌入的汇编语句的注释方式必须采用C语言的注释方式,即必须用“/*”标识注释的开始,用“*/”来标识注释的结束,绝不能像纯汇编那样使用“;”来作为一条注释的开始。8.1TurboC嵌入编程方式8.1.2汇编语句访问C语言的数据

内嵌的汇编语句除可以使用指令允许的立即数、寄存器名外,还可以使用C语言程序中的任何符号(标识符),包括变量、常量、标号、函数名、寄存器变量、函数参数等;C编译程序自动将它们转换成相应汇编语言指令的操作数,并在标识符名前加下划线。一般来说,只要汇编语句能够使用存储器操作数(地址操作数),就可以采用一个C语言程序中的符号;同样,只要汇编语句可以用寄存器作为合法的操作数,就可以使用一个寄存器变量。8.1TurboC嵌入编程方式8.1.2汇编语句访问C语言的数据

对于具有内嵌汇编语句的C程序,C编译器要调用汇编程序进行汇编。汇编程序在分析一条嵌入式汇编指令的操作数时,若遇到了一个标识符,它将在C程序的符号表中搜索该标识符,但8086寄存器名不在搜索范围之内,而且大小写形式的寄存器名都可以使用。在C语言程序中使用嵌入式汇编语句时,还应注意以下几个问题:8.1TurboC嵌入编程方式8.1.2汇编语句访问C语言的数据(1)TurboC语言中可以直接使用通用寄存器和段寄存器,只要在寄存器名前加一个下划线就可以了。另外,C语言中使用SI和DI指针寄存器作为寄存器变量,利用AX和DX传递返回参数。

如果C语言函数中没有寄存器说明,嵌入式汇编语句可以自由地把SI、DI用做暂存寄存器;如果C函数有寄存器说明,嵌入式汇编语句仍可以使用SI、DI,但最好采用C语言寄存器变量名形式。嵌入式汇编语句可以任意使用AX/BX/CX/DX寄存器,以及它们的8位形式。8.1TurboC嵌入编程方式8.1.2汇编语句访问C语言的数据(2)内嵌汇编指令可以使用转移指令和LOOP循环指令,但是它们只能在函数体内有效,不允许进行段间转移。由于ASM语句中不能给出标号,因而转移指令只能使用C语言程序中标号(在C语言程序中通常是定义给GOTO语句使用的)。(3)行内汇编语句的操作数也可以是C语言结构中的某个成员(字段),引用方法仍然采用下面的形式:结构变量名.结构成员名另一种引用方法是把结构变量的首地址送往某一地址寄存器,然后用该寄存器名(加方括号)再加成员名,中间用圆点隔开。8.1TurboC嵌入编程方式8.1.3嵌入汇编的编译过程C语言程序中含有嵌入式汇编语言语句时,C编译器首先将C代码的源程序(.c)编译成汇编语言源文件(.asm),然后调用汇编程序TurboAssembler将产生的汇编语言源文件编译成目标文件(.obj),最后调用Tlink程序将目标文件链接成可执行文件(.exe)。TurboC2.0在编译含内嵌汇编语句的程序时,只能采用命令行TCC方式,并且如果C源程序没有使用#pragmainline预处理,必须使用-B命令行选项编译连接。8.1TurboC嵌入编程方式8.1.3嵌入汇编的编译过程TurboC2.0在处理汇编语句时要调用TASM.EXE。如果没有TASM汇编器,可以用Microsoft公司的MASM.EXE来替代。具体的方法有3种:

(2)把MASM.EXE拷贝或改名为TASM.EXE,放到TurboC子目录中。

(1)用pctools或debug在tcc.exe中查找到TASM,并替换成MASM。(3)在命令行输入以下内容:tcc–b–e/path/masm/exec语言源文件名,其中,-b是使用汇编开关,-e是使用另一个汇编器开关,path是MASM或其他的汇编器所在的目录路径。8.2

TurboC模块连接方式

模块连接方式是汇编语言和C语言连接时最常用的方法。模块连接是指分别编制汇编语言程序和C语言程序,C语言程序和汇编语言程序分别编译后产生各自的目标程序.obj文件,然后通过连接程序LINK将几个.obj目标文件合并,建立一个单独的.exe可执行文件。

在这一过程中,汇编语言程序被看做是C语言可以调用的函数,汇编语言的程序名就是函数名。C语言像调用其他C函数一样,通过汇编语言程序名调用汇编程序。简单来说,就是将汇编语言程序作为C语言的外部子过程调用。8.2

TurboC模块连接方式8.2.1混合编程的约定规则8.2.2汇编模块的编译和连接8.2.4汇编语言程序对C语言程序的调用8.2.3混合编程的参数传递8.2

TurboC模块连接方式8.2.1混合编程的约定规则

C编译器对C源程序编译时要将其中的变量名、过程名、函数名等标识符前加下划线,而汇编程序在汇编时直接使用,所以被C语言调用的汇编程序的所有标识符前都要加下划线,以保持两者标识符一致。需要指出的是,如果是汇编语言设置采用C语言类型,则不必在标识符前加下划线。(1)

命名约定此外,C语言对标识符长度的要求是不超过8个字符,并且区分大小写;而汇编语言则要求标识符长度不超过31个字符,且不区分大小写。因此,在相互调用时,汇编源程序中的标识符最好不超过8个字符(由于TurboC在PC上支持标识符长度达到32个字符,所以无此限制),并遵循C语言习惯采用小写。8.2

TurboC模块连接方式8.2.1混合编程的约定规则

在C语言程序中,C对所要调用的外部过程、函数、变量均用EXTERN予以说明,并且放在主调用程序之前,一般放在各函数体外部,说明形式如下:(2)

声明约定extern返回值类型函数名称(参数类型表);extern变量类型变量名;8.2

TurboC模块连接方式8.2.1混合编程的约定规则

其中,返回值类型和变量类型是C语言中函数、变量中所允许的任意类型,当返回值类型空缺时,默认为int型。经过说明后,这些外部变量、过程、函数就可在C程序中直接使用。函数的参数在传递过程中要求参数个数、类型、顺序要一一对应。

为了使汇编语言程序的标识符(子程序名和变量名)能在其他模块可见,让C语言程序能够调用它,必须用public操作符定义它们。8.2

TurboC模块连接方式8.2.1混合编程的约定规则

作为一个独立的汇编语言子程序,当然要注意寄存器的保护和恢复。(3)

寄存器使用约定

对于寄存器BP、SP、DS、CS和SS,汇编语言子程序如果要使用它们,并且有可能改变它们的值,TurboC要求进行保护。经保护后,这些寄存器可以使用,但退出前必须加以恢复。寄存器AX、BX、CX、DX和ES,在汇编语言子程序中通常可以任意使用,其中的AX和DX寄存器承担了传递返回值的任务。标志寄存器也可以任意改变。8.2

TurboC模块连接方式8.2.1混合编程的约定规则

指针寄存器SI和DI比较特殊,因为TurboC将它们用做了寄存器变量。如果C程序启用了寄存器变量,则汇编语言子程序使用寄存器SI和DI前必须保护,退出前恢复。如果C程序没有启用寄存器变量,则汇编语言子程序不必保护寄存器SI和DI。TurboC编译程序提供了一个编译选择项(-r),它可以禁止C编译程序使用寄存器变量。一般来说,建议总是对SI和DI寄存器进行保护。8.2

TurboC模块连接方式8.2.1混合编程的约定规则

存储模式处理程序、数据、堆栈在主存中的分配和存取,决定代码和数据的默认指针类型

。存储模式在C语言中又称编译模式或主存模式。TurboC提供了6种存储模式,分别是:微型模式(Tiny)、小型模式(Small)、紧凑模式(Compact)、中型模式(Medium)、大型模式(Large)和巨型模式(Huge)。作为一个独立的汇编语言子程序,当然要注意寄存器的保护和恢复。(4)

存储模式约定为了使汇编语言程序与TurboC语言程序连接到一起,对于汇编语言简化段定义格式来说,两者必须具有相同的存储模式。汇编语言程序采用.model伪指令,TurboC利用TCC选项-m指定各自的存储模式。相同的存储模式将自动产生相互兼容的调用和返回类型;同时,汇编程序的段定义伪指令.code、.data等也将产生与TurboC相兼容的段名称和属性。8.2

TurboC模块连接方式8.2.1混合编程的约定规则

连接前,C语言与汇编语言程序都有各自的代码段、数据段;而连接后,它们的代码段、数据段就合二为一或者彼此相关。需要特别说明的是,被连接的多个目标模块中,应当有一个并且只有一个具有起始模块。也就是说,某个C语言程序中应有main()函数,汇编语言程序不用定义起始执行点。而且由于共用一个堆栈段,混合编程时通常汇编语言程序无须设置堆栈段。8.2

TurboC模块连接方式8.2.3混合编程的参数传递123利用汇编程序编译汇编语言程序成为.obj目标代码文件。利用C编译程序编译C语言程序成为.obj目标代码文件。利用连接程序将各个目标代码文件连接在一起,得到可执行程序文件。8.2

TurboC模块连接方式8.2.3混合编程的参数传递C语言程序可以通过堆栈将参数传递给被调用函数。C程序调用函数之前,先从该函数中的最右边的参数开始依次将参数压入堆栈,最后压入最左边的参数,参数压入堆栈的顺序与实参表中参数的排列顺序相反。当被调用函数运行结束后,压入堆栈中的参数已无价值,C程序会立即调整堆栈指针SP,使之恢复压入参数以前的值,释放堆栈中为参数保留的空间。也就是说,堆栈的平衡是主函数程序实现的,子程序不必在返回时调整堆栈指针SP。这就是参数传递的C语言规则。(1)利用堆栈传递参数8.2

TurboC模块连接方式8.2.3汇编模块的编译和连接(2)返回值得传递

被调用函数的返回值,按下列规则传递给调用者:如果返回值小于或等于16位,则将其存放在AX寄存器中;如果返回值是32位,则存放在DX.AX寄存器对中,其中,DX存储高16位,AX存储低16位;如果返回值大于32位,则存放在静态变量存储区,AX寄存器存放指向这个存储区的偏移地址;对于32位far指针,则还利用DX存放段地址。8.2

TurboC模块连接方式8.2.3汇编模块的编译和连接

由此可见,汇编语言子程序向C程序返回处理结果时,是通过AX和DX完成的。但对于不同长度的返回数据,使用寄存器的情况也不同。8.2

TurboC模块连接方式8.2.3混合编程的参数传递(3)地址参数的传递

C语言程序的参数传递,可采用传数值和传地址两种方式。如果参数是传值的,可直接写出实际参数;如果参数是传址的,则在说明中将参数类型说明为指针类型,调用时,用“&”取得变量的地址作为实参传递。

在汇编语言子程序中,利用基址指针BP,先取得地址,再间接取内容,修改后送回原处,同时以RET返回。8.2

TurboC模块连接方式8.2.3混合编程的参数传递(3)地址参数的传递

以传址方式传送参数时,实际被压入堆栈的是参数所在的逻辑地址。这个地址也要分为近指针(仅含偏移地址)和远指针(含段地址和偏移地址)。C语言程序以tiny、small、compact模式编译时,它以near近指针传递地址,在堆栈占2字节;如果C语言程序以medium、large、huge模式编译,则地址是32位的远指针,在堆栈中要占4字节。8.2

TurboC模块连接方式8.2.3混合编程的参数传递(4)通过外部变量传递参数

混合编程中,参数的传递也可以通过共用外部变量实现。

C语言程序中也可使用汇编语言程序中的变量。此时,要求在汇编语言程序中将该变量用public进行说明,C程序中也必须用extern说明,并且数据类型对应一致。8.2

TurboC模块连接方式8.2.4汇编语言程序对C语言程序的调用123

为了使C函数对汇编语言程序可见,汇编语言程序需要对所调用的C语言函数、变量用关键字EXTERN进行说明。

参数的正确传递是混合编程的关键。

若汇编语言程序以无参数的形式调用一个C语言函数,那么,在C语言程序中对此函数进行定义时,函数后面应该跟一个空括号。若汇编语言子程序以传值方式向C语言函数传送数据,则C语言函数可用基本类型对参数进行说明;若汇编语言子程序以传址方式向C语言函数传送数据,则C语言函数应该使用指针类型对参数进行说明。8.2

TurboC模块连接方式8.2.4汇编语言程序对C语言程序的调用45

若C语言函数向汇编语言程序送返回值,则C语言函数体必须用return语句返回。如果返回值是一个字,则送给AX;如果为32位,则低16位在AX中,高16位在DX中;更多的数据则利用DX:AX返回指针。若没有返回值,可以不使用return语句。

一般C语言程序具有起始模块,即有主函数。这是由于高级语言程序假定某些初始化代码已经预先执行过了,故能确信在高级语言模块启动时,适当的初始化操作已经完成。这样,程序从C语言程序开始执行;然后调用汇编语言子程序,进而又调用C语言函数。8.3汇编语言在VisualC++中的应用8.3.1嵌入汇编语句指令

在VisualC++中嵌入汇编语句需要用到__asm关键字,这个关键字有两种使用方法:(1)汇编指令块方法:在__asm关键字后用一对花括号{}将汇编指令括起来。(2)单条汇编指令方法:在每条汇编指令之前加__asm关键字。8.3汇编语言在VisualC++中的应用8.3.1嵌入汇编语句指令在__asm块中使用汇编语言应注意以下几点:注

意(1)嵌入汇编完全支持的Intel486指令集,允许使用MMX指令。对于还不能支持的指令,VisualC++中可以使用_EMIT伪指令来扩展。_EMIT伪指令相当于MASM中的DB,一次定义一个字节内容,且只能用于程序代码段。(2)嵌入汇编可以使用所有的MASM表达式。8.3汇编语言在VisualC++中的应用8.3.1嵌入汇编语句指令在__asm块中使用汇编语言应注意以下几点:注

意(3)__asm块中允许使用C/C++的数据类型和对象,但不能使用MASM指示符和操作符来定义数据对象。这里需要特别指出的是,__asm块中不允许使用MASM中的定义指示符(DB、DW、DD、DQ、DT和DF),也不允许使用DUP和THIS操作符。MASM中的结构和记录也不再有效,嵌入汇编不接受STRUCT、RECORD、WIDTH或者MASK。(4)尽管嵌入汇编不支持大多数MASM指示符,但它支持EVEN和ALIGN,当需要时,这些指示符在汇编代码中加入NOP(空操作)指令使标号对齐到特定边界。这样可以使某些处理器取指令时具有更高的效率。8.3汇编语言在VisualC++中的应用8.3.1嵌入汇编语句指令在__asm块中使用汇编语言应注意以下几点:注

意(5)嵌入汇编不是宏汇编,不能使用MASM宏指示符(MACRO、REPT、IRC、IRP和ENDM)和宏操作符(<>、!、&、%和.TYPE)。(6)必须使用寄存器而不是名称来指明段(段名称“_TEXT”是无效的),并且段跨越必须显式地说明。8.3汇编语言在VisualC++中的应用8.3.1嵌入汇编语句指令在__asm块中使用汇编语言应注意以下几点:注

意(7)在内联汇编中,可以用LENGTH、SIZE和TYPE来获取C/C++变量和类型的大小。(8)嵌入汇编中可以使用C/C++风格的注释,也可以使用汇编语言的注释,即“;”。(9)一般来说,不能假定某个寄存器在__asm块开始的时候有已知的值。8.3汇编语言在VisualC++中的应用8.3.1嵌入汇编语句指令在__asm块中使用C++语言应注意以下几点:注

意(1)在嵌入汇编中可以使用C/C++变量以及很多其他的C/C++元素,包括符号(包括标号、变量和函数名)、常量(包括符号常量和枚举型成员)、宏定义和预处理指示符、注释(包括“/**/”和“//”)、类型名(包括所有MASM中合法的类型)及typedef名称(通常使用PTR和TYPE操作符,或者使用指定的的结构或枚举成员)。(2)在嵌入汇编中,可以使用C/C++或汇编语言的基数计数法,如0x100和100H是相等的。(3)嵌入汇编中不能使用如“<<”一类的C/C++专用操作符。但C/C++和MASM共有的操作符(如“*”和“[]”操作符),被认为是汇编语言的操作符,是可以使用的。8.3汇编语言在VisualC++中的应用8.3.1嵌入汇编语句指令在__asm块中使用C++语言应注意以下几点:注

意(4)在__asm块中可以引用所有在作用范围内的C/C++符号,包括变量名称、函数名称和标号,但是不能访问C++类的成员函数。此外,在嵌入汇编中使用C/C++符号还有一些其他限制:每条汇编语句只能包含一个C/C++符号(多个符号只能出现在LENGTH、TYPE或SIZE表达式中);在__asm块中引用函数必须先声明(否则,编译器将不能区别__asm块中的函数名和标号);在__asm块中不能使用对于MASM来说是保留字(不区分大小写)的C/C++符号;在__asm块中不能识别结构(Structure)和联合(union)标签。(5)嵌入汇编的一个方便之处是它可以使用名称来引用C/C++变量。8.2

TurboC模块连接方式8.3.1嵌入汇编语句指令123使用括号把__asm块包围住。

把__asm关键字放在每条汇编指令之前。使用经典C风格的注释(“/*内容*/”),不要使用汇编风格的注释(“;内容”)或单行的C/C++注释(“//内容”)。(6)使用C/C++宏可以方便地把汇编代码插入到源代码中。但是这其中需要额外地注意,因为宏将会扩展到一个逻辑行中。为了不出现问题,可以按以下规则编写宏:8.3汇编语言在VisualC++中的应用8.3.1嵌入汇编语句指令在__asm块中使用C++语言应注意以下几点:注

意(7)可以在C/C++程序中使用goto语句跳转到__asm块中的标号处,也可以在__asm块中转跳到__asm块里面或外面的标号处。__asm块内的标号是不区分大小写的(指令、指示符等也是不区分大小写的)。(8)嵌入汇编不仅可以编写C∕C++函数,还可以调用C函数(包括C库函数)和非重载的全局C++函数,也可以调用任何用extern"C"说明的函数,但不能调用C++的成员函数。因为所有的标准头文件都采用extern"C"说明库函数,所以C++程序中的嵌入式汇编可以调用C库函数。8.3汇编语言在VisualC++中的应用8.3.1嵌入汇编语句指令在__asm块中使用C++语言应注意以下几点:注

意(9)汇编语句通过参数名就可以引用参数,采用return语句返回出口参数。返回值的约定是:对于小于等于32位的数据扩展为32位,存放在EAX寄存器中返回;4~8字节的返回值存放在EDX.EAX寄存器对中返回;更大字节数据则将它们的地址指针存放在EAX中返回。8.3汇编语言在VisualC++中的应用8.3.2调用汇编语言模块VisualC++语言具有3种调用协议(callingconvention):_cdecl、_stdcall和_fastcall。VisualC++默认的是_cdecl方式,按从右至左的顺序压参数入栈,由调用者把参数弹出栈,而传送参数的内存栈是由调用者来维护的,返回值在EAX中。(1)采用一致的调用协议8.3汇编语言在VisualC++中的应用8.3.2调用汇编语言模块

WindowsAPI则采用_stdcall方式,按从右至左的顺序压参数入栈,由被调用者把参数弹出栈,而传送参数的内存栈是由被调用者来维护的,返回值在EAX中。_stdcall调用约定在输出函数名前加上一个下划线前缀,后面加上一个“@”符号和其参数的字节数_fastcall调用的主要特点是速度快,因为它是通过寄存器来传送参数的。实际上,它用ECX和EDX传送前两个双字(DWORD)或更小的参数,剩下的参数仍旧自右向左压栈传送,被调用的函数在返回前清理传送参数的内存栈,而传送参数的内存栈是由被调用者来维护的。_fastcall调用约定在输出函数名前加上一个“@”符号,后面也是一个“@”符号和其参数的字节数8.3汇编语言在VisualC++中的应用8.3.2调用汇编语言模块(2)声明公用函数名和变量名

对VisualC++和汇编语言使用的公用函数和变量应该进行声明,并且标识符应该一致,C++语言对标识符区分字母的大小写,而汇编不区分大小写。

在VisualC++语言程序中,采用extern"C"{}对所调用的函数和变量给予说明。说

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论