ASM-汇编语言程序设计基础

《微型计算机原理》汇编语言程序设计基础知识总结。

翻译:源程序 ==> 二进制代码

翻译过程中,伪指令起协助作用,而且当翻译结束时,伪指令消失,只剩下源程序中指令所转换的二进制代码。

伪指令

指导汇编程序将源程序汇编(翻译)成二进制代码,只构成汇编语句语法。

宏指令

简化程序,以一代多。(和C语言宏一样的道理~)
宏指令语句和子程序的区别:
宏指令语句:速度快、占用空间大。
子程序:速度慢(调用时需要保存临时数据,函数地址等)、占用空间小。

汇编程序举例:将数据段内存单元DATA中的数据12H与立即数16H相加,结果保存在SUM中。完整的源程序如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
DESG	SEGMENT		;定义数据段
DATA DB 12H
SUM DB 0
DESG ENDS ;定义数据段结束

SSEG SEGMENT STACK ;定义堆栈段
DB 512 DUP(0)
SSEG ENDS ;定义堆栈段结束

CSEG SEGMENT ;定义代码段开始
ASSUME DS:DSEG,SS:SSEG,CS:CSEG
START: MOV AX,DSEG
MOV DS,AX
MOV AL,DATA
ADD AL,16H
MOV SUM,AL
MOV AH,4CH
INT 21H
CSEG ENDS ;定义代码段结束
END START ;整个汇编程序结束,规定入口地址

1)汇编语言程序一般由若干段组成,每个段都有一个名字(段名),以SEGMENT作为段的开始,ENDS作为段的结束。

汇编语言程序段有4种:代码段、堆栈段、数据段、附加段。
其中代码段和堆栈段不可少,数据段和附加段根据需要设置。

2)汇编语言一行不能超过128个字符,但一条语句允许有后续行,最后均已回车结束。整个程序必须以END作为结束,它通知汇编程序停止汇编。END后的START表示该程序执行时的起始地址。

3)每一条汇编语句最多由4个字段组成,按照语法规则写在一个语句的4个区域内。各区域之间用空格或TAB隔开。

汇编语句的4个字段:名字或标号、操作码(指令助记符)或伪操作指令、操作数(操作数或地址)、注释。

1. 数据项

1.1 常量

数字

1
2
3
4
0100B 	二进制
75Q 八进制
295D 十进制(D可省略)
3AFH 十六进制

所有的数必须以0~9输值开头,例如:FA3BH需写成0FA3BH

字符、字符串
'a' 'Hello'

用标识符表示常量
嘿嘿,类似于C语言中#define PI 3.14
在汇编中:AL EQU 0FA3BH,这个EQU是关键字,这样定义后AL就代表这个数。

1.2 变量

变量名:一个存储单元的地址

变量属性
段属性:变量所在段的段地址,用SEG 变量名得到变量的段地址。

偏移属性:变量与起始位置之间相距的字节数,OFFSET 变量名得到变量的偏移地址。

类型:存取长度单位,TYPE 变量名得到变量的类型。

  • 变量定义

    变量 类型 表达式

  • 变量类型

    DB:1个字节

    DW:2个字节

    DD:4个字节

    DQ:8个字节

    DT:10个字节

  • 变量定义中的表达式

    常量1,常量2,…

    ‘一串字符’

    重复因子DUP( )

变量定义举例:

变量定义举例1

变量定义举例2

变量定义3

1.3 标号

  • 标号名:不能以0开头(常量是必须以0开头),标号名代表标号那行指令所在内存单元的地址。

  • 标号属性

    段属性:SEG 标号取段地址。

    偏移属性:OFFSET 标号取偏移地址。

    类型属性:TYPE 标号取类型。

  • 标号类型

    near(近类型):段内

    far(远类型):段间

2. 运算符和表达式

表达式并不是指令,所以它本身并不能执行,只能在汇编时由汇编程序预先对其进行运算,然后再将所得的值作为操作数参加指令规定的操作。

