文章

计组笔记 08 汇编语言

汇编语言通过指令与伪指令实现对硬件的直接控制,核心在于数据定义、寄存器操作与过程调用机制,并依赖栈完成参数传递与现场保护。 其程序设计遵循结构化思想,通过顺序、分支与循环控制流程,并结合模块化与过程化方法实现复杂功能与代码复用。

计组笔记 08 汇编语言

第8章 汇编语言

适配 8086/MASM 语法


0. 汇编语句的一般形式与约定

  • 通式[label:] mnemonic operand1[, operand2] ;注释
  • 操作数:寄存器 / 立即数 / 存储器(可带符号名、位移、[寄存器])/ 表达式。
  • 大小写与空格:不敏感;分号 ; 之后是注释。
  • 一条语句一个功能;空行、仅注释行编译器不处理。
  • 常见段框架
.MODEL  SMALL               ; 或 TINY/SMALL/MEDIUM/COMPACT/LARGE
.STACK                      ; 可省长度,默认 1KB(教材默认 1024)
.DATA                       ; 数据段
    var DW 1234h
.CODE
start:                      ; 程序入口(COM 常用 label,EXE 常配 STARTUP)
    mov ax, @data          ; 经典 SMALL 初始化
    mov ds, ax
    ; …… Your code ……
    EXIT                   ; 等价于 .EXIT / INT 21h,4Ch
END start
  • 内存模型
    • TINY:单段(.COM);SMALL:1 Code + 1 Data;MEDIUM:多 Code,1 Data;COMPACT:1 Code,多 Data;LARGE:多 Code,多 Data(每段≤64KB)。

1. 数据定义与伪指令(Directive)

1.1 数据定义(存储器保留 + 初始化)

| 伪指令 | 大小 | 典型写法 | 说明 | | — | — | — | — | | DB | 1 字节 | DB 12, 0FFh, 'A',"Hi" | 可混合字节常数与字符串 | | DW | 2 字节 | DW 1234h, 0 | 按小端序存放 | | DD | 4 字节 | DD 0ABCDEF0h | 双字 | | DQ | 8 字节 | DQ 12345678h, 9ABCDEF0h | 四字 | | DT | 10 字节 | DT 10 dup(0) | 有的教材用于 BCD/扩展精度 |

  • 重复DUP(n),如 DB 10 DUP(0);嵌套可 DB 3 DUP('ABC')
  • 字符串"ABC" 等价三个字节 41h,42h,43h
  • 地址表达式:允许 OFFSET 符号 或由编译器计算的表达式(本教材更多用 LEA 装入 EA)。

1.2 命名与类型

  • EQU:给表达式/常量取名:TABW EQU 2编译期替换,不占存储
  • LABEL 类型:给当前位置贴类型化标签(并指明它的段:偏移类型),如:Here LABEL WORD

1.3 段与程序组织

  • 低级段法
段名  SEGMENT [对齐/组合/类别]
    ……(段体)
段名  ENDS
1
- 组合关键字(PUBLIC、STACK、MEMORY 等)按教材用于链接器段合并;类别用于说明用途('CODE'、'DATA')。 + **高级段法**(MASM 简化):`.MODEL`、`.STACK [n]`、`.DATA`、`.CODE`。 + `ASSUME`:声明段寄存器与逻辑段关联(简化模式多数由编译器自动处理)。 + `ORG`:设定**当前位置**(常见于设备/引导扇区编程)。 + `END [入口标号]`:**唯一终止语句**;指定可执行入口(EXE)。

1.4 模块化汇编伪指令

  • PUBLIC 符号本模块导出符号(变量/过程/标签等)。
  • EXTRN 名:TYPE[, 名:TYPE]声明外部符号,TYPE 可为 BYTE/WORD/DWORD/FAR/NEAR/ABS 等。

例:EXTRN puts:FAR, gCount:WORD

1.5 其他“文档类”伪指令

  • NAME 模块名:目标模块名。
  • TITLE text:页眉标题(打印/列表标题)。
  • SUBTTL text:小标题;PAGE [行数[,列宽]]:分页设置。
  • .STARTUP:设入口准备;.EXIT:返回 DOS(等价 INT 21h,4Ch)。

2. 过程(子程序)与调用

2.1 定义与调用

; 定义
ProcName  PROC  NEAR|FAR
    ; …… 过程体 ……
    RET           ; 或 RET n(栈平衡返回)
ProcName  ENDP

