【x86汇编】第三章:宏汇编语言的表达式

表达式

常量

常量分为:

  • 数值常量:MOV AX, 10H
  • 符号常量:VAR EQU 20

数值常量可以是:

  • 二进制:0101B
  • 八进制:123Q 或者 123O
  • 十进制:467 或者 467D
  • 十六进制:0FFH
  • 字符常量:‘123abc’ “hello”

数值表达式

算术运算:

  • 加、减、乘、除、取模(MOD)、左移(SHL)、右移(SHR)
  • 注意负数的取模,根据商的值进行推算(不同语言,商可能不同)

逻辑运算:

  • 相等(EQ)、不等(NE)、小于(LT)、大于(GT)、小于等于(LE)、大于等于(GE)
  • 运算结果为特殊常量:成立,为0FFFFH,不成立为0

变量

变量的属性:

  • 段属性:所在段的段首址
  • 偏移地址:相对段首址的EA
  • 类型:存取所需要的字节数

变量的定义使用伪指令:DB、DW、DD、DF、DQ、DT

定义格式: [变量名] 数据定义伪指令 表达式
表达式有以下几种形式:

  • 数值表达式:VAR DB 10
  • ASCII字符串:BUF DB ‘abc123’
  • 地址表达式:只适用于DW和DD,16位段中,DW取该地址的EA,DD取段首址和EA,32位段取EA
  • ?:表示不进行初始化赋值
  • 重复子句:n DUP(表达式)
  • 上述形式的组合,逗号隔开

标号

标号是机器指令语句存放地址的符号表示,也可以是子程序名
标号的属性:

  • 段属性:所在段的段首址
  • 偏移地址:到段首址的EA
  • 类型:NEAR和FAR,NEAR类型的标号,只能段内使用

地址表达式

  • 地址表达式是由变量、标号、常量、寄存器的内容,和运算符组成的
  • 如果地址表达式中出现了变量、标号,则取它的EA参与运算

属性定义算符PTR

指明该地址的操作数,是什么数据类型,或者临时改变操作数的类型,不能改变寄存器和立即数的类型

类型 PTR 地址表达式

例如:WORD PTR [SI]
类型:BYTE、WORD、DWORD、FWORD、NEAR、FAR

定义类型运算符THIS

指定下一个能分配的存储单元的类型,往往与EQU、=等连用

THIS 类型

跨段前缀算符

用于临时给变量、标号指明段属性

段寄存器:地址表达式

属性分离运算符

分离出变量、标号的段、EA和类型

  • 取段址运算符SEG:取出段首址
  • 取偏移地址算符OFFSET:取出EA
  • 取类型运算符TYPE:取出变量或标号的类型

其它算符

  • 取变量存储单元个数LENGTH:它的取值根据定义该变量时,数据定义伪指令后面的一个表达式而定
  • 取变量所含数据存储区大小算符SIZE:其值为LENGTH * TYPE
  • 字节分离算法:HIGH和LOW

常用运算符优先级

运算优先级

常用的机器指令语句

操作规定:

  • 目的操作数与源操作数,必须类型相同
  • 目的操作数不能是立即数
  • 目的操作数与源操作数,不能都存储在寄存器
  • 运算完后,结果送入目的操作数,源操作数不变

数据传送指令

  • 一般数据传送指令:MOV、MOVSX、MOVZX、XCHG、XLAT
  • 堆栈操作指令:PUSH、PUSHA、PUSHAD、POP、POPA、POPAD
  • 标志寄存器传送指令:PUSHF、PUSHFD、POPF、POPFD、LAHF、SAHF
  • 地址传送指令:LEA、LDS、LES、LFS、LGS、LSS
  • 输入输出指令:IN、OUT

影响标志位的指令:SAHF、POPF、POPFD

一般数据传送指令

传送指令

MOV OPD,OPS

将源操作数送入目的地址中

MOVSX OPD, OPS

将有符号数,向前扩展成与目的操作数相同的数据类型后,送入目的地址

MOVZX OPD, OPS

将无符号数,源操作数高位补0,扩展成与目的操作数相同的数据类型后,送入目的地址

数据交换指令

XCHG OPD, OPS

将源操作数和目的操作数中的内容互换

BSWAP OPD

将32位通用寄存器OPD中的,第一个和第三个、第二个和第四个字节的内容交换

XADD OPD,OPS

将源操作数和目的操作数中的内容互换,再求和,送入目的地址

查表转换指令

XLAT OPS 或者 XLAT

功能:( [ EBX/BX + AL ] ) -> AL,其中,BX为段首址,AL为EA

地址传送指令

传送偏移地址指令

LEA OPD,OPS

按照OPS提供的寻址方式,计算EA,送入OPD
其中,OPD一定是16/32位寄存器,OPS一定是存储器地址

传送偏移地址及数据段首址指令

CPU只能访问6个当前段,如果需要访问此外的段,要重新给相应的段寄存器赋值

