一篇速成 汇编程序语言设计之 8086 汇编核心指令

作者:逆境不可逃

技术永无止境

希望我的内容可以帮助到你!!!!


大家吼 ! 我是 逆境不可逃 今天给大家带来文章

《 一篇速通 汇编程序语言设计之 8086 汇编核心指令 》

近期文章 欢迎阅读

【学Git看这篇文章就够了】Git 终极避坑指南 + 全命令速查表-CSDN博客

【学Git看这篇文章就够了】远程仓库 AND 企业协作进阶-CSDN博客

【学Git看这篇文章就够了】基础入门之本地单机 Git-CSDN博客

好,废话不多说,进入正题

一开始接触汇编,看到满屏的英文缩写指令都会觉得头大

其实这些指令就像 CPU 能听懂的「基础动词」

掌握了它们,你就能给 CPU 发号施令

让它完成数据搬运、数值计算、批量处理等各种操作

今天我们把最常用的四大类指令 ------ 数据传送算术运算逻辑操作串处理

用通俗的比喻和直白的用法讲清楚,零基础也能快速理解

一、数据传送指令:CPU 的「搬运小分队」

数据传送是汇编里最常用的操作,就像现实里的搬家、储物、互换位置。它的核心是把数据在寄存器、内存、外设之间挪来挪去,绝大多数情况下不会改变数据本身,只改变数据的存放位置。

1. 通用数据传送指令:最基础的搬运操作

这是日常开发中使用频率最高的一组,包含 4 条指令:MOV、PUSH、POP、XCHG

  • MOV(Move):数据复制传送 相当于电脑里的「复制粘贴」 把源位置的数据复制一份放到目标位置,源位置的数据保持不变 ,格式:MOV 目标操作数, 源操作数,示例:MOV AX, BX ------ 把 BX 寄存器里的数值,复制一份放到 AX 寄存器中, 注意:不能直接把一段内存数据传到另一段内存,也不能直接修改段寄存器,需要通过通用寄存器中转。

  • PUSH / POP:栈操作指令 你可以把栈理解成一个「后进先出」的箱子:PUSH 是往箱子最上面放东西(压栈),POP 是从箱子最上面拿东西(弹栈)。

    • PUSH AX:把 AX 的值放到栈顶,栈指针自动上移
    • POP AX:把栈顶的值取出放到 AX,栈指针自动下移 常用于保存临时数据、调用子程序时保存现场。
  • XCHG(Exchange):数据交换 相当于「互换位置」,不用中间变量,直接交换两个位置的数据。 示例:XCHG AX, BX ------ 执行完成后,AX 里是原来 BX 的值,BX 里是原来 AX 的值。

2. 累加器专用传送指令:和外设打交道

这组指令专门通过累加器(AX/AL)和外部设备端口(比如键盘、串口)交互,包含IN、OUT、XLAT

  • IN:从端口读取数据 从指定的外设端口读取数据,存到 AL(8 位)或 AX(16 位)中。 示例:IN AL, 20H ------ 从 20 号端口读取一个字节,放到 AL 寄存器。

  • OUT:向端口写入数据 把 AL 或 AX 里的数据,写入到指定的外设端口。 示例:OUT 20H, AL ------ 把 AL 里的字节数据,写入 20 号端口。

  • XLAT(Translate):查表转换 俗称「换码指令」,用来快速查表取值。比如你提前在内存里存了一张 ASCII 码对照表,用 XLAT 就能根据索引快速取出对应的值,结果自动存入 AL。 用法:先把表的首地址存入 BX,索引值存入 AL,执行 XLAT 即可得到表中对应位置的数值。

3. 地址传送指令:拿地址,不拿数据

