汇编语言基本关键字

合集下载

C语言中嵌套汇编语言

C语言中嵌套汇编语言

在Visual C++ 中使用内联汇编- -使用内联汇编可以在C/C++ 代码中嵌入汇编语言指令,而且不需要额外的汇编和连接步骤。

在Visual C++ 中,内联汇编是内置的编译器,因此不需要配置诸如MASM 一类的独立汇编工具。

这里,我们就以Visual Studio .NET 2003 为背景,介绍在Visual C++ 中使用内联汇的相关知识(如果是早期的版本,可能会有些许出入)。

内联汇编代码可以使用C/C++ 变量和函数,因此它能非常容易地整合到C/C++ 代码中。

它能做一些对于单独使用C/C++ 来说非常笨重或不可能完成的任务。

一、优点使用内联汇编可以在C/C++ 代码中嵌入汇编语言指令,而且不需要额外的汇编和连接步骤。

在Visual C++ 中,内联汇编是内置的编译器,因此不需要配置诸如MASM 一类的独立汇编工具。

这里,我们就以Visual Studio .NET 2003 为背景,介绍在Visual C++ 中使用内联汇的相关知识(如果是早期的版本,可能会有些许出入)。

内联汇编代码可以使用C/C++ 变量和函数,因此它能非常容易地整合到C/C++ 代码中。

它能做一些对于单独使用C/C++ 来说非常笨重或不可能完成的任务。

内联汇编的用途包括:使用汇编语言编写特定的函数;编写对速度要求非常较高的代码;在设备驱动程序中直接访问硬件;编写naked 函数的初始化和结束代码。

二、关键字使用内联汇编要用到__asm 关键字,它可以出现在任何允许C/C++ 语句出现的地方。

我们来看一些例子:简单的__asm 块:__asm{MOV AL, 2MOV DX, 0xD007OUT AL, DX}在每条汇编指令之前加__asm 关键字:__asm MOV AL, 2__asm MOV DX, 0xD007__asm OUT AL, DX因为__asm 关键字是语句分隔符,所以可以把多条汇编指令放在同一行:__asm MOV AL, 2 __asm MOV DX, 0xD007 __asm OUT AL, DX显然,第一种方法与C/C++ 的风格很一致,并且把汇编代码和C/C++ 代码清楚地分开,还避免了重复输入__asm 关键字,因此推荐使用第一种方法。

汇编语言

汇编语言

