用AI赚第一桶💰低成本搭建一套AI赚钱工具,源码可二开。 广告
[TOC] ## 整数常量 整数常量(integer literal)(又称为整型常量(integer constant))由一个可选前置符号、一个或多个数字,以及一个指明其基数的可选基数字符构成: ``` [{+|-}] digits [radix] ``` 由此,比如 26 就是一个有效的整数常量。它没有基数,所以假设其是十进制形式。如果想要表示十六进制数 26,就将其写为 26h。同样,数字 1101 可以被看做是十进制值,除非在其末尾添加“b”,使其成为 1101b (二进制)。下表列出了可能的基数值: | 标识符 | 描述 | | --- | --- | | h | 十六进制 | | q/o | 八进制 | | d | 十进制 | | b | 二进制 | | r | 实数 | | t | 十进制 (备用) | | y | 十进制 (备用) | 下面这些整数常量声明了各种基数。每行都有注释: ``` 26 ;十进制 26d ;十进制 11010011b ;二进制 42q ;八进制 42o ;八进制 1Ah ;十六进制 0A3h ;十六进制 ``` ## 保留字 保留字(reserved words)有特殊意义并且只能在其正确的上下文中使用。默认情况下,保留字是没有大小写之分的。比如,MOV 与 mov、Mov 是相同的。 保留字有不同的类型: * 指令助记符,如 MOV、ADD 和 MUL。 * 寄存器名称。 * 伪指令,告诉汇编器如何汇编程序。 * 属性,提供变量和操作数的大小与使用信息。例如 BYTE 和 WORD。 * 运算符,在常量表达式中使用。 * 预定义符号,比如 @data,它在汇编时返回常量的整数值。 下表是常用的保留字列表。 | | | | | | --- | --- | --- | --- | | $ | PARITY? | DWORD| STDCALL | |? | PASCAL FAR |SWORD | |@B |QWORD |FAR16 |SYSCALL | |@F |REAL4 |FORTRAN |TBYTE | |ADDR | REAL8 |FWORD |VARARG | |BASIC | REAL10 |NEAR | WORD | |BYTE |SBYTE |NEAR16 |ZERO? | |C |SDORD |OVERFLOW? | |CARRY? | SIGN? | ## 标识符 标识符(identifier)是由程序员选择的名称,它用于标识变量、常数、子程序和代码标签。 标识符的形成有一些规则: * 可以包含 1 到 247 个字符。 * 不区分大小写。 * 第一个字符必须为字母 (A---Z, a---z) A 下划线 (\_)、@、? 或 $。其后的字符也可以是数字。 * 标识符不能与汇编器保留字相同。 > 提示:可以在运行汇编器时,添加 -Cp 命令行切换项来使得所有关键字和标识符变成大小写敏感。 下面是一些命名良好的名称: ``` lineCount     firstValue       index       line_count myFile          xCoord           main       x_Coord ``` 下面的名称合法,但是不可取: ``` _lineCount       $first        @myFile ``` 一般情况下,应避免用符号 @ 和下划线作为第一个字符,因为它们既用于汇编器,也用于高级语言编译器。 ## 伪指令 伪指令 (directive) 是嵌入源代码中的命令,由汇编器识别和执行。伪指令不在运行时执行,但是它们可以定义变量、宏和子程序;为内存段分配名称,执行许多其他与汇编器相关的日常任务。 默认情况下,伪指令不区分大小写。例如,.data,.DATA 和 .Data 是相同的。 ### 定义段 汇编器伪指令的一个重要功能是定义程序区段,也称为段 (segment)。程序中的段具有不同的作用。如下面的例子,一个段可以用于定义变量,并用 .DATA 伪指令进行标识: ``` .data ``` .CODE 伪指令标识的程序区段包含了可执行的指令: ``` .code ``` .STACK 伪指令标识的程序区段定义了运行时堆栈,并设置了其大小: ``` .stack 100h ``` 与 = 伪指令不同,在同一源代码文件中,用 EQU 定义的符号不能被重新定义。这个限制可以防止现有符号在无意中被赋予新值。 ## 指令 指令(instruction)是一种语句,它在程序汇编编译时变得可执行。汇编器将指令翻译为机器语言字节,并且在运行时由 CPU 加载和执行。 一条指令有四个组成部分: * 标号(可选) * 指令助记符(必需) * 操作数(通常是必需的) * 注释(可选) ### 标号 标号(label)是一种标识符,是指令和数据的位置标记。标号位于指令的前端,表示指令的地址。同样,标号也位于变量的前端,表示变量的地址。标号有两种类型:数据标号和代码标号。 数据标号标识变量的位置,它提供了一种方便的手段在代码中引用该变量。比如,下面定义了一个名为 count 的变量: ```asm count DWORD 100 ``` 汇编器为每个标号分配一个数字地址。可以在一个标号后面定义多个数据项。在下面的例子中,array 定义了第一个数字(1024)的位置,其他数字在内存中的位置紧随其后: ```asm array DWORD 1024, 2048 DWORD 4096, 8192 ``` 程序代码区(指令所在区段)的标号必须用冒号(:)结束。代码标号用作跳转和循环指令的目标。例如,下面的 JMP 指令创建一个循环,将程序控制传递给标号 target 标识的位置: ```asm target: mov ax,bx ... jmp target ``` 代码标号可以与指令在同一行上,也可以自己独立一行: ```asm L1: mov ax, bxL2 : ``` >标号命名规则要求,只要每个标号在其封闭子程序页中是唯一的,那么就可以多次使用相同的标号。 ### 指令助记符 指令助记符(instruction mnemonic)是标记一条指令的短单词。在英语中,助记符是帮助记忆的方法。相似地,[汇编语言](http://c.biancheng.net/asm/)指令助记符,如 mov, add 和 sub,给出了指令执行操作类型的线索。下面是一些指令助记符的例子: |助记符 |说明 |助记符 | 说明 | | --- | --- | --- | --- | |MOV |传送 |(分配) |数值 |MUL |两个数值相乘 | |ADD |两个数值相加 |JMP |跳转到一个新位置 | |SUB |从一个数值中减去另一个数值 |CALL | 调用一个子程序 | ### 操作数 操作数是指令输入输出的数值。汇编语言指令操作数的个数范围是 0〜3 个,每个操作数可以是寄存器、内存操作数、整数表达式和输入输岀端口。 生成内存操作数有不同的方法,比如,使用变量名、带方括号的寄存器等。变量名暗示了变量地址,并指示计算机使用给定地址的内存内容。下表列出了一些操作数示例: | 示例 | 操作数类型 | 示例  | 操作数类型 | | --- | --- | --- | --- | | 96  | 整数常量 | eax | 寄存器 | | 2+4 | 整数表达式 | count | 内存 | 现在来考虑一些包含不同个数操作数的汇编语言指令示例。比如,STC 指令没有操作数: ``` stc ;进位标志位置 1 ``` INC 指令有一个操作数: ``` inc eax ;EAX 加 1 ``` MOV 指令有两个操作数: ``` mov count, ebx ;将 EBX 传送给变量 count ``` 操作数有固有顺序。当指令有多个操作数时,通常第一个操作数被称为目的操作数,第二个操作数被称为源操作数(source operand)。 一般情况下,目的操作数的内容由指令修改。比如,在 mov 指令中,数据就是从源操作数复制到目的操作数。 IMUL 指令有三个操作数,第一个是目的操作数,第二个和第三个是进行乘法的源操作数: ``` imul eax,ebx,5 ``` 在上例中,EBX 与 5 相乘,结果存放在 EAX 寄存器中。 ### 注释 注释有两种指定方法: * 单行注释,用分号(;)开始。汇编器将忽略在同一行上分号之后的所有字符。 * 块注释,用 COMMENT 伪指令和一个用户定义的符号开始。汇编器将忽略其后所有的文本行,直到相同的用户定义符号出现为止。 示例如下: ``` COMMENT ! This line is a comment. This line is also a comment. ! ``` 其他符号也可以使用,只要该符号不出现在注释行中: ``` COMMENT & This line is a comment. This line is also a comment. & ``` ### NOP(空操作)指令 最安全(也是最无用)的指令是 NOP(空操作)。它在程序空间中占有一个字节,但是不做任何操作。它有时被编译器和汇编器用于将代码对齐到有效的地址边界。 在下面的例子中,第一条指令 MOV 生成了 3 字节的机器代码。NOP 指令就把第三条指令的地址对齐到双字边界(4 的偶数倍): ``` 00000000 66 8B C3 mov ax,bx 00000003 90 nop ;对齐下条指令 00000004 8B D1 mov edx,ecx ``` x86 处理器被设计为从双字的偶数倍地址处加载代码和数据,这使得加载速度更快。 ps 参考连接:http://c.biancheng.net/view/3469.html