这组指令传送的不是数据本身,而是数据在内存中的地址,包含LEA、LDS、LES

  • LEA(Load Effective Address):取有效地址 把内存操作数的偏移地址,送到指定的通用寄存器。注意它取的是「地址坐标」,不是地址里存储的数值。 示例:LEA AX, [BX+SI] ------ 把 BX+SI 计算出的偏移地址放到 AX,而不是把这个地址里的数据放到 AX。 通俗理解:MOV 是拿盒子里的东西,LEA 是拿盒子的位置坐标。

  • LDS / LES:加载远地址 一次性加载「段地址 + 偏移地址」:LDS 会把段地址存入 DS 数据段寄存器,LES 会把段地址存入 ES 附加段寄存器,偏移地址统一存入指定的通用寄存器。 示例:LDS SI, [1000H] ------ 把内存 1000H 处的偏移地址给 SI,后续的段地址给 DS。

4. 标志寄存器传送指令:操作状态标志

标志寄存器保存着 CPU 运算的各种状态(比如是否进位、结果是否为 0),这组指令专门用来读写标志寄存器,包含LAHF、SAHF、PUSHF、POPF

  • LAHF:把标志寄存器的低 8 位(SF、ZF、AF、PF、CF 等状态标志),复制到 AH 寄存器。
  • SAHF:和 LAHF 相反,把 AH 里的值写回标志寄存器的低 8 位,用来修改标志位。
  • PUSHF / POPF:对整个 16 位标志寄存器做栈操作。PUSHF 把标志寄存器整体压栈保存,POPF 把栈顶数据弹出恢复标志位,常用于子程序中保存和恢复运算状态。

5. 类型转换指令:自动扩展数据长度

做乘除法运算时,经常需要把短数据扩展成长数据,这两条指令会自动按照符号位扩展,保证数值大小不变,包含CBW、CWD

  • CBW(Convert Byte to Word):字节转字 把 AL 里的 8 位有符号数,扩展成 16 位有符号数,结果存在 AX 中。扩展规则:AL 最高位是 0 则 AH 全填 0,最高位是 1 则 AH 全填 1。

  • CWD(Convert Word to Double word):字转双字 把 AX 里的 16 位有符号数,扩展成 32 位有符号数,高 16 位存在 DX,低 16 位存在 AX,同样按符号位自动扩展。

二、算术指令:CPU 的「自带计算器」

算术指令就是负责加减乘除运算,和我们日常使用的计算器逻辑基本一致,运算的同时会同步修改标志寄存器的状态位。

1. 加法指令

包含ADD、ADC、INC三条

  • ADD:普通加法 两个数相加,结果存回目标操作数。 格式:ADD 目标, 源 示例:ADD AX, BX ------ 等价于 AX = AX + BX

  • ADC(Add with Carry):带进位加法 相加时会额外加上进位标志 CF 的值,专门用来计算超过 16 位的大数。比如计算 32 位加法,先算低 16 位,再用 ADC 算高 16 位,把低 16 位的进位包含进去。

  • INC(Increment):自增 1 给目标操作数加 1,等价于目标 = 目标 + 1,常用在循环中给计数器累加。 示例:INC CX ------ CX 的数值加 1

2. 减法指令

包含SUB、SBB、DEC、NEG、CMP五条

  • SUB:普通减法 目标操作数减去源操作数,结果存回目标。 示例:SUB AX, BX ------ 等价于 AX = AX - BX

  • SBB(Subtract with Borrow):带借位减法 相减时会额外减去借位标志 CF 的值,和 ADC 对应,用于实现大数减法。

  • DEC(Decrement):自减 1 给目标操作数减 1,等价于目标 = 目标 - 1,循环中非常常用。

  • NEG(Negate):取负指令 对操作数求补码,也就是正数变负数、负数变正数,等价于操作数 = 0 - 操作数

  • CMP(Compare):比较指令 用目标操作数减去源操作数,但不保存运算结果,只修改标志位 。它是分支判断的核心:执行完 CMP 后,我们就能通过标志位判断两个数是否相等、谁大谁小。 比如执行CMP AX, BX后,如果 ZF 标志为 1,说明 AX 和 BX 数值相等。

