汇编程序设计

基本概念

助记符 目标操作数,源操作数

操作数按照种类大致分为三种

  • 立即操作数:1234H
  • 寄存器操作数: AX, BX, CX, DX
  • 存储器操作数: [1234H],[BX],[SI+DI],[BP+SI],[BX+DI],[BP+BX],[SI+1234H],[DI+1234H]

寻址方式(计算)

所谓寻址方式指的就是寻找操作数所在地址的方法,源操作数指的是运算数据的来源,目标操作数:运算结果的去向。

下面谈谈关于数据的寻址方式:注意:事实上寻址方式只和源操作数偏移地址的表达方式有关,目的操作数都是寄存器操作数。

20250408104301

简单的寻址

  • 立即寻址:立即操作数作为源操作数
  • 寄存器寻址:寄存器操作数作为源操作数
  • 直接寻址:源操作数的偏移地址是常数
  • 寄存器间接寻址:源操作数的偏移地址存于寄存器,进行”解引用“操作[BX]

寄存器相对寻址(一维数组操作)

操作数地址为寄存器内容与位移量之和。常用于数组操作
20250408104557

mov BX, 100H  
mov AX, [BX + 200H]  ; 从 DS:BX+200H 处取字数据  
mov AX, BX[200H]  ; 等价于上面指令
mov AX, 200H[BX]  ; 等价于上面指令

基址变址寻址

操作数地址由基址寄存器(BX/BP)和变址寄存器(SI/DI)内容相加得到。 简而言之就是将两种类的寄存器的内容相加得到一个地址,然后从这个地址中取出数据。

mov BX, 1000H  
mov SI, 200H  
mov AX, [BX+SI]  ; 从 DS:BX+SI 处取字数据  ,也可表示为[BX][SI]

相对基址变址寻址 (用于二维表格操作)

在基址变址寻址基础上,增加位移量。

mov BX, 1000H  
mov SI, 200H  
mov MASK, 100H
mov AX, [BX][SI][100H]  ; 从 DS:BX+SI+100H 处取字数据 ,也可表示为[BX+SI+100H]
mov AX, [BX][SI][MASK]  ; MASK为变量,表示偏移量
mov AX, MASK[BX][SI]  ; MASK为变量,表示偏移量
;只有偏移量(MASK)与常数(100H)可以做数组名称,BX,SI等寄存器不能做数组名称

考试例题:计算物理地址
20250604113759

通用数据传输指令(交换,查找,字位扩展仅了解)

MOV指令

易错点:

  • 两操作数字长必须相同;
  • 两操作数不允许同时为存储器操作数;
  • 两操作数不允许同时为段寄存器;
  • 在源操作数是立即数时, 目标操作数不能是段寄存器;
  • IP和CS不作为目标操作数,FLAGS一般也不作为操作数在指令中出现。

例题:20250604114419

堆栈操作

遵循先进后出原则,同时操作必须以为单位!(ORPD为16位寄存器或存储器两单元)

基本格式为PUSH ORPDPOP ORPD.

20250604160619

图中地址表示上低下高,向地址下增长,栈向上生长。

地址传输

LEA BX,[1234H]
结果:BX=1234H

LEA指令读取指定
内存单元的偏移地

输入输出指令

基本格式

IN acc PORT
OUT PORT acc

IN AL DX
OUT DX AL
  • acc为寄存器,必须为为AL,AX,DX

  • PORT为端口地址,必须为8位或16位

  • 指令功能:从端口地址读入数据到累加器/将累加器的值输出到端口中

  • 端口其实是一个个寄存器,有8位的也有16位的

  • 端口地址为8位时,指令中直接给出8位端口地址;端口地址为16位时,指令中的端口地址必须由DX指定!!!

; 从 80H 端口读 16 位数据到 AX
IN AX, 80H        ; ✅ 正确:直接寻址(8 位端口号)

; 从 2400H 端口读 8 位数据到 AL
MOV DX, 2400H     ; ✅ 正确:端口号十六位的时候必须用 DX 中转一下
IN AL, DX         ; ✅ 正确:间接寻址

; 将 AX 的 16 位数据写入 35H 端口
OUT 35H, AX       ; ✅ 正确:目标端口在前

