285 lines
14 KiB
Markdown
285 lines
14 KiB
Markdown
# 第 4 章 汇编语言及其程序设计(6-8 节)总结
|
||
|
||
> 本章 6-8 节内容重点:**伪指令**(4.6)、**汇编语言源程序的结构**(4.7)、**汇编语言程序设计**(4.8,含顺序/分支/循环/子程序)。与第 4 章前 5 节(指令系统)衔接,但侧重点转向**汇编源程序组织与结构化程序设计**。
|
||
|
||
---
|
||
|
||
## 一、详细内容分析
|
||
|
||
### 4.6 伪指令
|
||
|
||
伪指令是给汇编程序(编译器)的指示,CPU 不执行,**不产生目标代码**(宏指令除外)。用于选择处理器、定义数据、分配存储区等。
|
||
|
||
#### 1. END — 源程序结束伪指令
|
||
|
||
- **格式**:`END [标号]`
|
||
- **功能**:表示源程序结束,不可缺,是源程序编译的最后一条语句。
|
||
- **说明**:
|
||
1) 标号指示程序开始执行的起始地址;
|
||
2) 起始执行地址缺省值为代码段第一条指令地址;
|
||
3) 多个模块链接时,主程序用标号,其他程序不用。
|
||
|
||
#### 2. SEGMENT 和 ENDS — 段定义伪指令
|
||
|
||
- **格式**:
|
||
```
|
||
段名 SEGMENT [定位类型][组合类型][字长类型]['类别']
|
||
…
|
||
段名 ENDS
|
||
```
|
||
- **功能**:定义段名、段属性,并表示段的开始位置、结束位置。
|
||
- **说明**:
|
||
1) `SEGMENT` 和 `ENDS` 必须成对出现;
|
||
2) 段名是段的标识符(基址),由程序员指定;
|
||
3) 四个参数选项可省略,使用默认值:
|
||
- **定位类型**:`BYTE`、`WORD`、`DWORD`、`PARA`(默认)、`PAGE`;
|
||
- **组合类型**:`PUBLIC`、`STACK`、`COMMON`、`MEMORY`、`PRIVATE`(默认)、`AT 表达式`;
|
||
- **字长类型**:`USE16`(默认)、`USE32`;
|
||
- **类别**:`'DATA'`、`'CODE'`、`'STACK'`、`'EXTRA'` 等,连接时同类别段放在连续存储空间。
|
||
|
||
#### 3. ASSUME — 段分配伪指令
|
||
|
||
- **格式**:`ASSUME 段寄存器名:段名, 段寄存器名:段名, ……`
|
||
- **功能**:说明某个段关联哪一个段寄存器。
|
||
- **说明**:
|
||
1) 程序段必须用 CS,堆栈段必须用 SS;
|
||
2) 该语句一般放在代码段最前面;
|
||
3) **说明性语句**,除 CS 由初始化赋值外,其他段寄存器在程序中赋值。
|
||
|
||
#### 4. ORG — 起始地址定义
|
||
|
||
- **格式**:`ORG 数值表达式`
|
||
- **功能**:定义指令或数据的起始地址,`$ ← 表达式的值`。数值表达式范围 0~65535。
|
||
- **地址计数器 `$`**:指示当前语句使用的段内偏移值,每段开始时为 0,每分配一个单元加 1。
|
||
|
||
#### 5. EVEN — 偶数地址定义
|
||
|
||
- **格式**:`EVEN`
|
||
- **功能**:使下一个变量或指令从偶地址开始(用于字访问对齐)。
|
||
|
||
#### 6. 数据定义伪指令
|
||
|
||
- **格式**:`[变量名] 操作符, 操作数[, …] [: 注释]`
|
||
- **功能**:为操作数分配存储单元,用变量与存储单元相联系。
|
||
- **操作符**(定义数据类型):
|
||
- `DB`:1 字节(8 位),字节变量;
|
||
- `DW`:1 字(16 位),字变量;
|
||
- `DD`:1 双字(32 位),双字变量。
|
||
- **操作数**:常数、表达式、字符串、`?`、`n DUP(操作数)`(重复 n 次)。
|
||
- **典型示例**:
|
||
```
|
||
ORG 200H
|
||
DATA1 DB 12H, ?, 2+6 ; 12H、保留、08H
|
||
EVEN
|
||
DATA2 DW 789AH, 5 ; 字变量
|
||
DATA3 DD 12345678H ; 双字
|
||
DATA4 DW $, 6699H ; $ 为当前地址
|
||
DATA5 DB 4 DUP(?) ; 预留 4 个字节
|
||
```
|
||
|
||
#### 7. PROC 和 ENDP — 过程定义伪指令
|
||
|
||
- **格式**:
|
||
```
|
||
过程名 PROC [属性]
|
||
…
|
||
过程名 ENDP
|
||
```
|
||
- **功能**:定义子程序结构,过程名是入口,是 `CALL` 的操作数。
|
||
- **属性**:`FAR`、`NEAR`(默认)。
|
||
|
||
#### 8. EQU — 赋值伪指令
|
||
|
||
- **格式**:`符号常数名 EQU 表达式`
|
||
- **功能**:将表达式的值赋给符号常数;**只能定义一次**。
|
||
- 例:`DATA1 EQU 88`、`AAA1 EQU CX`、`DATA2 EQU DATA1+12`。
|
||
|
||
#### 9. 返回值运算符
|
||
|
||
| 运算符 | 含义 |
|
||
|--------|------|
|
||
| `SEG 变量/标号` | 段地址值 |
|
||
| `OFFSET 变量/标号` | 偏移量值 |
|
||
| `TYPE 变量` | 数据类型字节数:`DB=1`、`DW=2`、`DD=4` |
|
||
| `TYPE 标号` | 标号属性:`NEAR=-1`、`FAR=-2` |
|
||
| `LENGTH 变量` | 第一个数占用的单元数 |
|
||
| `SIZE 变量` | 第一个数占用的字节数 |
|
||
|
||
#### 10. PTR — 临时改变类型属性运算符
|
||
|
||
- **格式**:`类型 PTR 变量/标号`
|
||
- **变量类型**:BYTE / WORD / DWORD / FWORD / QWORD / TBYTE;
|
||
- **标号类型**:NEAR(近)/ FAR(远)。
|
||
- 当指令中操作数类型不明确(如 `MOV BYTE PTR [BX], 8` 或 `MOV WORD PTR [BX], 8`)时**必须使用 PTR**。
|
||
|
||
---
|
||
|
||
### 4.7 汇编语言源程序的结构
|
||
|
||
#### 80x86 汇编语言源程序结构特点
|
||
|
||
1. 一个程序由若干**逻辑段**组成,各逻辑段由伪指令语句定义和说明;
|
||
2. 整个源程序以 `END` 伪指令结束;
|
||
3. 每个逻辑段由语句序列组成,语句可以是:
|
||
- **指令语句**:CPU 指令,可执行,汇编时翻译成目标码;
|
||
- **伪指令语句**:CPU 不执行,提供汇编信息,不产生目标代码;
|
||
- **宏指令语句**:一个指令序列,汇编时产生对应的目标代码序列;
|
||
- **注释语句**:以分号 `;` 开始,说明性语句,汇编程序不处理;
|
||
- **空行语句**:仅包含回车换行符,便于阅读。
|
||
4. 每个源程序应当有**返回操作系统的指令语句**(典型:`MOV AH,4CH` + `INT 21H`),使程序执行完后能自动返回系统。
|
||
|
||
#### DOS 环境下两种程序结构
|
||
|
||
| 类型 | 长度限制 | 加载特点 | 段起始 | 适用场景 |
|
||
|------|----------|----------|--------|----------|
|
||
| **.COM 文件** | 一个段长(64KB) | 无段重定位,结构紧凑、装入快 | 偏移量从 100H 开始,且 100H 处必须是可执行指令 | 小型程序 |
|
||
| **.EXE 文件** | 仅受内存空间限制 | 需段重定位,占用盘空间大、装入慢 | 由程序员指定 | 中、大型程序 |
|
||
|
||
---
|
||
|
||
### 4.8 汇编语言程序设计
|
||
|
||
#### 基本步骤
|
||
|
||
1. 描述问题 → 2. 确定算法 → 3. 绘制流程图 → 4. 分配存储空间和工作单元 → 5. 编写程序 → 6. 上机调试。
|
||
|
||
#### 程序基本结构形式:顺序、分支、循环、子程序。
|
||
|
||
#### 4.8.1 分支程序设计
|
||
|
||
- **分支程序**:根据不同情况或条件执行不同功能,具有判断和转移功能,利用条件转移指令对状态标志进行判断实现转移。
|
||
- **特点**:按条件判断、转移、分支。
|
||
- **两种结构**:**二路分支**(if-then-else)、**多路分支**(case)。
|
||
- **共同特点**:在某一特定条件下,只执行多个分支中的一个。
|
||
|
||
#### 4.8.2 循环程序设计
|
||
|
||
- **循环程序五部分**:
|
||
1. 初始化部分(设置初值);
|
||
2. 循环工作部分(核心);
|
||
3. 循环修改部分(修改工作变量、指针);
|
||
4. 循环控制部分(修改控制变量,确定程序走向);
|
||
5. 循环结束部分(结果处理)。
|
||
- **两种常用结构**:
|
||
- **先执行后判断**(DO-WHILE):至少执行一次循环体;
|
||
- **先判断后执行**(DO-UNTIL):允许零次循环。
|
||
|
||
#### 典型例题:例 4.8.4 多重循环(冒泡排序)
|
||
|
||
- **问题**:从首地址 `AA1` 开始存放 N 个无符号字节数据,用**冒泡法**将数据按由大到小排序。
|
||
- **冒泡法核心**:相邻两个单元比较,位置交换,N-1 次后排出一个最大(或最小)数据;经 N-1 次循环完成排序。
|
||
- **关键步骤**:比较 → 判断 → 交换。
|
||
|
||
**版本 (1):N-1 遍,每遍比较 N-1 次** — 内外循环计数都用 N-1。
|
||
|
||
**版本 (2):N-1 遍,每遍比较次数少 1** — 用 DX 作为外循环计数器,每次进入内循环前 `MOV CX, DX`,使每遍比较次数递减。
|
||
|
||
**版本 (3):有交换标志** — 增加 AH 作为交换标志,每次交换时 `MOV AH,1`;每遍结束 `OR AH,AH` + `JZ` 提前退出;无交换则提前结束排序(效率优化)。
|
||
|
||
#### 4.8.3 子程序设计
|
||
|
||
##### 1. 子程序的定义
|
||
|
||
- **子程序组成 7 部分**:子程序定义(即入口)、保护现场、取入口参数、子程序体、存输出参数、恢复现场、返回。
|
||
|
||
##### 2. 现场的保存与恢复
|
||
|
||
- **保护现场**:在子程序中,保护那些主程序要用、而子程序也要用的寄存器内容。
|
||
- **恢复现场**:恢复现场保护的内容。
|
||
- **方法**:(1) 使用堆栈指令(PUSH/POP);(2) 使用数据传送指令。
|
||
|
||
##### 3. 子程序的参数传送
|
||
|
||
- **参数传送**:主程序和子程序之间的数据传送。
|
||
- **方法**:(1) 通过**寄存器/存储器**传送参数;(2) 通过**堆栈**传送参数或参数表地址。
|
||
|
||
**(1) 通过寄存器传送参数**(最常用)
|
||
|
||
- 特点:参数放在寄存器中,简便、实用,适用于参数较少的情况。
|
||
|
||
**(2) 典型例题:例 4.8.5 — 用寄存器传送,编制键入 5 位十进制数加法程序**
|
||
|
||
- **子程序 S1 功能**:键盘输入 5 位以内十进制数 → 二进制数 → 存入 CX,**用非数字键结束本次数字输入**。
|
||
- 10 进制 → 2 进制转换算法(霍纳/秦九韶法):
|
||
`((D5×10+D4)×10+D3)×10+D2)×10+D1)×10+D0`
|
||
- 实现方式:每按一个数字键,`CX×10 + 本次输入数位`。
|
||
- **子程序 S2 功能**:CX(二进制数) → 十进制数,在显示器上显示。
|
||
- 基本方法:从万位开始依次比较 `CX ≥ 10000`、`≥ 1000`、`≥ 100`、`≥ 10`,不够则跳过(避免最高位显示 0);用 `SUB` + `INC DL`(不影响 CF)+ `JNC` 累加,再用 `OR DL,30H` 转为 ASCII 码,最后用 `INT 21H` 的 02H 号功能逐位显示。
|
||
- **主程序 MAIN**:调用 S1 取被加数和加数 → 求和 → 调用 S2 显示结果。
|
||
- 约束条件:结果 ≤ 65535;MAIN、S1、S2 同段,子程序使用 NEAR 属性,主程序 MAIN 使用 FAR 属性。
|
||
- **程序返回操作系统**:`MOV AH, 4CH` + `INT 21H`。
|
||
|
||
---
|
||
|
||
## 二、考点总结
|
||
|
||
### 1. 伪指令(4.6)
|
||
|
||
- 【高频】**END**:源程序结束伪指令,必须有,可带启动标号。
|
||
- 【高频】**SEGMENT/ENDS**:成对出现,四个参数(定位、组合、字长、类别)及默认值(PARA / PRIVATE / USE16)。
|
||
- 【高频】**ASSUME**:说明段与段寄存器关联(CS、SS 必用,其他由程序赋值),属说明性语句。
|
||
- 【高频】**数据定义 DB/DW/DD**:字节/字/双字,`DUP(?)` 预留空间;`?` 表示不赋值。
|
||
- 【高频】**ORG** 与 **`$` 地址计数器**:控制起始地址。
|
||
- **EQU**:赋值伪指令,**只能定义一次**,可指向寄存器名。
|
||
- **PROC/ENDP**:过程定义,属性 NEAR(默认)/ FAR;过程名是 CALL 的操作数。
|
||
- 【高频】**PTR**:类型不确定时必须使用(如 `MOV BYTE PTR [BX], 8`)。
|
||
- **返回值运算符**:SEG / OFFSET / TYPE / LENGTH / SIZE 的返回值含义(TYPE: NEAR=-1、FAR=-2、DB=1、DW=2、DD=4)。
|
||
|
||
### 2. 源程序结构(4.7)
|
||
|
||
- 【高频】**5 种语句类型**:指令语句、伪指令语句、宏指令语句、注释语句、空行语句。
|
||
- 【高频】**.COM 与 .EXE 比较**:段长限制(64KB / 内存空间)、段重定位、入口偏移(100H / 段首)。
|
||
- 程序结尾必须有返回 DOS 指令:`MOV AH,4CH` + `INT 21H`。
|
||
|
||
### 3. 程序设计(4.8)
|
||
|
||
- **程序设计 6 步**:描述问题 → 算法 → 流程图 → 存储分配 → 编写 → 调试。
|
||
- **基本结构 4 类**:顺序、分支、循环、子程序。
|
||
- 【高频】**分支**:二路分支、多路分支;常用条件转移指令(JZ/JNZ、JC/JNC、JO/JNO 等)。
|
||
- 【高频】**循环 5 部分**:初始化、工作、修改、控制、结束。
|
||
- 【高频】**两种循环结构**:先执行后判断(至少一次)、先判断后执行(可零次)。
|
||
- 【高频】**冒泡排序**:N 个数需 N-1 遍,每遍两两比较交换;可优化为带"交换标志"提前退出。
|
||
- 【高频】**子程序 7 部分**及**参数传送两种方式**:寄存器传送(最常用)、堆栈传送。
|
||
- **现场保护**:PUSH/POP 配对使用,后进先出。
|
||
|
||
### 4. 常见题型
|
||
|
||
| 题型 | 示例 |
|
||
|------|------|
|
||
| **简答题** | 简述汇编语言源程序的 5 种语句;简述子程序的组成结构;简述现场保护与恢复的方法 |
|
||
| **填空题** | `DB`/`DW`/`DD` 数据类型字节数;SEGMENT 默认定位类型 PARA;TYPE NEAR = -1 |
|
||
| **选择题** | 下列伪指令属于说明性语句的是(A. END B. ASSUME C. DB D. PROC);COM 文件入口偏移为 100H |
|
||
| **判断题** | SEGMENT 与 ENDS 必须成对出现(√);EQU 可重复定义同一符号(×);PROC 默认属性 FAR(×,应为 NEAR) |
|
||
| **程序阅读/改错** | 阅读冒泡排序程序指出错误(如 LOOP 用错、循环计数初值错) |
|
||
| **程序设计题** | 用寄存器传送参数设计"键入十进制数求和并显示"程序;用多重循环实现数据排序 |
|
||
| **指令正误** | `MOV BYTE PTR [BX], 8` 是否合法(合法);`MOV AH, 4CH` 与 `INT 21H` 是否配套(是) |
|
||
|
||
### 5. 易混淆点
|
||
|
||
- **PROC 属性**:默认 **NEAR**,不是 FAR;只有跨段调用才用 FAR。
|
||
- **ASSUME**:仅说明关联关系,**不是赋值**;段寄存器 DS、ES 等需程序中 `MOV`。
|
||
- **PTR 与变量定义**:DB 定义字节变量,若要按字读需 `MOV AX, WORD PTR DATA2`。
|
||
- **冒泡排序方向**:从大到小排序时用 `JNC`(前大后小不交换);从小到大排序时用 `JC`(前小后大不交换)。
|
||
- **EQU vs `=`**:EQU 不允许重复定义同名符号。
|
||
- **堆栈段**:必须有 `SEGMENT … STACK`,并通过 `ASSUME SS:段名` 关联。
|
||
|
||
### 6. 综合程序设计模板(务必熟记)
|
||
|
||
```
|
||
DATA SEGMENT
|
||
; 数据定义
|
||
DATA ENDS
|
||
|
||
CODE SEGMENT
|
||
ASSUME CS:CODE, DS:DATA
|
||
MAIN PROC FAR
|
||
MOV AX, DATA
|
||
MOV DS, AX
|
||
; … 程序主体 …
|
||
MOV AH, 4CH
|
||
INT 21H
|
||
MAIN ENDP
|
||
; … 子程序 …
|
||
CODE ENDS
|
||
END MAIN
|
||
``` |