LDS OPD,OPS

功能:( OPS ) -> OPD, ( OPS + 2/4 ) -> DS,切换当前数据段
其中:OPD一定是16/32位寄存器,OPS一定是存储器地址,且类型为DW/FW

传送偏移地址及附加数据段首址指令

LES OPD,OPS

功能:( OPS ) -> OPD, ( OPS + 2/4 ) -> ES,切换当前附加数据段
其中:OPD一定是16/32位寄存器,OPS一定是存储器地址,且类型为DW/FW

算数运算指令

二进制算数运算指令

加类指令

ADD、ADC、INC

ADD OPD OPS
INC OPD

减类指令

DEC、NEG、SUB、SBB、CMP

DEC OPD
NEG OPD :求补指令
SUB OPD,OPS
CMP OPD,OPS:结果为 ( OPD ) - ( OPS ),根据结果设置标志位,但是源、目标操作数不变

乘类指令

IMUL、MUL
有符号乘:

IMUL OPD,OPS:( OPD ) * ( OPS ) -> OPD
IMUL OPD,OPS,n:( OPD ) * n -> OPD
IMUL OPS

无符号乘:

IMUL OPS

字节乘法:( AL ) * ( OPS ) -> AX
字乘法:( AX ) * ( OPS ) -> DX,AX
双字乘法:( EAX ) * ( OPS ) -> EDX,EAX

除类指令

IDIV、DIV

无符号除:

DIV OPS

有符号除:

IDIV OPS

字节除法:( AX ) / ( OPS ) -> AL(商)、AH(余数)
字除法:( DX、AX ) / ( OPS ) -> AX(商)、DX(余数)
双字除法:( EDX、EAX ) / ( OPS ) -> EAX(商)、EDX(余数)

符号扩展指令

CBW、CWD、CWDE、CDQ

  • CBW:字节转换为字,将AL中的符号扩展至AH中
  • CWD:字转换为双字,将AX中的符号扩展至DX中
  • CWDE:将AX中的有符号数扩展为32位数 -> EAX
  • CDQ:将EAX中的有符号数扩展为64位数 -> EDX,EAX

位操作指令

逻辑运算指令

求反

NOT OPD

将目的地址中的内容,逐位取反,然后送回目的地址

逻辑乘

AND OPD,OPS

目的操作数与源操作数逐位做与运算,结果存入目的地址中

测试

TEST、BT、BTC

TEST OPD,OPS

目的操作数与源操作数做逻辑乘(AND),按结果置标志位SF、ZF、PF
该指令主要用于检测源操作数中1的那几位,对应于目的操作数的那几位,是否为0

逻辑加

OR OPD,OPS

目的操作数与源操作数逐位做或运算,结果存入目的地址中

按位加

XOR OPD,OPS

目的操作数与源操作数逐位做加运算,结果存入目的地址中

移位指令

算数、逻辑移位

SAL OPD,n:算数左移
SHL OPD,n:逻辑左移

向左移动N位,低位补0,CF标志位为最后移入的值

SHR OPD,n:逻辑右移

向右移动N位,高位补0

SAR OPD,n:算数右移

向右移动N位,高位保持不变(为1则补1,为0则补0),CF为最后移入的值

循环移位

ROL OPD,n:循环左移
ROR OPD,n:循环右移

将目的操作数的最高位和最低位连起来,组成一个环,一起移位,CF为最后移入的值

RCL OPD,n:带进位的循环左移
RCR OPD,n:带进位的循环右移

双精度移位

SHLD OPD,OPS,n:双精度左移
SHRD OPD,OPS,n:双精度右移

双精度左移:将OPS的最高n位,移入OPD低n位中,OPS保持不变,CF为OPD最后移出的一位
双精度右移:低n位,移入高n位

伪指令语句

伪指令语句,也叫汇编控制指令,它是在源程序中,使用一些约定好的、固定格式的符号,来告诉编译程序,该如何工作,每一条伪指令,都对应一段处理程序

伪指令一共有九类:

  • 处理器选择伪指令
  • 数据定义伪指令
  • 符号定义伪指令
  • 段定义伪指令
  • 过程定义伪指令
  • 程序模块的定义与通信伪指令
  • 宏定义伪指令
  • 条件汇编伪指令
  • 格式控制、列表控制及其它功能伪指令

处理器选择伪指令

学习的时候,一般选择.386,根据具体芯片支持的指令集来
该指令一般放在源代码的开头部分,也可以放在段中

数据定义伪指令

DB、DW、DD、DF、DQ、DT
该伪指令用以定义变量时,指定其类型大小

符号定义伪指令

等价伪指令

符号名 EQU 表达式

给表达式定义一个别名,但是不申请分配新的空间,类似于C语言的宏替换

等号伪指令

符号名 = 表达式

与EQU类似,不同的是等号语句可以对定义的符号名重定义

定义符号名伪指令