; 错误示例
OUT AX, 35H       ; ❌ 错误:操作数顺序颠倒!

四则运算

加法

普通加法 add

MOV AL 78H
ADD AL, 99H
; AL = 78H + 99H = 111H

20250528105505

进位加法 adc

MOV AL, 78H
ADD AL, 99H
ADC AL, 01H
; AL = 78H + 99H + 01H = 112H
; OPRD1+OPRD2+CF -> OPRD1,CF为前一指令执行产生的进位

自增1指令 INC

MOV AL, 78H
INC AL
; AL = 78H + 01H = 79H
; 用于修改地址指针

其中INC后的操作数不能是段寄存器不能是立即数

减法

普通减法

SUB OPRD1,OPRD2
; OPRD1 = OPRD1 - OPRD2

借位减法

SBB OPRD1,OPRD2
; OPRD1 = OPRD1 - OPRD2 - CF

自减1

DEC OPRD1
; OPRD1 = OPRD1 - 01H

CMP指令

CMP OPRD1, OPRD2
; 执行 OPRD1 - OPRD2
; 若OPRD1>OPRD2,则ZF=0,CF=0,OF=0
; 若OPRD1=OPRD2,则ZF=1,CF=0,OF=0
; 若OPRD1<OPRD2,则ZF=0,CF=1,OF=0
; CMP指令不改变操作数的值

乘法

分为无符号的乘法MUL和有符号的乘法IMUL

MUL

MUL OPRD(单字节数)
; AL * OPRD -> AX(结果)
MUL OPRD(双字节数)
; AX * OPRD -> DX:AX(结果)

有符号乘法IMUL同理

除法

分为无符号的除法DIV和有符号的除法IDIV

DIV

DIV OPRD(单字节数)
; AX / OPRD -> AL(商),AH(余数)
DIV OPRD(双字节数)
; DX:AX / OPRD -> AX(商),DX(余数)

指令要求被除数是除数的双倍字长

逻辑运算

与或非(AND OR NOT)

实现两操作数按位相与的运算

AND BL, [SI]

使目标操作数的某些位不变,某些位清零

AND AL, 0FH

在操作数不变的情况下使 CF 和 OF 清零

AND AX, AX

例子:从地址为3F8H端口中读入一个字节数,如果该数bit1位
为1, 则可从38FH端口将DATA为首地址的1个字输出
,否则就不能进行数据传送。

MOV DX, 3F8H        ; 将端口地址3F8H加载到DX寄存器
WATT: IN AL, DX          ; 从端口3F8H读取一个字节到AL寄存器
AND AL, 02H        ; 将AL与02H按位与,检查bit1位
JZ WATT         ; 如果bit1位为0(ZF=1),则跳转到WATT重新读取
MOV DX, 38FH        ; 将端口地址38FH加载到DX寄存器
MOV AX, DATA      ; 将DATA的地址加载到AX寄存器
OUT DX, AX        ; 将AX中的数据输出到端口38FH

还有一个测试与指令运算,他执行yu但不把结果存回前操作数

TEST OPRD1,OPRD2

移位操作指令

重点只需要复习非循环移位指令

算术左移和逻辑左移

SHL OPRD1, CL
; OPRD1 = OPRD1 << CL,逻辑左移,用于无符号数
SAL OPRD1, CL
; OPRD1 = OPRD1 << CL,算数左移,用于有符号数

左移具体例子
20250604211247

算术右移和逻辑右移

SHR OPRD1, CL
; OPRD1 = OPRD1 >> CL  逻辑右移,用于无符号数
SAR OPRD1, CL   
; OPRD1 = OPRD1 >> CL  算数右移,用于有符号数

20250604211337

左:逻辑右移,右:算数右移
20250604211437

左移操作中,逻辑左移和算术左移完全相同​​。区别仅存在于右移操作:

  • 逻辑右移:高位补 0(用于无符号数)。
  • 算术右移:高位补符号位(用于有符号数的符号保持)

串操作

串操作指令的操作对象是多个字节数(一串字符或数据), 因此, 指令的执行需要确定:

  • 串所在的区域
  • 串的首地址(原串、 目标串起始地址)
  • 串长度(大小)
  • 串的操作方向