; 调用
CALL ProcName     ; 近调用改 IP;FAR 同时改 CS:IP
  • NEAR/FAR:是否跨段;同一代码段内取 NEAR;跨段或 DOS 子程序常取 FAR。
  • 返回RET [n]RET n 会在返回前 弹栈并额外丢弃 n 字节(常用于“被调用者清栈”的参数约定)。

2.2 入口/出口约定与现场保护

  • 入口参数:调用时的先决条件(需要哪些寄存器/内存参数)。
  • 出口结果:返回后在哪些寄存器或内存可取到结果。
  • 现场保护(保存/恢复寄存器)三法(教材原话要点):
    1. 调用者保存:先 PUSH 自己要用的寄存器,返回后 POP
    2. 被调者保存(最常见):过程开始 PUSH 所用寄存器,结束前 POP
    3. 统一工作寄存器区:用专用内存区保存/恢复(少见,但试题爱考“还有这种方式”)。

实操惯例:过程体第一行 push ax bx cx dx si di bp(按需),结束前对称 pop …,中间可用 BP 做栈基址访问参数。

2.3 参数传递方式

  1. 寄存器传参:快、简单,数量受限
  2. 存储单元传参:把地址/变量作为“形参”放在约定位置(DS:…);可共享全局
  3. 栈传参PUSH 实参,过程内用 BP 定框访问,如 [BP+4][BP+6]……;可配 RET n 清栈。
    • 延伸:返回值也可放栈或寄存器(AX/AX:DX)。

2.4 递归与可重入

  • 递归:过程调用自身(直接/间接)。考点是“必须使用栈保存返回地址与局部数据”。
  • 可重入:过程允许在执行中再次被调用(含中断打断),要求不使用静态易变的全局区,或正确保护它。

3. 指令系统要点

3.1 数据传送/栈/I-O

  • MOV不许内存内存;不可写 MOV CS, …
  • PUSH/POP:以为单位更改 SPSS:SP 指向栈顶。
  • XCHG:寄存器/存储器互换(不能与立即数)。
  • IN/OUT:立即端口 8 位;16 位端口放 DXIN AL/AX, DX / OUT DX, AL/AX
  • XLATAL ← [BX + AL](查表)。

3.2 算术/逻辑/移位/比较

  • ADD/ADCSUB/SBBINC/DEC不改 CF),NEG(若操作数≠0 → CF=1)。
  • CMP:只改旗标;配 Jcc
  • MUL/IMULDIV/IDIV:结果位宽翻倍;除法商/余位置记忆(8位:AL/AH;16位:AX/DX)。
  • 逻辑:AND/OR/XOR/TESTTEST 不写回)。
  • 移位:SHL/SHR/SAL/SAR;循环:ROL/ROR/RCL/RCR被移出位→CF;1 位左移 OF = 旧MSB ⊕ 新MSB

3.3 条件与循环控制

  • 条件跳转表
    • 判断位:JZ/JE(ZF),JNZ/JNEJS/JNS(SF),JO/JNO(OF),JP/JPE/JNP/JPO(PF),JC/JNC(CF)。
    • 无符号JB/JNAE(CF=1), JAE/JNB(CF=0), JA/JNBE(CF=0∧ZF=0), JBE/JNA(CF=1∨ZF=1)。
    • 有符号JL/JNGE(SF≠OF), JGE/JNL(SF=OF), JG/JNLE(ZF=0∧SF=OF), JLE/JNG(ZF=1∨SF≠OF)。
  • 计数循环LOOPCX--CX≠0 跳);LOOPE/LOOPZ(再加 ZF=1);LOOPNE/LOOPNZ(再加 ZF=0)。
  • 无条件跳转JMP 近/远、直接/间接(表驱动)。

3.4 串操作与前缀

  • MOVS/CMPS/SCAS/STOS/LODS + B/W;隐含 DS:SI(源)、ES:DI(目的);
    DF=0 递增,DF=1 递减;REP/REPE/REPNE 结合 CX 计数

4. 结构化程序设计

4.1 顺序结构

  • 语句线性执行。注意:更新段寄存器/栈寄存器要成对,并保证数据段有效。

4.2 分支结构

  • 二分支IF-THEN-ELSECMP + 合适的 Jcc + JMP 跳过;
  • 多分支
    • 多次 CMP + 多个 Jcc
    • 或“跳转表”——JMP WORD PTR [BX+SI] 等间接转移(段内/间接)。

4.3 循环结构

  • 计数循环(for):初始化计数 → 体 → 计数/条件 → 回到体首;CX 常用。
  • 条件循环(while/do-while):先判后跳或先做后判。
  • 嵌套循环外层与内层的计数寄存器/标志位不要混用;方向标志 DF 的设置在进入串循环前明确 CLD/STD