3. 乘法指令

包含MUL、IMUL,分别对应无符号数和有符号数乘法

  • MUL(Multiply):无符号乘法

    • 8 位乘法:一个乘数默认在 AL,另一个是指定的 8 位操作数,结果存在 AX(AH 存高 8 位,AL 存低 8 位)
    • 16 位乘法:一个乘数默认在 AX,另一个是指定的 16 位操作数,结果存在 DX:AX(DX 存高 16 位,AX 存低 16 位)
  • IMUL(Integer Multiply):有符号乘法 用法和 MUL 完全一致,专门用于有符号数乘法,保证符号位计算正确。

4. 除法指令

包含DIV、IDIV,同样区分无符号和有符号

  • DIV(Divide):无符号除法

    • 8 位除法:被除数默认在 AX(16 位),除以指定的 8 位操作数;商存在 AL,余数存在 AH
    • 16 位除法:被除数默认在 DX:AX(32 位),除以指定的 16 位操作数;商存在 AX,余数存在 DX
  • IDIV(Integer Divide):有符号除法 用法和 DIV 一致,专门处理有符号数除法,余数的符号和被除数保持一致。

5. 十进制调整指令

计算机内部用二进制运算,但很多场景需要用十进制(BCD 码)计算,这组指令的作用就是把二进制运算结果,修正为正确的十进制格式。

  • 压缩 BCD 调整:DAA(加法调整)、DAS(减法调整) 压缩 BCD 指一个字节存两位十进制数,运算后用这两条指令修正结果。
  • 非压缩 BCD 调整:AAA(加法调整)、AAS(减法调整)、AAM(乘法调整)、AAD(除法调整) 非压缩 BCD 指一个字节只存一位十进制数,对应四种运算的结果修正。

三、逻辑指令:CPU 的「位操作工具箱」

逻辑指令以二进制的「位」为单位进行操作,是汇编里非常灵活的一类指令,常用于控制某一位的开关、实现快速乘除。

1. 逻辑运算指令

包含AND、OR、NOT、XOR、TEST

  • AND:按位与 两个二进制位都为 1,结果才是 1,否则为 0。 典型用法:把某几位清零(屏蔽位)。比如AND AL, 0FH ------ 把 AL 的高 4 位清零,低 4 位保持不变。

  • OR:按位或 两个二进制位只要有一个是 1,结果就是 1。 典型用法:把某几位置 1。比如OR AL, 80H ------ 把 AL 的最高位设为 1,其余位不变。

  • NOT:按位取反 把每一位的 0 变 1、1 变 0,是单操作数指令。注意它不会影响标志位。

  • XOR:按位异或 两个位相同结果为 0,不同结果为 1。 典型用法:① 给寄存器快速清 0,比如XOR AX, AX,执行后 AX 一定为 0,比 MOV 指令更高效;② 翻转某几位的数值。

  • TEST:位测试指令 和 AND 一样执行按位与运算,但不保存结果,只修改标志位 。 用来检测某一位是否为 0。比如TEST AL, 01H,如果执行后 ZF=1,说明 AL 的最低位是 0。

2. 移位指令

把二进制数整体向左或向右移动,分为普通移位、算术移位、循环移位三类,共 8 条:SHL、SHR、SAL、SAR、ROL、ROR、RCL、RCR

逻辑移位
  • SHL(Shift Left):逻辑左移 所有位整体左移,最低位补 0,最高位移入进位标志 CF。左移一位等价于无符号数乘以 2。
  • SHR(Shift Right):逻辑右移 所有位整体右移,最高位补 0,最低位移入 CF。右移一位等价于无符号数除以 2。
算术移位
  • SAL(Shift Arithmetic Left):算术左移 效果和 SHL 完全一致,左移低位补 0,不影响符号位。
  • SAR(Shift Arithmetic Right):算术右移 右移时最高位(符号位)保持不变,保证有符号数的正负属性不变,适合有符号数除以 2。