处理器指令格式汇编语言程序设计程序用程序设计语言编写,由指令构成指令由操作码和操作数(地址码)组成操作码(Opcode)表明处理器执行的操作►例如数据传送、加法运算、跳转等操作操作码操作数►汇编语言使用指令助记符表示操作数(Operand)是参与操作的数据对象►主要以寄存器名或地址形式指明数据的来源►汇编语言使用寄存器、常量、变量等形式表示传送指令的助记符:MOV(取自Move)►将数据从一个位置传送到另一个位置►类似高级语言的赋值语句mov dest,src;源操作数src:被传送的数据或数据所在的位置;目的操作数dest:数据将要传送到的位置mov dest,src 操作码操作数目的操作数dest 30H30H被传送的数据源操作数src使用最多、最基本的数据传送指令传送指令的助记符:MOV (取自Move )►将数据从一个位置传送到另一个位置►类似高级语言的赋值语句mov dest,src ;源操作数src :被传送的数据或数据所在的位置;目的操作数dest :数据将要传送到的位置mov eax, 100;EAX ←100 (常量)mov eax, dvar;EAX ←dvar (变量)mov eax,ebx;EAX ←EBX(寄存器)指令格式(Instruction Format处理器指令的二进制编码0~4字节1~3字节0/1字节0/1字节0/1/2/4字节0/1/2/4字节指令前缀操作码Mod R/MSIB位移量立即数代码格式(Code Format)机器代码(Machine Code)操作码操作数指令的一般格式IA-32处理器的指令格式低字节高字节IA-32处理器采用可变长度指令格式操作码►可选的指令前缀(用于扩展指令功能,0~4字节)►1~3字节的主要操作码操作数►可选的寻址方式域(包括ModR/M和SIB字段,0或1字节)►可选的位移量(0、1、2或4字节)►可选的立即数(0、1、2或4字节)mov eax,ebx ;机器代码:8B C3mov eax,[ebx] ;机器代码:8B 03mov eax,[ebx+esi*4+80h] ;机器代码:8B 84 B3 80 00 00 000~4字节1~3字节0/1字节0/1字节0/1/2/4字节0/1/2/4字节指令前缀操作码Mod R/M SIB位移量立即数IA-32处理器的指令格式低字节高字节汇编语言语句格式汇编语言程序设计源程序由语句组成通常一个语句常占一行(支持续行符“\”)一个语句不超过132个字符,4个部分执行性语句:表达处理器指令,实现功能标号: 硬指令助记符操作数, 操作数;注释 说明性语句:表达伪指令,控制汇编方式名字伪指令助记符参数, 参数, …;注释1. 标号与名字标号:执行性语句中标号与名字是用户定义的标识符►冒号分隔►表示处理器指令在主存中的逻辑地址►指示分支、循环等程序的目的地址名字:说明性语句中►空格或制表符分隔►变量名、段名、子程序名等►反映变量、段和子程序等的逻辑地址标识符(最多由31个字母、数字及规定的特殊符号组成►不能以数字开头►一个源程序中,用户定义的每个标识符必须唯一►不能是保留字(Reserved Word)=关键字(Key Word)•硬指令助记符:MOV …•伪指令助记符:BYTE …•操作符:OFFSET …•寄存器名:EAX …取名原则类似高级语言,但默认不区别大小写字母助记符是帮助记忆指令功能的符号►硬指令助记符表示处理器指令►伪指令助记符表达一个汇编命令处理器指令示例:传送指令MOV 伪指令示例:字节变量定义►助记符:BYTE (或DB )►功能:在主存占用若干存储空间,用于保存变量值msg byte 'Hello, Assembly !',13,10,0msg byte 'Hello, Assembly !',13,10,0处理器指令的操作数:表示参与操作的对象►具体的常量►保存在寄存器的数据►保存在存储器中的变量►逗号前常是目的操作数,逗号后常是源操作数 伪指令的参数:►常量、变量名、表达式等►可以有多个,参数之间用逗号分隔msg byte 'Hello, Assembly !',13,10,0msg byte 'Hello, Assembly !',13,10,0mov eax,offset msgmov eax,offset msg语句中分号后的内容是注释►对指令或程序进行说明,使用英文或中文均可►汇编程序不对它们做任何处理►注释利于阅读,应养成书写注释的好习惯►注释可以用分号开头,占用一个语句行;数据段的变量msg byte 'Hello, Assembly !',13,10,0 ;定义字符串;代码段的指令mov eax,offset msg ;EAX获得msg的偏移地址语句的4个组成部分要用分隔符分开►标号后的冒号►注释前的分号►操作数间和参数间的逗号►分隔其他部分采用一个或多个空格或制表符分隔符都是英文标点标号: 硬指令助记符 操作数, 操作数;注释名字 伪指令助记符 参数, 参数, … ;注释汇编语言不直接支持结构化程序设计为了清晰表达语句,以及整个源程序,建议:►标号和名字从首列开始书写►通过制表符对齐指令助记符和注释部分►助记符与操作数和参数之间用空格或者制表符分隔标号: 硬指令助记符操作数, 操作数;注释名字伪指令助记符参数, 参数, …;注释首列对齐对齐;执行性语句标号: 硬指令助记符操作数, 操作数;注释start: mov eax,offset msg ;EAX获得msg的偏移地址;说明性语句名字伪指令助记符参数, 参数, …;注释msg byte 'Hello, Assembly !',13,10,0 ;定义字符串源程序框架汇编语言程序设计汇编程序为汇编语言制定了严格的语法规范►例如,语句格式、标识符定义、保留字、注释符等 汇编程序也为源程序书写设计了框架结构►数据段、代码段等的定义►程序起始执行的位置►汇编结束的标示►…基于MASM 6.x简化段定义格式配合IO32.INC和IO32.LIB文件具备键盘输入和显示器输出子程序本书的MASM源程序框架;eg0000.asm in Windows Consoleinclude io32.inc ;包含32位输入输出文件.data ;定义数据段…;数据定义(数据待填).code ;定义代码段start: ;程序执行起始位置…;主程序(指令待填)exit 0 ;程序正常执行终止…;子程序(指令待填)end start ;汇编结束用于声明常用的常量定义、过程说明、共享的子程序库等►相当于C和C++语言中,包含头文件的作用本书的IO32.INC包含文件的前3个语句include io32.inc .686 ;32位指令.model flat,stdcall;选择平展模型,标准调用规范option casemap:none;告知MASM区分用户定义标识符的大小写MASM支持段的简化定义►数据段定义伪指令.DATA ;创建一个数据段►代码段定义伪指令.CODE ;创建一个代码段►堆栈段定义伪指令.STACK ;创建一个堆栈段(Windows自动维护堆栈段,用户可以不必设置)include io32.inc .data …;数据定义.code …;程序指令程序的开始和结束程序开始执行的位置►使用一个标号(例如:START )►作为汇编结束END 伪指令的参数 应用程序执行终止►语句“EXIT 0”终止程序执行►返回操作系统,并提供一个返回代码(0)源程序汇编结束►使用END 伪指令语句执行终止≠汇编结束执行终止≠汇编结束.codestart: …exit 0…end start;eg0000.asm in Windows Console include io32.inc.data;数据定义.codestart:;主程序exit 0;子程序end start;数据段…;代码段,主程序…;代码段,子程序…本书的简化表达信息显示程序汇编语言程序设计#include <stdio.h>int main(){printf("Hello, world !\n");exit(0);}Hello, world !显示信息printf("Hello, world !\n");在数据段给出这个字符串形式的信息:;数据段msg byte 'Hello, Assembly!',13,10,0;定义要显示的字符串在代码段编写显示字符串的程序:;代码段mov eax,offset msg ;指定字符串的偏移地址call dispmsg ;调用I/O子程序显示信息"Hello, world !\n""\n"printf( );字符串结尾字符;eg0000.asm in Windows Consoleinclude io32.inc .data;数据定义.codestart:;主程序exit 0;子程序end start;数据段…;代码段,主程序…;代码段,子程序…本书的简化表达;eg0101.asminclude io32.inc.data ;数据段msg byte 'Hello, Assembly!',13,10,0 .code ;代码段start: ;程序执行起始位置mov eax,offset msgcall dispmsgexit 0 ;程序正常执行终止end start ;汇编结束Hello, Assembly !运行结果汇编程序通常不提供任何函数或程序库必须利用操作系统的编程资源本书配套键盘输入和显示器输出的I/O子程序含IO32.INC和IO32.LIB,需要包含文件声明源程序文件开始使用包含命令声明INCLUDE IO32.INC 子程序调用方法MOV EAX,入口参数CALL 子程序名子程序名DISPMSG入口参数EAX=字符串地址功能说明显示字符串(以0结尾);数据段,字符串定义msg byte 'Hello, Assembly!',13,10,0 ;字符串;代码段,字符串显示mov eax,offset msg ;指定字符串的偏移地址call dispmsg ;调用I/O子程序显示信息C语言格式符子程序名功能说明printf("%s",a)DISPMSG显示字符串(以0结尾)printf("%c",a)DISPC显示一个字符printf("\n")DISPCRLF光标回车换行,到下行首列DISPRD显示8个32位通用寄存器内容DISPRF显示6个状态标志的状态printf("%X",a)DISPHD以十六进制形式显示8位数据printf("%u",a)DISPUID显示无符号十进制整数printf("%d",a)DISPSID显示有符号十进制整数C语言格式符子程序名功能说明scanf("%s",&a)READMSG输入一个字符串(回车结束)scanf("%c",&a)READC输入一个字符(回显)scanf("%X",&a)READHD输入8位十六进制数据scanf("%u",&a)READUID 输入无符号十进制整数(≤232-1)scanf("%d",&a)READSID 输入有符号十进制整数(-231~231-1)include io32.inc.datamsg byte 'Hello, Assembly!',13,10,0.code start: mov eax,offset msg call dispmsg exit 0end start 汇编语言程序#include <stdio.h>int main(){printf("Hello, world !\n");exit(0);}C语言程序。

汇编语言equ的用法

汇编语言equ的用法

汇编语言equ的用法汇编语言是一种底层的编程语言,直接操作计算机硬件,可以实现高效的算法和程序。

在汇编语言中,equ是一个非常重要的关键字,用于定义符号常量。

equ是equation的缩写,意思是“等式”。

在汇编语言中,我们可以使用equ关键字来定义一个符号常量,它的值在整个程序中不会发生改变。

这样做的好处是可以提高程序的可读性和可维护性,因为我们可以使用有意义的符号代替数字或字符串,更加清晰地表达程序的含义。

equ的语法格式为:符号名 equ 表达式其中符号名是我们所定义的常量的名字,可以使用任何合法的汇编语言标识符;表达式是一个算术表达式,可以包含数字、符号常量、运算符等。

下面是一个例子,定义了一个名为counter的符号常量,它的值为10:counter equ 10在程序中,我们可以使用counter代替数字10,如下所示:mov eax, counter ;将eax寄存器的值设置为10使用符号常量可以使程序更加易读易懂,并且方便修改。

如果我们要修改counter的值,只需要修改它的定义,整个程序中所有使用counter的地方都会自动更新。

除了定义数字常量,我们还可以使用equ定义字符串常量,如下所示:msg db 'Hello, world!', 0这里我们定义了一个字符串常量msg,它的值为“Hello, world!”,0是字符串的结束符号。

我们可以使用msg来输出这个字符串:mov eax, 4 ;调用系统调用4,输出字符串mov ebx, 1 ;输出到标准输出mov ecx, msg ;msg是字符串常量的符号名mov edx, 13 ;字符串的长度int 0x80 ;调用系统调用在程序中使用符号常量可以使程序更加清晰易懂,并且方便修改。

但是需要注意的是,符号常量只是一种宏定义,它不会分配内存空间,也不会检查定义的有效性。

因此,在使用符号常量时,需要确保其定义的正确性和合理性。

汇编语言---GCC内联汇编

汇编语言---GCC内联汇编

汇编语⾔---GCC内联汇编GCC⽀持在C/C++代码中嵌⼊汇编代码,这些代码被称作是"GCC Inline ASM"(GCC内联汇编);⼀、基本内联汇编GCC中基本的内联汇编⾮常易懂,格式如下:__asm__ [__volatile__] ("instruction list");其中,1.__asm__:它是GCC定义的关键字asm的宏定义(#define __asm__ asm),它⽤来声明⼀个内联汇编表达式,所以,任何⼀个内联汇编表达式都以它开头,它是必不可少的;如果要编写符合ANSI C标准的代码(即:与ANSI C兼容),那就要使⽤__asm__;2.__volatile__:它是GCC关键字volatile的宏定义;这个选项是可选的;它向GCC声明"不要动我所写的instruction list,我需要原封不动地保留每⼀条指令";如果不使⽤__volatile__,则当你使⽤了优化选项-O进⾏优化编译时,GCC将会根据⾃⼰的判断来决定是否将这个内联汇编表达式中的指令优化掉;如果要编写符合ANSI C标准的代码(即:与ANSI C兼容),那就要使⽤__volatile__;3.instruction list:它是汇编指令列表;它可以是空列表,⽐如:__asm__ __volatile__("");或__asm__("");都是合法的内联汇编表达式,只不过这两条语句什么都不做,没有什么意义;但并⾮所有"instruction list"为空的内联汇编表达式都是没意义的,⽐如:__asm__("":::"memory");就是⾮常有意义的,它向GCC声明:"我对内存做了改动",这样,GCC在编译的时候,就会将此因素考虑进去;例如:__asm__("movl %esp,%eax");或者是__asm__("movl 1,1,0x80");或者是__asm__("movl 1,1,0x80");instruction list的编写规则:当指令列表⾥⾯有多条指令时,可以在⼀对双引号中全部写出,也可将⼀条或多条指令放在⼀对双引号中,所有指令放在多对双引号中;如果是将所有指令写在⼀对双引号中,那么,相邻俩条指令之间必须⽤分号";"或换⾏符(\n)隔开,如果使⽤换⾏符(\n),通常\n后⾯还要跟⼀个\t;或者是相邻两条指令分别单独写在两⾏中;规则1:任意两条指令之间要么被分号(;)或换⾏符(\n)或(\n\t)分隔开,要么单独放在两⾏;规则2:单独放在两⾏的⽅法既可以通过\n或\n\t的⽅法来实现,也可以真正地放在两⾏;规则3:可以使⽤1对或多对双引号,每1对双引号⾥⾯可以放1条或多条指令,所有的指令都要放在双引号中;例如,下⾯的内联汇编语句都是合法的:__asm__("movl %eax,%ebx sti popl %edi subl %ecx,%ebx");__asm__("movl %eax,%ebx; sti popl %edi; subl %ecx,%ebx");__asm__("movl %eax,%ebx; sti\n\t popl %edi subl %ecx,%ebx");如果将指令放在多对双引号中,则,除了最后⼀对双引号之外,前⾯的所有双引号⾥的最后⼀条指令后⾯都要有⼀个分号(;)或(\n)或(\n\t);⽐如,下⾯的内联汇编语句都是合法的:__asm__("movl %eax,%ebx sti\n" "popl %edi;" "subl %ecx,%bx");__asm__("movl %eax,%ebx; sti\n\t" "popl %edi; subl %ecx,%ebx");__asm__("movl %eax,%ebx; sti\n\t popl %edi\n" "subl %ecx,%ebx"); ⼆、带有C/C++表达式的内联汇编GCC允许你通过C/C++表达式指定内联汇编中"instruction list"中的指令的输⼊和输出,你甚⾄可以不关⼼到底使⽤哪些寄存器,完全依靠GCC来安排和指定;这⼀点可以让程序员免去考虑有限的寄存器的使⽤,也可以提⾼⽬标代码的效率;1.带有C/C++表达式的内联汇编语句的格式:__asm__ [__volatile__]("instruction list":Output:Input:Clobber/Modify);圆括号中的内容被冒号":"分为四个部分:A. 如果第四部分的"Clobber/Modify"可以为空;如果"Clobber/Modify"为空,则其前⾯的冒号(:)必须省略;⽐如:语句 __asm__("movl%%eax,%%ebx":"=b"(foo):"a"(inp):);是⾮法的,⽽语句__asm__("movl %%eax,%%ebx":"=b"(foo):"a"(inp));则是合法的;B.如果第⼀部分的"instruction list"为空,则input、output、Clobber/Modify可以为空,也可以不为空;⽐如,语句__asm__("":::"memory");和语句__asm__(""::);都是合法的写法;C. 如果Output、Input和Clobber/Modify都为空,那么,Output、Input之前的冒号(:)可以省略,也可以不省略;如果都省略,则此汇编就退化为⼀个基本汇编,否则,仍然是⼀个带有C/C++表达式的内联汇编,此时"instruction list"中的寄存器的写法要遵循相关规定,⽐如:寄存器名称前⾯必须使⽤两个百分号(%%);基本内联汇编中的寄存器名称前⾯只有⼀个百分号(%);⽐如,语句__asm__("movl %%eax,%%ebx"::);__asm__("movl %%eax,%%ebx":);和语句__asm__("movl %%eax,%%ebx");都是正确的写法,⽽语句__asm__("movl %eax,%ebx"::);__asm__("movl%eax,%ebx":);和语句__asm__("movl %%eax,%%ebx");都是错误的写法;D.如果Input、Clobber/Modify为空,但Output不为空,则,Input前⾯的冒号(:)可以省略,也可以不省略;⽐如,语句__asm__("movl%%eax,%%ebx":"=b"(foo):);和语句__asm__("movl %%eax,%%ebx":"=b"(foo));都是正确的;E. 如果后⾯的部分不为空,⽽前⾯的部分为空,则,前⾯的冒号(:)都必须保留,否则⽆法说明不为空的部分究竟是第⼏部分;⽐如,Clobber/Modify、Output为空,⽽Input不为空,则Clobber/Modify前⾯的冒号必须省略,⽽Output前⾯的冒号必须保留;如果Clobber/Modify不为空,⽽Input和Output都为空,则Input和Output前⾯的冒号都必须保留;⽐如,语句 __asm__("movl %%eax,%%ebx"::"a"(foo));和__asm__("movl %%eax,%%ebx":::"ebx");注意:基本内联汇编中的寄存器名称前⾯只能有⼀个百分号(%),⽽带有C/C++表达式的内联汇编中的寄存器名⾂前⾯必须有两个百分号(%%);2.Output:Output部分⽤来指定当前内联汇编语句的输出,称为输出表达式;格式为: "操作约束"(输出表达式)例如:__asm__("movl%%rc0,%1":"=a"(cr0));这个语句中的Output部分就是("=a"(cr0)),它是⼀个操作表达式,指定了⼀个内联汇编语句的输出部分;Output部分由两个部分组成:由双引号括起来的部分和由圆括号括起来的部分,这两个部分是⼀个Output部分所不可缺少的部分;⽤双引号括起来的部分就是C/C++表达式,它⽤于保存当前内联汇编语句的⼀个输出值,其操作就是C/C++赋值语句"="的左值部分,因此,圆括号中指定的表达式只能是C/C++中赋值语句的左值表达式,即:放在等号=左边的表达式;也就是说,Output部分只能作为C/C++赋值操作左边的表达式使⽤;⽤双引号括起来的部分就指定了C/C++中赋值表达式的右值来源;这个部分被称作是"操作约束"(Operation Constraint),也可以称为"输出约束";在这个例⼦中的操作约束是"=a",这个操作约束包含两个组成部分:等号(=)和字母a,其中,等号 (=)说明圆括号中的表达式cr0是⼀个只写的表达式,只能被⽤作当前内联汇编语句的输出,⽽不能作为输⼊;字母a是寄存器EAX/AX/AL的缩写,说明cr0的值要从寄存器EAX中获取,也就是说cr0=eax,最终这⼀点被转化成汇编指令就是:movl %eax,address_of_cr0;注意:很多⽂档中都声明,所有输出操作的的操作约束都必须包含⼀个等号(=),但是GCC的⽂档中却明确地声明,并⾮如此;因为等号(=)约束说明当前的表达式是⼀个只写的,但是还有另外⼀个符号:加号(+),也可以⽤来说明当前表达式是可读可写的;如果⼀个操作约束中没有给出这两个符号中的任何⼀个,则说明当前表达式是只读的;因此,对于输出操作来说,肯定必须是可写的,⽽等号(=)和加号(+)都可表⽰可写,只不过加号(+)同时也可以表⽰可读;所以, 对于⼀个输出操作来说,其操作约束中只要包含等号(=)或加号(+)中的任意⼀个就可以了;等号(=)与加号(+)的区别:等号(=)表⽰当前表达式是⼀个纯粹的输出操作,⽽加号(+)则表⽰当前表达式不仅仅是⼀个输出操作,还是⼀个输⼊操作;但⽆论是等号(=)还是加号(+),所表⽰的都是可写,只能⽤于输出,只能出现在Output部分,⽽不能出现在Input部分;在Output部分可以出现多个输出操作表达式,多个输出操作表达式之间必须⽤逗号(,)隔开;3、Input:Input部分⽤来指定当前内联汇编语句的输⼊;称为输⼊表达式;格式为: "操作约束"(输⼊表达式)例如:__asm__("movl %0,%%db7"::"a"(cpu->db7));其中,表达式"a"(cpu->db7)就称为输⼊表达式,⽤于表⽰⼀个对当前内联汇编的输⼊;Input同样也由两部分组成:由双引号括起来的部分和由圆括号括起来的部分;这两个部分对于当前内联汇编语句的输⼊来说也是必不可少的;在这个例⼦中,由双引号括起来的部分是"a",⽤圆括号括起来的部分是(cpu->db7);⽤双引号括起来的部分就是C/C++表达式,它为当前内联汇编语句提供⼀个输⼊值;在这⾥,圆括号中的表达式cpu->db7是⼀个C/C++语⾔的表达式,它不必是左值表达式,也就是说,它不仅可以是放在C/C++赋值操作左边的表达式,还可以是放在C/C++赋值操作右边的表达式;所以,Input可以是⼀个变量、⼀个数字,还可以是⼀个复杂的表达式(如:a+b/c*d);⽐如,上例还可以这样写:__asm__("movl %0,%%db7"::"a"(foo));__asm__("movl%0,%%db7"::"a"(0x12345));__asm__("movl %0,%%db7"::"a"(va:vb/vc));⽤双引号括起来的部分就是C/C++中赋值表达式的右值表达式,⽤于约束当前内联汇编语句中的当前输⼊;这个部分也成为"操作约束",也可以成为是"输⼊约束";与输出表达式中的操作约束不同的是,输⼊表达式中的操作约束不允许指定等号(=)约束或加号(+)约束,也就是说,它只能是只读的;约束中必须指定⼀个寄存器约束;例⼦中的字母a表⽰当前输⼊变量cpu->db7要通过寄存器EAX输⼊到当前内联汇编语句中;三、操作约束:Operation Constraint操作约束只会出现在带有C/C++表达式的内联汇编语句中;每⼀个Input和Output表达式都必须指定⾃⼰的操作约束Operation Constraint;约束的类型有:寄存器约束、内存约束、⽴即数约束、通⽤约束;操作表达式的格式:"约束"(C/C++表达式)即:"Constraint"(C/C++ expression)1.寄存器约束:当你的输⼊或输出需要借助于⼀个寄存器时,你需要为其指定⼀个寄存器约束;可以直接指定⼀个寄存器名字;⽐如:__asm__ __volatile__("movl %0,%%cr0"::"eax"(cr0));也可以指定寄存器的缩写名称;⽐如:__asm__ __volatile__("movl %0,%%cr0"::"a"(cr0));如果指定的是寄存器的缩写名称,⽐如:字母a;那么,GCC将会根据当前操作表达式中C/C++表达式的宽度来决定使⽤%eax、%ax还是%al;⽐如:unsigned short __shrt;__asm__ __volatile__("movl%0,%%bx"::"a"(__shrt));由于变量__shrt是16位⽆符号类型m⼤⼩是两个字节,所以,编译器编译出来的汇编代码中,则会让此变量使⽤寄存器%ax;⽆论是Input还是Output操作约束,都可以使⽤寄存器约束;常⽤的寄存器约束的缩写:r:I/O,表⽰使⽤⼀个通⽤寄存器,由GCC在%eax/%ax/%al、%ebx/%bx/%bl、%ecx/%cx/%cl、%edx/%dx/%dl中选取⼀个GCC认为是合适的;q:I/O,表⽰使⽤⼀个通⽤寄存器,与r的意义相同;g:I/O,表⽰使⽤寄存器或内存地址;m:I/O,表⽰使⽤内存地址;a:I/O,表⽰使⽤%eax/%ax/%al;b:I/O,表⽰使⽤%ebx/%bx/%bl;c:I/O,表⽰使⽤%ecx/%cx/%cl;d:I/O,表⽰使⽤%edx/%dx/%dl;D:I/O,表⽰使⽤%edi/%di;S:I/O,表⽰使⽤%esi/%si;f:I/O,表⽰使⽤浮点寄存器;t:I/O,表⽰使⽤第⼀个浮点寄存器;u:I/O,表⽰使⽤第⼆个浮点寄存器;A:I/O,表⽰把%eax与%edx组合成⼀个64位的整数值;o:I/O,表⽰使⽤⼀个内存位置的偏移量;V:I/O,表⽰仅仅使⽤⼀个直接内存位置;i:I/O,表⽰使⽤⼀个整数类型的⽴即数;n:I/O,表⽰使⽤⼀个带有已知整数值的⽴即数;F:I/O,表⽰使⽤⼀个浮点类型的⽴即数;2.内存约束:如果⼀个Input/Output操作表达式的C/C++表达式表现为⼀个内存地址(指针变量),不想借助于任何寄存器,则可以使⽤内存约束;⽐如:__asm__("lidt %0":"=m"(__idt_addr));或__asm__("lidt %0"::"m"(__idt_addr));内存约束使⽤约束名"m",表⽰的是使⽤系统⽀持的任何⼀种内存⽅式,不需要借助于寄存器;使⽤内存约束⽅式进⾏输⼊输出时,由于不借助于寄存器,所以,GCC不会按照你的声明对其做任何的输⼊输出处理;GCC只会直接拿来使⽤,对这个C/C++ 表达式⽽⾔,究竟是输⼊还是输出,完全依赖于你写在"instruction list"中的指令对其操作的⽅式;所以,不管你把操作约束和操作表达式放在Input部分还是放在Output部分,GCC编译⽣成的汇编代码都是⼀样的,程序的执⾏结果也都是正确的;本来我们将⼀个操作表达式放在Input或Output部分是希望GCC能为我们⾃动通过寄存器将表达式的值输⼊或输出;既然对于内存约束类型的操作表达式来说,GCC不会为它做任何事情,那么放在哪⾥就⽆所谓了;但是从程序员的⾓度来看,为了增强代码的可读性,最好能够把它放在符合实际情况的地⽅;3.⽴即数约束:如果⼀个Input/Output操作表达式的C/C++表达式是⼀个数字常数,不想借助于任何寄存器或内存,则可以使⽤⽴即数约束;由于⽴即数在C/C++表达式中只能作为右值使⽤,所以,对于使⽤⽴即数约束的表达式⽽⾔,只能放在Input部分;⽐如:__asm__ __volatile__("movl %0,%%eax"::"i"(100));⽴即数约束使⽤约束名"i"表⽰输⼊表达式是⼀个整数类型的⽴即数,不需要借助于任何寄存器,只能⽤于Input部分;使⽤约束名"F"表⽰输⼊表达式是⼀个浮点数类型的⽴即数,不需要借助于任何寄存器,只能⽤于Input部分;4.通⽤约束:约束名"g"可以⽤于输⼊和输出,表⽰可以使⽤通⽤寄存器、内存、⽴即数等任何⼀种处理⽅式;约束名"0,1,2,3,4,5,6,7,8,9"只能⽤于输⼊,表⽰与第n个操作表达式使⽤相同的寄存器/内存;通⽤约束"g"是⼀个⾮常灵活的约束,当程序员认为⼀个C/C++表达式在实际操作中,⽆论使⽤寄存器⽅式、内存⽅式还是⽴即数⽅式都⽆所谓时,或者程序员想实现⼀个灵活的模板,以让GCC可以根据不同的C/C++表达式⽣成不同的访问⽅式时,就可以使⽤通⽤约束g;例如:#define JUST_MOV(foo) __asm__("movl %0,%%eax"::"g"(foo))则,JUST_MOV(100)和JUST_MOV(var)就会让编译器产⽣不同的汇编代码;对于JUST_MOV(100)的汇编代码为:#APPmovl $100,%eax #⽴即数⽅式;#NO_APP对于JUST_MOV(var)的汇编代码为:#APPmovl 8(%ebp),%eax #内存⽅式;#NO_APP像这样的效果,就是通⽤约束g的作⽤;5.修饰符:等号(=)和加号(+)作为修饰符,只能⽤于Output部分;等号(=)表⽰当前输出表达式的属性为只写,加号(+)表⽰当前输出表达式的属性为可读可写;这两个修饰符⽤于约束对输出表达式的操作,它们俩被写在输出表达式的约束部分中,并且只能写在第⼀个字符的位置;符号&也写在输出表达式的约束部分,⽤于约束寄存器的分配,但是只能写在约束部分的第⼆个字符的位置上;⽤符号&进⾏修饰时,等于向GCC声明:"GCC不得为任何Input操作表达式分配与此Output操作表达式相同的寄存器";其原因是修饰符&意味着被其修饰的Output操作表达式要在所有的Input操作表达式被输⼊之前输出;即:GCC会先使⽤输出值对被修饰符&修饰的Output操作表达式进⾏填充,然后,才对Input操作表达式进⾏输⼊;这样的话,如果不使⽤修饰符&对Output操作表达式进⾏修饰,⼀旦后⾯的Input操作表达式使⽤了与Output操作表达式相同的寄存器,就会产⽣输⼊输出数据混乱的情况;相反,如果没有⽤修饰符&修饰输出操作表达式,那么,就意味着GCC会先把Input操作表达式的值输⼊到选定的寄存器中,然后经过处理,最后才⽤输出值填充对应的Output操作表达式;所以, 修饰符&的作⽤就是要求GCC编译器为所有的Input操作表达式分配别的寄存器,⽽不会分配与被修饰符&修饰的Output操作表达式相同的寄存器;修饰符&也写在操作约束中,即:&约束;由于GCC已经规定加号(+)或等号(=)占据约束的第⼀个字符,那么& 约束只能占⽤第⼆个字符;例如:int __out, __in1, __in2;__asm__("popl %0\n\t""movl %1,%%esi\n\t""movl %2,%%edi\n\t":"=&a"(__out):"r"(__in1),"r"(__in2));注意: 如果⼀个Output操作表达式的寄存器约束被指定为某个寄存器,只有当⾄少存在⼀个Input操作表达式的寄存器约束为可选约束(意思是GCC可以从多个寄存器中选取⼀个,或使⽤⾮寄存器⽅式)时,⽐如"r"或"g"时,此Output操作表达式使⽤符号&修饰才有意义;如果你为所有的Input操作表达式指定了固定的寄存器,或使⽤内存/⽴即数约束时,则此Output操作表达式使⽤符号&修饰没有任何意义;⽐如:__asm__("popl%0\n\t" "movl %1,%esi\n\t" "movl %2,%edi\n\t" :"=&a"(__out) :"m"(__in1),"c"(__in2));此例中的Output操作表达式完全没有必要使⽤符号&来修饰,因为__in1和__in2都已经被指定了固定的寄存器,或使⽤了内存⽅式,GCC⽆从选择;如果你已经为某个Output操作表达式指定了修饰符&,并指定了固定的寄存器,那么,就不能再为任何Input操作表达式指定这个寄存器了,否则会出现编译报错;⽐如:__asm__("popl %0; movl %1,%%esi; movl %2,%%edi;":"=&a"(__out):"a"(__in1),"c"(__in2));对这条语句的编译就会报错;相反,你也可以为Output指定可选约束,⽐如"r"或"g"等,让GCC为此Output操作表达式选择合适的寄存器,或使⽤内存⽅式,GCC在选择的时候,会排除掉已经被Input操作表达式所使⽤过的所有寄存器,然后在剩下的寄存器中选择,或者⼲脆使⽤内存⽅式;⽐如:__asm__("popl %0; movl %1,%%esi; movl %2,%%edi;":"=&r" (__out):"a"(__in1),"c"(__in2));这三个修饰符只能⽤在Output操作表达式中,⽽修饰符%则恰恰相反,它只能⽤在Input操作表达式中;修饰符%⽤于向GCC声明:"当前Input操作表达式中的C/C++表达式可以与下⼀个Input操作表达式中的C/C++表达式互换";这个修饰符⼀般⽤于符合交换律运算的地⽅;⽐如:加、乘、按位与&、按位或|等等;例如:__asm__("addl %1,%0\n\t":"=r"(__out):"%r"(__in1),"0"(__in2));其中,"0"(__in2)表⽰使⽤与第⼀个Input操作表达式("r"(__in1))相同的寄存器或内存;由于使⽤符号%修饰__in1的寄存器⽅式r,那么就表⽰,__in1与__in2可以互换位置;加法的两个操作数交换位置之后,和不变;修饰符 I/O 意义= O 表⽰此Output操作表达式是只写的+ O 表⽰此Output操作表达式是可读可写的& O 表⽰此Output操作表达式独占为其指定的寄存器% I 表⽰此Input操作表达式中的C/C++表达式可以与下⼀个Input操作表达式中的C/C++表达式互换四、占位符每⼀个占位符对应⼀个Input/Output操作表达式;带C/C++表达式的内联汇编中有两种占位符:序号占位符和名称占位符;1.序号占位符:GCC 规定:⼀个内联汇编语句中最多只能有10个Input/Output操作表达式,这些操作表达式按照他们被列出来的顺序依次赋予编号0到9;对于占位符中的数字⽽⾔,与这些编号是对应的;⽐如:占位符%0对应编号为0的操作表达式,占位符%1对应编号为1的操作表达式,依次类推;由于占位符前⾯要有⼀个百分号%,为了去边占位符与寄存器,GCC规定:在带有C/C++表达式的内联汇编语句的指令列表⾥列出的寄存器名称前⾯必须使⽤两个百分号(%%),⼀区别于占位符语法;GCC对占位符进⾏编译的时候,会将每⼀个占位符替换为对应的Input/Output操作表达式所指定的寄存器/内存/⽴即数;例如:__asm__("addl %1,%0\n\t":"=a"(__out):"m"(__in1),"a"(__in2));这个语句中,%0对应Output操作表达式"=a"(__out),⽽"=a"(__out)指定的寄存器是%eax,所以,占位符%0被替换为%eax;占位符%1对应Input操作表达式"m"(__in1),⽽"m"(__in1)被指定为内存,所以,占位符%1被替换位__in1的内存地址;⽤⼀句话描述:序号占位符就是前⾯描述的%0、%1、%2、%3、%4、%5、%6、%7、%8、%9;其中,每⼀个占位符对应⼀个Input/Output的C/C++表达式;2.名称占位符:由于GCC中限制这种占位符的个数最多只能由这10个,这也就限制了Input/Output操作表达式中C/C++表达式的数量做多只能有10个;如果需要的C/C++表达式的数量超过10个,那么,这些需要占位符就不够⽤了;GCC内联汇编提供了名称占位符来解决这个问题;即:使⽤⼀个名字字符串与⼀个C/C++表达式对应;这个名字字符串就称为名称占位符;⽽这个名字通常使⽤与C/C++表达式中的变量完全相同的名字;使⽤名字占位符时,内联汇编的Input/Output操作表达式中的C/C++表达式的格式如下:[name] "constraint"(变量)此时,指令列表中的占位符的书写格式如下:%[name]这个格式等价于序号占位符中的%0,%1,$2等等;使⽤名称占位符时,⼀个name对应⼀个变量;例如:__asm__("imull %[value1],%[value2]":[value2] "=r"(data2):[value1] "r"(data1),"0"(data2));此例中,名称占位符value1就对应变量data1,名称占位符value2对应变量data2;GCC编译的时候,同样会把这两个占位符分别替换成对应的变量所使⽤的寄存器/内存地址/⽴即数;⽽且也增强了代码的可读性;这个例⼦,使⽤序号占位符的写法如下:__asm__("imull %1,%0":"=r"(data2):"r"(data1),"0"(data2));五、寄存器/内存修改标⽰(Clobber/Modify)有时候,当你想通知GCC当前内联汇编语句可能会对某些寄存器或内存进⾏修改,希望GCC在编译时能够将这⼀点考虑进去;那么你就可以在Clobber/Modify部分声明这些寄存器或内存;1.寄存器修改通知:这种情况⼀般发⽣在⼀个寄存器出现在指令列表中,但⼜不是Input/Output操作表达式所指定的,也不是在⼀些Input/Output操作表达式中使⽤"r"或"g"约束时由GCC选择的,同时,此寄存器被指令列表中的指令所修改,⽽这个寄存器只供当前内联汇编语句使⽤的情况;⽐如:__asm__("movl %0,%%ebx"::"a"(__foo):"bx");//这个内联汇编语句中,%ebx出现在指令列表中,并且被指令修改了,但是却未被任何Input/Output操作表达式是所指定,所以,你需要在Clobber/Modify部分指定"bx",以让GCC知道这⼀点;因为你在Input/Output操作表达式中指定的寄存器,或当你为⼀些Input/Output操作表达式使⽤"r"/"g"约束,让GCC为你选择⼀个寄存器时,GCC对这些寄存器的状态是⾮常清楚的,它知道这些寄存器是被修改的,你根本不需要在Clobber/Modify部分声明它们;但除此之外,GCC对剩下的寄存器中哪些会被当前内联汇编语句所修改则⼀⽆所知;所以,如果你真的在当前内联汇编指令中修改了它们,那么就最好在 Clobber/Modify部分声明它们,让GCC针对这些寄存器做相应的处理;否则,有可能会造成寄存器不⼀致,从⽽造成程序执⾏错误;在Clobber/Modify部分声明这些寄存器的⽅法很简单,只需要将寄存器的名字⽤双引号括起来就可以;如果要声明多个寄存器,则相邻两个寄存器名字之间⽤逗号隔开;例如:__asm__("movl %0,%%ebx; popl %%ecx"::"a"(__foo):"bx","cx");这个语句中,声明了bx和cx,告诉GCC:寄存器%ebx和%ecx可能会被修改,要求GCC考虑这个因素;寄存器名称串:"al"/"ax"/"eax":代表寄存器%eax"bl"/"bx"/"ebx":代表寄存器%ebx"cl"/"cx"/"ecx":代表寄存器%ecx"dl"/"dx"/"edx":代表寄存器%edx"si"/"esi":代表寄存器%esi"di"/"edi":代表寄存器%edi所以,只需要使⽤"ax","bx","cx","dx","si","di"就可以了,因为他们都代表对应的寄存器;如果你在⼀个内敛汇编语句的Clobber/Modify部分向GCC声明了某个寄存器内存发⽣了改变,GCC在编译时,如果发现这个被声明的寄存器的内容在此内联汇编之后还要继续使⽤,那么,GCC会⾸先将此寄存器的内容保存起来,然后在此内联汇编语句的相关代码⽣成之后,再将其内容回复;另外需要注意的是,如果你在Clobber/Modify部分声明了⼀个寄存器,那么这个寄存器将不能再被⽤作当前内敛汇编语句的Input/Output操作表达式的寄存器约束,如果Input/Output操作表达式的寄存器约束被指定为"r"/"g",GCC也不会选择已经被声明在Clobber /Modify部分中的寄存器;例如:__asm__("movl %0,%%ebx"::"a"(__foo):"ax","bx");这条语句中的Input操作表达式"a"(__foo)中已经指定了寄存器%eax,那么在Clobber/Modify部分中个列出的"ax"就是⾮法的;编译时,GCC会报错;2.内存修改通知:除了寄存器的内容会被修改之外,内存的内容也会被修改;如果⼀个内联汇编语句的指令列表中的指令对内存进⾏了修改,或者在此内联汇编出现的地⽅,内存内容可能发⽣改变,⽽被改变的内存地址你没有在其Output操作表达式中使⽤"m"约束,这种情况下,你需要使⽤在Clobber/Modify部分使⽤字符串"memory"向GCC声明:"在这⾥,内存发⽣了,或可能发⽣了改变";例如:void* memset(void* s, char c, size_t count){__asm__("cld\n\d""rep\n\t""stosb":/*no output*/:"a"(c),"D"(s),"c"(count):"cx","di","memory");return s;}如果⼀个内联汇编语句的Clobber/Modify部分存在"memory",那么GCC会保证在此内联汇编之前,如果某个内存的内容被装⼊了寄存器,那么,在这个内联汇编之后,如果需要使⽤这个内存处的内容,就会直接到这个内存处重新读取,⽽不是使⽤被存放在寄存器中的拷贝;因为这个时候寄存器中的拷贝很可能已经和内存处的内容不⼀致了;3.标志寄存器修改通知:当⼀个内联汇编中包含影响标志寄存器eflags的条件,那么也需要在Clobber/Modify部分中使⽤"cc"来向GCC声明这⼀点;。

汇编语言关键字

汇编语言关键字

汇编语言关键字在计算机科学领域中,汇编语言是一种低级别的编程语言,用于与计算机硬件进行直接交互。

它是计算机指令的文本表示,由一系列的关键字组成。

了解和熟悉汇编语言的关键字对于理解计算机底层运行机制以及进行系统级编程至关重要。

本文将介绍一些常见的汇编语言关键字,帮助读者了解其功能和用法。

一、数据传输指令数据传输指令用于将数据从一个位置传输到另一个位置。

以下是几个常见的数据传输指令:1. MOV:MOV指令用于将一个数据从一个位置复制到另一个位置。

它可以用于将数据从寄存器传输到内存,或者从内存传输到寄存器。

2. PUSH:用于将数据压入堆栈中。

堆栈是一种后进先出(LIFO)的数据结构,常用于存储临时变量和函数调用返回地址。

3. POP:与PUSH相反,POP指令用于将数据从堆栈中弹出,并存储到指定的位置。

二、算术和逻辑指令算术和逻辑指令用于对数据进行算术和逻辑运算。

以下是一些常用的算术和逻辑指令:1. ADD:用于将两个数相加,并将结果保存在指定位置。

可以用于寄存器之间的相加,也可以用于寄存器和内存之间的相加。

2. SUB:与ADD类似,SUB指令用于将一个数减去另一个数,并将结果保存在指定位置。

3. AND:用于执行按位与运算。

将两个数的每个对应位作与操作,并将结果保存在指定位置。

4. OR:与AND指令类似,OR指令用于执行按位或运算。

5. XOR:用于执行按位异或运算。

将两个数的每个对应位作异或操作,并将结果保存在指定位置。

三、分支和循环指令分支和循环指令用于控制程序的流程和执行顺序。

以下是一些常用的分支和循环指令:1. JMP:JMP指令用于无条件跳转到指定的地址。

可以用于实现程序的跳转和循环。

2. JZ和JNZ:JZ指令用于在前一个操作的结果为零时跳转到指定地址,而JNZ则相反,用于在结果不为零时跳转。

3. CMP:CMP指令用于比较两个数据的大小关系,并根据比较结果设置标志位,用于后续的条件跳转。

汇编语言学习第4章

汇编语言学习第4章

不同而不同。
(名字项,常称为标号) 标号是程序设计人员自己定义的表示符号,用来表示本语句的符号地址
(即该指令的偏移地址,也就是该单元与其所处段基址的偏移量)是可有
可无的,只有当需要用符号地址来访问该语句时才需要。 2.operation(操作符)
操作符项可以是指令、伪操作或宏指令的助记符。对于指令,作用是指出
1.等价语句EQU
等价语句的一般使用格式如下: SYMBOL EQU EXPRESSION
作用是用左边的符号名代表右边的表达式。
注意:等价语句不会给符号名分配存储空间,符号名不能与其它符号同名, 也不能被重新定义。
(1)用符号名代表常量或表达式
例4.14 (2)用符号名代表字符串 例4.15 (3)用符号名代表关键字或指令助记符 例4.16
例4.21
2.定义字变量的伪指令为DW
一个变量占一个字空间
例4.22:WORD1 DW DW 89H, 1909H, -1 0ABCDH, ?, 0
上面的定义语句经汇编后所产生出的内存单元分配情况如下:
… 89 00 09 19 FF FF CD AB --00 00 …
例4.23
3.双字变量定义伪指令DD 每个双字变量占用二个连续的字单元(四个字节)。
功能和作用,而不应该只写出指令的动作。
4.2运算符号
4.2.1算术运算符
算术运算符有:+、-、*、/和MOD。 其中: +、-、*、/就是我们算术中常用的加、减、乘、除。 MOD算符是模运算。指除法运算后得到的余数。 例如:5 MOD 2为1。 注意:算术运算符可以用于数字表达式或地址表达式中,但当它用于地址 表达式时,只有当其结果有明确的物理意义时才是有效的。 例如:将两个地址相乘或相除是无意义的。地址可以做加减运算,但也必 须注意物理意义。例如把两个不同段的地址相加减也是无意义的。 例4.1 例4.2

汇编语言switch语句

汇编语言switch语句

汇编语言switch语句什么是汇编语言?汇编语言是一种低级程序设计语言,用于与计算机硬件直接交互。

与高级语言相比,汇编语言更接近机器码,可以直接操作计算机的寄存器、内存和输入输出设备。

汇编语言的指令由操作码和操作数组成,使用助记符代替了机器码的二进制表示,更易于理解和编写。

在汇编语言中,switch语句可以让程序根据不同的情况执行不同的代码块。

它通常用于处理多重条件判断,实现分支控制逻辑。

switch语句的基本语法如下所示:switch (expression){case constant1:执行代码块1break;case constant2:执行代码块2break;case constant3:执行代码块3break;default:默认执行代码块break;}其中,expression是一个表达式或变量,用于进行判断;constant1、constant2等是常量,与expression进行比较。

如果expression的值与某个常量匹配,则执行相应的代码块,直到遇到break语句或switch语句结束。

如果没有匹配的常量,将执行default后的代码块。

下面将逐步回答关于汇编语言switch语句的一些常见问题。

一、如何在汇编语言中实现switch语句的功能?在汇编语言中,由于没有switch关键字,我们需要使用条件分支和跳转指令来实现类似的功能。

一般情况下,可以使用cmp指令将expression 的值与每个常量进行比较,再选择对应的代码块执行。

如果没有匹配的常量,可以通过无条件跳转指令(jmp)执行default后的代码块。

二、如何处理switch语句中的多个常量情况?为了实现多个常量的判断,可以使用多个cmp指令。

比如,对于三个常量的情况,可以使用三个cmp指令将expression的值与每个常量进行比较,再根据比较结果选择执行相应的代码块。

三、如何避免代码块之间的控制流乱跳?为了避免代码块之间的控制流乱跳,我们需要使用跳转指令来明确指示接下来应该执行的代码块。

集合知识点总结[汇编]

集合知识点总结[汇编]

集合知识点总结[汇编]一、汇编语言基础1、汇编语言是一种低级的机器语言,它是由机器指令和操作数构成的。

汇编语言帮助计算机硬件完成如输入/输出操作和内存管理等操作;2、汇编语言与高级语言的最大区别是,汇编语言的执行效率更高,但是在程序的开发上需要更多的努力,需要使用许多汇编指令来实现;3、汇编语言是由一系列指令构成的,指令可以被分为四种:控制指令、储存器操作指令、数据传输指令、计算指令等;4、汇编语言有许多共同的特点,如易于学习,编写简单,可以轻松实现多种操作等;5、汇编语言中有许多指令,如:MOV指令用于对寄存器的操作,ADD指令用于实现二进制数的加法,CMP指令用于实现二进制数的比较等;二、汇编语言的数据类型1、汇编语言的数据类型有无符号数据、有符号数据、比特(bit)、字节(byte)、字(word)、双字(double word)、四字(quad word)等;2、无符号数据是指没有正负号,即汇编语言中只用二进制;3、有符号数据是指含有正负号;4、比特是指由0或1组成的一个二进制数据,也就是最小的数据单位;5、字节是汇编中的一个基本数据单位,由8个比特组成;6、字是汇编中的一个基本数据单位,由16个比特组成;7、双字是汇编中的一个基本数据单位,由32个比特组成;4、四字是汇编中的一个基本数据单位,由64个比特组成。

三、汇编语言指令1、单操作数指令:单操作数指令是指汇编语言中只有一个操作数的指令,如INC、DEC、PUSH、POP等;2、双操作数指令:双操作数指令是指汇编语言中有两个操作数的指令,如MOV、ADD、SUB等;3、控制指令:控制指令是指能实现程序的控制、跳转和循环的指令,如JMP、LOOP、JB、JZ等;4、汇编关键字:汇编关键字是与汇编中的指令和数据有关的一些字,如DB、DW、DD 等;5、立即数指令:立即数指令是指指令的操作数是一个数值而不是地址的指令,如MOV AL,78H等。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

汇编语言基本关键字
aaa对非压缩BCD码加法之和调整
aas对非压缩BCD码减法之差调整
aam乘法调整aad被除数调整
add不带进位标志位的加法adc带进位标志位的加法
and逻辑与
assume指定段寄存器
bswap双字单操作数内部交换
bt位测试bts位测试并置一
btr位测试并清零btc位测试并取反
bsf/bsr正,反向位扫描
call调用
cbw字节转换为字cwd字转换为双字cwde字转换为扩展的双字cdq双字转换为四字
cmp比较cmpxchg比较并交换
cmps串比较
code定义简化代码段
const定义简化常数数据段
daa对压缩BCD码加法之和调整das对压缩BCD码减法之差调整
data定义简化数据段
db/dw/dd/dq/dt定义字节/字/双字/四字/十字变量
dec减一
df定义32位便宜地址的远地址指针
div无符号数除法
equ等价textequ文本等价
even取偶偏移地址
fardata,fardata定义简化独立数据段
group定义段组
idiv有符号整数除法
imul有符号整数乘法
in输入
inc加一
ins/outs输入/输出串元素
jcxz/jecxz若cx=0/ecx=0,跳转
jmpdopd无条件跳转到DOPD处取出指令继续执行
label为$定义符号
Lahf标志位低八位送AH
lea偏移地址送通用寄存器lda传送进入数据段的地址指针
les传送进入附加数据段的地址指针lfs传送进入FS段的地址指针
lgs传送进入GS段的地址指针lss传送进入堆栈段的地址指针
local说明局部变量
lods读出串元素
Loop/loopd无条件循环cx/ecx为循环次数
loopnz/loopnzd非零或不等时循环,cx/ecx为循环次数
loopz/loopzd为零或相等时循环,cx/ecx为循环次数
model存储模式
MOV传送movsx符号扩展传送,movzx零扩展传送
movs串传送
mul无符号数乘法
neg求负
not逻辑非
offset得到操作数的偏移地址
or逻辑或
org设置段内偏移地址
out输出
pop出栈popa所有16为寄存器出栈popad所有32位寄存器出栈popf标志出栈
proc,endp过程定义
ptr合成操作符p88
purge取消宏定义p191
push进栈pusha所有16位寄存器进栈pushad所有32位寄存器进栈pushf标志进栈rcl/rcr包含进位的左,右循环移位
rep无条件重复前缀
repe相等或为零时,重复前缀
repne不相等,不为零,重复前缀
ret返回
rol/ror不包含进位的左,右循环移位
sahf AH送标志位寄存器低八位
sbb带减借位标志位的减法sub不带减借位标志位的减法
sbyte/sword/sdword定义有符号的字节,字,双字,变量
scas搜索串
seg得到操作数的段基址
segment,ends定义完整段
shl/shr逻辑左移、右移sal/sar算术左移,右移
shld/shrd双精度左,右移
stack定义简化堆栈段
startup/exit程序开始,结束
stos存储串元素
struc/struct定义结构数据类型
test测试
type得到变量一个数据项的字节数
xadd交换并相加
xchg两操作数相互交换
xor逻辑异或。

相关文档
最新文档