5. 过程化编程要点

5.1 过程设计流程

  1. 明确问题定义
  2. 建立数学模型
  3. 确定算法/处理方案
  4. 画流程图
  5. 编写程序(结构化,过程化)
  6. 上机调试
  7. 试运行与分析结果
  8. 整理/投人运行

5.2 过程接口(I/O)与注释

  • 入口:需要参数、起始状态、被改动资源;出口:返回值与状态。
  • 注释建议写明:用途、输入、输出、破坏寄存器、被调用过程等(试卷会考“应当说明哪些内容”)。

5.3 参数传递细化

  1. 寄存器(直接、显式、常用)
  2. 立即数(把常量写在指令中)
  3. 存储单元(通过变量表地址传入/传出)
  4. (最灵活;可嵌套、可递归;配 BP 定位参数)

过程返回多结果:寄存器 + 存储单元混合最常见;或在调用点分配输出缓冲区地址传入。

5.4 递归/嵌套调用

  • 递归:每次调用都生成新的返回地址与局部副本;必须正确 PUSH/POP,可配帧指针 BP 管理局部变量。
  • 嵌套:一个过程内部 CALL 另一个;需注意调用深度寄存器保护

6. 易错

  1. MOV不能 mem↔mem;XCHG 也不行(寄存器必须参与)。
  2. PUSH/POP 对象为;8086 栈向低地址生长(SP-=2 入栈)。
  3. INC/DEC 不影响 CFNEG 若操作数非 0 → CF=1
  4. IN/OUT:立即端口只有 8 位;16 位端口号放 DX
  5. CMP/TEST 只改旗标、不写回。
  6. LEAMOV 区分:LEA reg, mem有效地址(不访存);MOV reg, mem内容(访存)。
  7. CBW/CWD符号扩展(AL→AX、AX→DX:AX)。
  8. DIV/IDIV 若除数为 0 或商溢出 → 异常(题目常问结果寄存器位置)。
  9. 条件转移:无符号CF/ZF有符号SFOF 的关系。
  10. 串指令:方向由 DF 控制;进入循环前记得 CLD(正向)或 STD(反向);计数在 CX
  11. 过程:NEAR 只改 IPFAR 同时改 CS:IPRET n 会清理 n 字节参数。
  12. 递归/可重入:必须依赖栈;避免使用共享可变全局(或妥善保护)。
  13. .STARTUP/.EXIT伪指令层面的入口/退出封装;END 入口 指出程序起点。
  14. PUBLIC/EXTRN:模块间符号导出/声明EXTRN 名:类型 的类型要写对(FAR/NEAR/BYTE/WORD 等)。

7. 典型模板

7.1 SMALL 模型 + 过程 + 栈传参

.MODEL SMALL
.STACK 100h
.DATA
    msg DB "sum=",0
    a   DW 3
    b   DW 5
.CODE
start:
    mov ax, @data
    mov ds, ax

    ; 栈传参:右到左压栈
    push b
    push a
    call Sum2             ; AX ← a+b
    add  sp, 4            ; 调用者清栈(也可在被调者用 RET 4)

    ; …… 使用 AX 的结果 ……

    EXIT
;-------------------------
; int Sum2(word x, word y) -> AX
Sum2 PROC NEAR
    push bp
    mov  bp, sp
    push bx              ; 现场保护(示例)

    mov ax, [bp+4]       ; y
    mov bx, [bp+6]       ; x
    add ax, bx

    pop  bx
    pop  bp
    ret                  ; 若被调者清栈可写:ret 4
Sum2 ENDP
;-------------------------
END start

7.2 串搬运 + 条件/计数循环

cld                      ; DF=0,正向
mov cx, count
mov si, OFFSET src
mov di, OFFSET dst
rep movsb                ; 拷贝 CX 个字节

; 比较直到找到 0
mov cx, maxlen
mov di, OFFSET buf
mov al, 0
repne scasb              ; 找 0:当 AL≠[ES:DI] 时继续,ZF=1 表示命中
jnz not_found
; found...

8. 程序设计与文档伪指令

  • TITLE/SUBTTL:打印/列表标题;
  • PAGE rows[,cols]:分页设置;
  • NAME:模块名;
  • 过程化文档:过程接口(入口/出口/破坏寄存器)、参数说明与返回值、寄存器保护策略、调用关系图
本文由作者按照 CC BY-NC 4.0. 进行授权
...

Comments

评论区

碎片之中

正在加载中...