即:表达式求值是由汇编程序来完成的

  • 算数运算符(7种)

    加(+)、减(-)、乘(*)、除(/)、模除(MOD)、算数左移(SHL)、算数右移(SHR)。

    注意:除了加、减运算符可以使用变量和标号外,其他算数运算符只适用于常量的数值运算。

    例如:设NUMB=01010101B ,则NUMB SHL 1 = 10101010B

  • 逻辑运算符(4种)

    与(AND)、或(OR)、非(NOT)、异或(XOR)。

    注意:逻辑运算符只能用于表达式求值,用来对数值进行按位逻辑运算,并得到一个数值。对地址进行逻辑运算则无意义。

    例如:MOV AL,0ADH AND 0EAH<=>MOV AL,0A8H

  • 关系运算符(6个)

    =(EQ)、$\ne$(NE)、$\lt$(LT)、$\gt$(GT)、$\le$(LE)、$\ge$(GE)。

    注意:在数值表达式中参与关系运算的必须是两个数值或同一段中的两个存储单元的地址。关系运算符的结果是一个逻辑值(常数),其值在汇编(翻译)时获得。当关系成立(TRUE)时,结果为$0FFFFH$,当关系不成立(FALSE)时,结果为$0$。

  • 数值返回操作符

    数值返回操作符用来分析一个存储器操作数(即变量或标号)的属性,即将它分解为其组成部分(段地址、偏移值、类型、数据字节数、数据项总数等),并在汇编时以数值形式返回给存储器操作数。运算符总是加在运算对象之前,返回的结果是一个数值。

    SEG:返回其后变量或标号的段地址,例:MOV AX,SEG DATA1将变量DATA1的段地址送到AX中。

    OFFSET:返回其后变量或标号的偏移值,例:MOV SI,OFFSET DATA2

    TYPE:返回的数值是反应该变量或标号类型的一个数值。

    如果是变量,则返回数值为字节数:DB为1,DW为2,DD为4,DQ为8,DT为10。

    如果是标号,返回数值为该标号的类型值:NEAR为-1(FFH),FAR为-2(FEH)。

    SIZE:返回变量所占数据区的字节总数。

    LENGTH:返回数据单元个数。

    如果变量是DUP说明的,返回外层DUP前面的数值。

    其他,返回的总是1。

  • 属性运算符(4个)

    PTR:用来说明或修改位于其后的存储器操作数的类型。

    如果一个变量已经定义为字变量,利用PTR运算符可以修改它的属性。例如:变量VAR已经定义为字类型,若要将VAR当作字节操作数写成MOV AL,VAR则会出错,因为两个操作数的字长类型不同;如果将指令写成MOV AL,BYTE PTR VAR是合法的。

    注意!PTR运算符只对当前指令有效。

    THIS:(类似于C语言中的union?),THIS用来把它后面指定的类型和距离属性赋给当前变量、标号或地址表达式,但不分配新的存储单元。

    例如:DATAB EQU THIS BYTE DATAW DW ?

    这里的DATAB与DATAW的段地址和偏移量相同(公用一块空间),但变量DATAB的类型是字节,而变量DATAW的类型是字。

    注意!运算符THIS和PTR有类似的功能,但具体用法有所不同。

    其中,THIS是为当前存储单元定义一个指定类型的变量或标号,也就是说为下一个能分配存储单元的变量或标号定义新的类型,因此它必须放在被修改的变量之前。例如上个栗子中的THIS就是放在DATAW之前,以便将DATAW定义为字节类型变量DATAB。而运算符PTR则是对已经定义的变量或标号修改其属性,它可以放在被修改的变量之前,也可以放在后面。

    HIGH:取高8位

    LOW:取低8位

    :段超越:eg:MOV AX,ES:[BS]

3. 伪指令

3.1 数据定义伪指令

DB:1个字节,BYTE,也常常用来定义字符串。

DW:2个字节,WORD。

DD:4个字节,DWORD。

DQ:8个字节,QBYTE。

DT:10个字节,TBYTE,DT后面的每个操作数都为10个字节的压缩BCD数。

3.2 符号定义伪指令

  • EQU(赋值伪指令)

    格式:名字 EQU 表达式

    EQU不能重复定义已使用过的符号名。

    CONST EQU 256

    N_CONST EQU 256+10

    ADDR EQU [BP+8]

    CB EQU DAA

  • LABEL(数据定义伪指令)

    格式:名字 类型 表达式

3.3 段定义伪指令

格式:段名 SEGMENT [定位][组合][类别名] // []中的一般不写

SEGMENT和ENDS伪指令:

SEGMENT和ENDS必须成对出现,他们之间为段体,给其赋予一个名字(不可省略)。

  • 定位类型(4种)

    BYTE,字节型

    WORD,字型

    PARA,节型,默认为这个。

    PAGE,页型

  • 组合类型(连接类型)

    即多个模块的程序中,指示连接程序如何将某个逻辑段在装入内存时与其他段进行组合。

    NONE,默认不组合

    PUBLIC,同类型之和、一个整的内存段

    STACK

    COMMON,重叠,值分配最大的那个段的存储长度

    MEMORY

    AT表达式

  • 类别名(在组合中使用)

    用来说明程序在运行期间CS、DS、SS、ES所放的段基址。

ASSUME伪指令:

一般出现在代码段,且放在代码段首句。

格式:段寄存器:段名

例如笔记最开始的代码:ASSUME DS:DSEG,SS:SSEG,CS:CSEG

3.4 过程定义伪指令

“过程”也称为“子程序”,在主程序中任何需要的地方都可以调用。

例如:

1
2
3
4
名字 PROC FAR/NEAR
...
ret
名字 ENDP

3.5 程序结束伪指令

格式:END 标号

告诉汇编程序到这里就结束咯。

例如笔记最开始时的那段代码:

END START


文章作者: ahoj
文章链接: https://ahoj.cc/2018/10/ASM-汇编语言程序设计基础/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 ahoj 的小本本