循环移位
  • ROL / ROR:不带进位循环移位 ROL 循环左移:最高位移到最低位,同时送入 CF; ROR 循环右移:最低位移到最高位,同时送入 CF。 所有数据位在内部循环,不会丢失数据。

  • RCL / RCR:带进位循环移位 把进位标志 CF 也加入循环圈,相当于多了一位参与循环。RCL 是带进位左移,RCR 是带进位右移。

四、串处理指令:CPU 的「批量处理流水线」

这里的「串」指内存中连续的一段数据(比如字符串、数组),串处理指令可以批量操作一整段数据,不用手动写循环逐个处理,执行效率非常高。

1. 方向标志指令:控制处理方向

串处理是按地址逐个推进的,方向标志决定了地址是递增还是递减:

  • CLD:清除方向标志,地址从低到高推进(从串头到串尾)
  • STD:设置方向标志,地址从高到低推进(从串尾到串头)

2. 核心串处理指令

所有串指令都有字节(后缀 B)和字(后缀 W)两个版本,默认规则:源串位于 DS:SI,目标串位于 ES:DI,每执行一次,SI/DI 会自动增减 1(字节)或 2(字)。

  • MOVSB / MOVSW:串传送 把源串的一个字节 / 字,复制到目标串位置,然后自动修改 SI 和 DI。 配合重复前缀可以实现「批量复制内存块」,是最常用的串指令。

  • STOSB / STOSW:串存储 把 AL(字节)或 AX(字)里的值,写入目标串的位置,然后自动修改 DI。 常用于给一段内存批量填充同一个值(比如批量清 0、填充空格)。

  • LODSB / LODSW:串读取 把源串的一个字节 / 字,读取到 AL 或 AX 中,然后自动修改 SI。 通常配合循环使用,逐个读取串内数据进行处理。

  • CMPSB / CMPSW:串比较 将源串和目标串的对应位置数据相减,不保存结果,只修改标志位,然后自动修改 SI 和 DI。 用来比较两个字符串 / 数组是否完全相同。

  • SCASB / SCASW:串扫描 用 AL/AX 里的值,和目标串的对应位置数据做比较,只修改标志位,然后自动修改 DI。 用来在字符串中查找某个特定字符。

3. 重复前缀:让指令自动循环

串指令本身只执行一次,加上重复前缀后,就会自动重复执行;重复次数存放在 CX 寄存器中,每执行一次 CX 减 1,直到 CX 为 0 时停止。

  • REP:无条件重复 只要 CX 不为 0 就持续重复,常和 MOVS、STOS 搭配,实现批量复制、批量填充。 示例:REP MOVSB ------ 连续复制 CX 个字节,从源串复制到目标串。

  • REPE / REPZ:相等时重复 除了 CX 不为 0,还要求比较结果相等(ZF=1)才继续重复。常和 CMPS、SCAS 搭配,用来查找第一个不相等的位置。

  • REPNE / REPNZ:不相等时重复 CX 不为 0,且比较结果不相等(ZF=0)时才继续重复。常和 SCAS 搭配,用来在串中查找第一个匹配的字符。

写在最后

以上就是 8086 汇编最核心的四大类指令,它们是编写汇编程序的「基础词汇」:

  • 搬运数据用数据传送指令
  • 数值计算用算术指令
  • 按位操作用逻辑指令
  • 批量处理内存用串指令

刚开始不用死记硬背,写代码的时候多查多用,慢慢就能熟练掌握。等把这些指令吃透,你就能看懂绝大多数基础汇编代码,也能独立写出简单的汇编程序了。

附参考程序

复制代码
; ========== 数据段:定义程序用到的变量和数据 ==========
DATA SEGMENT
    ; 1. 算术运算测试用变量
    num_byte  DB  12H      ; 8位字节变量
    num_word  DW  1234H    ; 16位字变量
    result    DW  ?        ; 预留结果存储位置

    ; 2. 串操作测试用数据
    src_str   DB  'Hello, Assembly!', 0  ; 源字符串,共16字节
    dest_str  DB  20 DUP(0)              ; 目标缓冲区,20字节初始化为0
    fill_buf  DB  10 DUP(?)              ; 批量填充测试缓冲区
    search_ch DB  's'                    ; 待查找的字符