变量名或标号 LABLE 类型
DWBUF LABEL WORD

给当前存储单元定义一个指定类型的变量或者标号,类似于C语言的typedef

段定义伪指令

段定义伪指令

段名 SEGMENT [使用类型] [定位方式] [组合方式] [‘类别’]
段名 ENDS

假定伪指令

ASSUME 段寄存器:段名[,段寄存器:段名]

设定段寄存器与段之间的对应关系,即告诉汇编程序,目前哪些段为CPU当前可访问段

置汇编地址计数器伪指令

  • 汇编地址计数器用 符号$ 来表示,它用来记录正在被汇编程序翻译的语句的地址,即 $ 的内容标示了汇编程序当前的工作位置
  • 一个程序包含多个段,汇编时,每遇到一个段,就为该段分配一个初值为0的 $ 汇编地址计数器
  • 段内定义的所有标号和变量的偏移地址,就是汇编时,当前汇编地址计数器 $ 的值
  • 该计数器可以用ORG指令设置

源程序结束伪指令

END [表达式]

  • 标志整个程序的结束,后面可以带表达式,表示程序的启动地址
  • 如果后面不带表达式,往往是作为子模块被其它模块调用

常用的DOS系统功能调用

概述

DOS提供的功能主要有:

  • 设备管理
  • 文件管理
  • 目录管理
  • 其它功能调用

DOS系统功能调用的一般过程:

  • 将调用号放入寄存器AH中,置好入口参数
  • 然后执行软中断语句 INT 21H

常用的输入输出调用

键盘输入

调用格式:

MOV AH,1
INT 21H

功能:等待从键盘输入一个字符,并将ASCII码送入寄存器AL中

显示输出

调用格式:

MOV DL,待显示的ASCII码
MOV AH,2
INT 21H

功能:将DL中的字符,送到显示器

输入字符串

调用格式:

LEA DX,缓冲区偏移地址(字符串首的偏移地址)
MOV AH,10
INT 21H

功能:将键盘输入的字符串,送到当前数据段DS:DX中
调用要求:

  • 该缓冲区一定要定义在当前数据段中
  • 该调用要求输入缓冲区按照规定的格式定义
BUF   DB      80
          DB      ?
          DB      80     DUP(0)
  1. 第一个字节规定缓冲区大小,不能是0
  2. 第二个字节存放实际输入的个数
  3. 第三个字节开始,存放输入字符串的ASCII码,以回车 0DH 结束

显示字符串

调用格式:

LEA DX,字符串首EA
MOV AH,9
INT 21H

功能:将当前数据段中,DS:DX所指向的,以 $ 结尾的字符串送到显示器

MASM的功能

MASM的介绍

常用的汇编程序是微软推出的 MASM 和 Borland推出的 TASM
MASM就是一个两次扫描的宏汇编程序,即两次扫描后,MASM就能将源程序翻译成目标程序
主要功能如下:

  • 检查汇编源程序中的语法错误, 并给出错误信息
  • 处理宏库, 对源程序中的宏指令完成宏扩展
  • 处理各种伪指令
  • 产生与源文件对应的可再定位的目标文件(.OBJ)
  • 提供包括源程序、目标程序以及符号表在内的汇编列表文件(.LST)
  • 提供一个含有特定控制字符的符号交叉参考文件(.CRF 或.SBR)

汇编过程

MASM提供了两个符号表:

  • 机器指令表:指令记忆符与其目标代码的对照
  • 伪指令表:伪指令与其对应处理程序的入口地址对照表

第一次扫描,建立用户自定义符号表和宏定义表

  • 自定义符号表分为段表和一般符号表(符号常量、标号、变量等)
  • 段表中登记着程序中所定义的各段的段名、所占字节数、定位、组合方式、类别
  • 一般符号表登记着程序中所定义和引用的全部符号常量、变量、标号的名字及其属性值
  • 宏定义表记录程序中全部宏定义的名字、内容及其有关的性质, 在扫描过程中进行宏扩展

第二次扫描,将源程序翻译成目标程序,同时产生汇编列表文件(.LST)、符号交叉参考文件(.CRF)

汇编列表文件

汇编列表文件是源程序行、目标代码及其在段内存放的偏移地址的一个对照表,出错时,给出提示,可以分为以下三部分:

  • 汇编表:主要由源程序行、对应的目标代码及其在段内的偏移地址和错误信息提示组成
  • 段(组)表:列出源程序中所定义的各段(组)的名字、所占存储区大小及其特征等
  • 符号表:列出了源程序中所定义或引用的全部标号、变量、符号常量的属性值及其特征等

符号交叉列表文件

  • 详尽地列出了程序中用户自定义符号, 如: 段名、标号、变量、符号常量、宏定义名等的定义符号和引用行行号
  • 用户按照这个行号, 可以很快找到自己程序中所有符号的位置,便于程序调试

猜你喜欢

转载自blog.csdn.net/whitefish520/article/details/105478444