串所在区域及首地址:

  • 源串一般存放在数据段,偏移地址由SI指定,允许段重设
  • 目标串必须在附加段(ES),偏移地址由DI指定
  • 串长度值由CX指定
    串操作指令中,FLAGS中的DF状态位祈祷状态控制作用
    DF=0 增地址方向
    DF=1 减地址方向

串传送MOVS

讲几个重复前缀

  • REP,当CX!=0,后面语句不停重复
  • REPE/REPZ,当CX!=0且ZF=1时,后面语句不停重复
  • REPNE/REPNZ,当CX!=0且ZF=0时,后面语句不停重复

串传送操作分为三大类

MOVS OPRD1,OPRD2
MOVSB;按字节传送
MOVSW;按字传送

MOVS OPRD1,OPRD2 指令将源操作数(OPRD2)中的数据传送到目标操作数(OPRD1)中。源操作数的地址由SI寄存器指定,目标操作数的地址由DI寄存器指定。传送的数据长度由CX寄存器指定。此格式仅用于源操作数需段重设的情况下,举个例子:

MOVS ES:[DI], ES:[SI]  ; ✅ 正确重设源段为ES

20250604221200

其中CLD(DF=0)​​ → 指针 ​​递增​​(​​从低地址向高地址​​处理数据)。STD(DF=1)​​ → 指针 ​​递减​​(​​从高地址向低地址​​处理数据)。

串比较CMPS

同理,也可分为三类

CMPS OPRD1,OPRD2
CMPSB;按字节比较
CMPSW;按字传比较

程序控制指令

无条件转移指令JMP

段内转移,分为直接与间接

直接转移

JMP label

间接转移:转移的目标地址存放在某个16位寄存器或存储器的某两个单元中

MOV BX,1200H
JMP BX
;执行完上述指令后:
;IP=1200H

或者存储器的两个单元(一个单元存XXH)

MOV BX,1200H
JMP WORD PTR [BX]
;执行完上述指令后:
;IP为存储器1200H处向上的两字节内容

段间转移,分为直接与间接

可以直接转移

JMP FAR label

间接转移:转移的目标地址由指令中的32位操作数给出,32位目标地址须存放于内存中(四字节)

JMP DWORD PTR [BX]
;执行完上述指令后:
;IP为存储器BX处向上的四字节内容

20250604222716

条件转移指令

条件转移指令根据标志寄存器中的标志位的状态来决定是否执行转移操作。常见的条件转移指令包括:

  • JZ/JNZ:当ZF=1时转移(等于0)
  • JC/JNC:当CF=1时转移(进位)
  • JO/JNO:当OF=1时转移(溢出)
  • JS /JNS 判断SF的状态。常用于判断数的性质
  • JP/JPE 判断PF的状态。用于判断运算结果低8位中1的个数是否为偶数

循环

  • LOOP:无条件循环,只要CX不为0就循环,基本格式为LOOP label,执行时会先将CX减1,然后检查CX是否为0,如果不为0则跳转label处执行。
    完全相当于
    先DEC CX
    后JNZ 符号地址
  • LOOPZ Label 继续循环的条件:CX≠0,且ZF=1
  • LOOPNZ Label 继续循环的条件:CX≠0,且ZF=0

调用

20250604223734
基本跳转方式与转移指令一致,只不过调用是调用子程序,转移是转移到某一个标签处,注意,子程序的最后一条指令必须是RET!!

中断

某种异常或随机 使处理器暂时停止正在运行的程序,转去执行一段特殊处理程序,并在处理结束后返回原程序被中断处继续执行的过程。

中断就直接

INT n

其中n为中断号,8086有256个中断号,0-31为处理器保留的中断号,32-255为用户自定义的中断号。十六进制写为XXH。n4,n4+1存放中断服务子程序入口地址的单元的偏移地址,该单元在数据段,段地址=DS.
20250604224155

中断程序必须伴随中断返回指令IRET

处理器控制指令

CLC:清除进位标志,使得CF=0

CLD:令DF=0,使得进行串操作时数据指针(SI,DI)递增


汇编语言源程序(简答)

一些概念性问题,可能会考简答

20250604224909