DATA ENDS

; ========== 代码段:编写指令逻辑 ==========
CODE SEGMENT
    ASSUME CS:CODE, DS:DATA, ES:DATA  ; 声明各段对应的段寄存器

START:
    ; 初始化数据段和附加段(串操作需要ES寄存器,这里和DS共用同一段)
    MOV AX, DATA
    MOV DS, AX
    MOV ES, AX

; ----------------------------------------------------------------------
; 第一部分:数据传送指令演示
; ----------------------------------------------------------------------
    ; 1. MOV 基本数据传送:内存 → 寄存器
    MOV AL, num_byte   ; 把num_byte的值(12H)复制到AL寄存器
    MOV BX, num_word   ; 把num_word的值(1234H)复制到BX寄存器

    ; 2. XCHG 数据交换:交换AX和BX的内容
    XCHG AX, BX        ; 执行后 AX=1234H,BX=0012H

    ; 3. PUSH / POP 栈操作:保存和恢复寄存器
    PUSH AX            ; 将AX压入栈顶保存
    PUSH BX            ; 将BX压入栈顶保存
    POP AX             ; 弹出栈顶数据到AX(得到原BX的值0012H)
    POP BX             ; 弹出栈顶数据到BX(得到原AX的值1234H)

    ; 4. LEA 取有效地址:获取变量的内存偏移地址
    LEA SI, src_str    ; SI = src_str在数据段中的偏移地址
    LEA DI, dest_str   ; DI = dest_str在数据段中的偏移地址

    ; 5. CBW 字节转字:有符号数符号扩展
    MOV AL, 80H        ; AL = 80H(有符号数 -128)
    CBW                ; 扩展为16位,AX = FF80H,数值保持不变

    ; 6. CWD 字转双字:16位扩展为32位
    MOV AX, 8000H      ; AX = 8000H(有符号数 -32768)
    CWD                ; 扩展为32位,高16位DX=FFFFH,低16位AX=8000H

; ----------------------------------------------------------------------
; 第二部分:算术指令演示
; ----------------------------------------------------------------------
    ; 1. ADD 普通加法
    MOV AX, 1000H
    ADD AX, 2000H      ; AX = AX + 2000H = 3000H

    ; 2. ADC 带进位加法:实现32位加法
    ; 计算 0001FFFFH + 00020001H = 00040000H
    MOV AX, 0FFFFH     ; 被加数低16位
    MOV DX, 0001H      ; 被加数高16位
    ADD AX, 0001H      ; 低16位相加,产生进位 CF=1
    ADC DX, 0002H      ; 高16位相加 + 进位,DX = 0001+0002+1 = 0004H

    ; 3. INC 自增1
    MOV CX, 0
    INC CX             ; CX = CX + 1 = 1

    ; 4. SUB 普通减法
    SUB AX, 1000H      ; AX = AX - 1000H

    ; 5. DEC 自减1
    DEC CX             ; CX = CX - 1 = 0

    ; 6. NEG 取负(求补码)
    MOV AX, 5
    NEG AX             ; AX = -5(补码表示为 FFFBH)

    ; 7. CMP 比较指令:只修改标志位,不改变操作数
    MOV AX, 10
    CMP AX, 10         ; 两数相等,ZF标志位置1
    CMP AX, 20         ; AX < 20,SF标志位置1

    ; 8. MUL 无符号8位乘法:AL × 操作数 → AX
    MOV AL, 10H
    MOV BL, 20H
    MUL BL             ; AX = 10H × 20H = 0200H

    ; 9. DIV 无符号8位除法:AX ÷ 操作数 → 商在AL,余数在AH
    MOV AX, 0200H
    MOV BL, 10H
    DIV BL             ; AL = 20H(商),AH = 00H(余数)

; ----------------------------------------------------------------------
; 第三部分:逻辑指令演示
; ----------------------------------------------------------------------
    ; 1. AND 按位与:清零高4位,保留低4位
    MOV AL, 0ABH
    AND AL, 0FH        ; AL = 0BH,高4位被强制清零

    ; 2. OR 按位或:最高位置1
    OR AL, 80H         ; AL = 8BH,最高位变为1

    ; 3. XOR 按位异或:快速清零寄存器(比MOV更高效)
    XOR AX, AX         ; AX = 0000H

    ; 4. TEST 位测试:检测最低位是否为1
    MOV AL, 03H
    TEST AL, 01H       ; 结果非零,ZF=0,说明最低位是1

    ; 5. SHL 逻辑左移:无符号数 ×2
    MOV AX, 3
    SHL AX, 1          ; AX = 6,左移1位等价于乘以2

    ; 6. SAR 算术右移:有符号数 ÷2,符号位保持不变
    MOV AX, 0FFFCH     ; -4 的补码
    SAR AX, 1          ; AX = 0FFFEH(-2),最高位保持1

    ; 7. ROL 循环左移:最高位移到最低位
    MOV AL, 11000000B
    ROL AL, 1          ; AL = 10000001B

; ----------------------------------------------------------------------
; 第四部分:串处理指令演示
; ----------------------------------------------------------------------
    ; 1. 串传送:批量复制字符串(src_str → dest_str)
    CLD                ; 清除方向标志,地址从低到高递增
    LEA SI, src_str    ; 源串地址 → SI
    LEA DI, dest_str   ; 目标串地址 → DI
    MOV CX, 16         ; 复制长度:16个字节
    REP MOVSB          ; 重复执行MOVSB,直到CX=0,完成批量复制

    ; 2. 串存储:批量填充内存(把fill_buf全部填0)
    LEA DI, fill_buf
    MOV CX, 10         ; 填充10个字节
    MOV AL, 0          ; 填充的数值
    REP STOSB          ; 重复执行STOSB,10个字节全部变为0

    ; 3. 串扫描:在dest_str中查找字符's'
    LEA DI, dest_str
    MOV AL, search_ch  ; 待查找的字符 → AL
    MOV CX, 20         ; 最大扫描长度
    CLD
    REPNE SCASB        ; 不相等就继续找,找到匹配字符后停止
                       ; 找到后:DI指向匹配字符的下一位,CX为剩余未扫描长度

; ----------------------------------------------------------------------
; 程序结束:正常返回DOS系统
; ----------------------------------------------------------------------
    MOV AH, 4CH        ; DOS功能号:程序退出
    INT 21H            ; 调用DOS中断

CODE ENDS
END START
相关推荐
iCxhust2 小时前
MTK8088单板机制作(一)时钟电路
汇编·单片机·嵌入式硬件·微机原理·8088单板机
iCxhust5 小时前
8086 汇编位测试使用方法
汇编·单片机·嵌入式硬件·微机原理·8088单板机
iCxhust5 小时前
用汇编在8088单板机上创建一个进程
汇编·微机原理
AI科技星1 天前
第三卷:质数王朝志(全卷定稿)
c语言·开发语言·汇编·electron·概率论
H Journey1 天前
汇编基础知识:CPU的寻址逻辑
汇编·cpu寻址
AI科技星2 天前
《全域数学/数术工坊》体系总览
c语言·开发语言·汇编·electron·概率论
H Journey2 天前
用汇编语言写一个hello world,并进行汇编和编译
汇编·assembly·寄存器
疯狂打码的少年3 天前
【程序语言与编译】程序设计语言分类(机器/汇编/高级)
汇编·笔记
JAMSAN09303 天前
16.0% 高增长!全球异构计算架构服务市场扩容态势
汇编·人工智能·架构