简单来说,你依靠汇编语言(而不是c语言等其他语言)写了一段汇编语言源程序,这一源程序经过汇编程序编译为机器语言。

先写一个main.asm

然后 masm(汇编) main.asm称为main.obj

然后link(链接) main.obj称为.exe文件

汇编语言语句分类

  • 指令性语句:CPU执行的指令,如mov、add等,能产生机器指令。
  • 指示性语句:不产生机器指令,主要用于程序的组织和控制,如伪指令、注释等。

属性运算符:

  • 用于指定其后存储器操作数的类型
  • 运算符:PTR
    例:
MOV BYTE PTR [BX],12H

数据定义伪指令(简答-画图)

数据定义伪指令助记符

  • DB(Define Byte):
    定义的变量为字节型
  • DW (Define Word) :
    定义的变量为字类型
  • DD (Define Double Word) :
    定义的变量为双字型
  • DQ (Define Quadword) :
    定义的变量为4字型
  • DT (Define Tenbytes) :
    定义的变量为10字型

20250605150442

如图所示,(3344H)字数据,低二位44存到低地址,高二位33存到高地址。

注意一点:定义字符串必须使用DB,因为ASCII码是一个字节一个字节存储的。(XXH)例如DATA1 DB 'ABCD', 66H,字符串是顺位存储的(低地址到高地址)
20250605151020

重复操作符:[变量名] 伪指令助记符 n DUP(初值)DUP括号里的多个初值也是顺位存储的
例:

M1 DB 10 DUP(0)

?操作符,表示随机值,用于预留存储空间

一个概括性的例子:
20250605151319

符号与段定义伪指令

符号定义伪指令

将表达式的值赋给一个名字。当源程序需多次引用某一表达式时,
可以利用EQU伪指令,用一个符号代替表达式,以便于程序维护
✓ 格式
符号名 EQU 表达式
✓ 操作:
用符号名取代后边的表达式,不可重新定义
例:
CONSTANT EQU 100

段定义伪指令

段定义伪指令用于定义程序的段,段是汇编语言程序的基本组织单位。每个段都有一个名称和类型。

  • SEGMENT:定义一个段的开始
  • ENDS:定义一个段的结束
  • ASSUME:告诉汇编程序某个段寄存器指向哪个段
    例:
DATA SEGMENT
    MEM1 DB 11H ,22H
    MEM2 DB ‘Hello!’
    MEM3 DW 2 DUP ( ? )
DATA ENDS

CODE SEGMENT
    START: MOV AX,DATA
        MOV DS,AX
        MOV AX,CODE
        MOV CS,AX
CODE ENDS
ASSUME CS:CODE,DS:DATA

其他伪指令(宏仅了解)

过程定义

过程定义用于将一段代码封装成一个可重用的模块。通过过程调用,可以在程序中多次执行相同的代码,而无需重复编写。
定义延时子程序

DELAY PROC
PUSH BX
PUSH CX
MOV BL,2
NEXT:MOV CX,4167
W10M: LOOP W10M
DEC BL
JNZ NEXT
POP CX
POP BX
RET
DELAY ENDP

调整偏移量

20250605160154

系统功能调用

单字符输入(01H)

键盘输入字符,存在寄存器AL中

MOV AH ,01
INT 21H
;输入的字符在AL中

字符串输入0AH

键盘输入字符串,存在内存中,格式为:

DAT1 DB 20 DUP (0) ;预留20个字节
MOV AH,0AH
INT 21H
;输入的字符串存储在DAT1中,第一字节为实际输入的字符数

单字符输出(02H)

MOV AH,02H
MOV DL,'A' ;要输出的字符
INT 21H

字符串输出(09H)

DATA SEGMENT
    MESS1 DB 'Input String:', 0DH,0AH,'$'
DATA ENDS
CODE SEGMENT
    MOV AH,09
    MOV DX,OFFSET MESS1
    INT 21H

返回操作系统( DOS)功能(4CH)

程序执行完该2条语句后能正常返回OS
常位于程序结尾处。

MOV AH,4CH
INT 21H

简单的汇编程序分析与设计(简答)

posted @ 2025-06-10 21:15  bradinz  阅读(32)  评论(0)    收藏  举报