整点薯条

没有薯条的码头毫无意义。

0%

汇编与接口 Chapter3笔记

3.1 8086 指令系统

3.1.1 寻址方式

指令的寻址方式就是指令中操作数的表示方式,8086 的寻址方式有立即寻址、寄存器寻址、存储器寻址、串操作寻址、外设 I/O 端口寻址、程序转移操作寻址

  • 与数据有关的寻址方式

    1. 立即寻址

      指令直接给出操作数的数值

      立即数只能作为源操作数,若十六进制以字母开头,要在前面加 0,如0FFH

      操作位数由目的操作数决定

      eg. MOV AX,0FFFH

    2. 寄存器寻址

      操作数存放在寄存器中,地址码为寄存器的符号

      由于寄存器在微处理器内部,所有操作都在内部进行,不执行访问内存的周期,执行速度最快

      可用于源/目的操作数

      eg. MOV DS,AXMOV AL,31H

    3. 存储器寻址

      操作数存储在主存中,BIU 根据 EU 传送来的偏移地址(操作数的有效地址 EA)算出物理地址后执行存取该操作数的总线周期

      • 直接寻址

        指令直接给出操作数的偏移地址即 EA,eg. MOV AX,[2002H]INC BYTE PTR[05A2H]

        操作数的地址也可以用符号变量表示(之前定义在数据段中的变量)

        默认段地址为 DS 中的地址,可通过段跨越前缀进行更改,eg. MOV AX, ES:VALUE

        规定 8086 的双操作数指令至少有一个操作数采用寄存器寻址或立即寻址,即两个操作数不能同时采用与存储器有关的寻址方式

      • 寄存器间接寻址

        操作数的 EA 在BX 或 SI/DI/BP中,eg. MOV AX,[BX]

        BX/SI/DI,段地址由 DS 指明

        BP,段地址由 SS 指明

        可通过段跨越前缀更改

      • 寄存器相对寻址

        操作数的 EA 为寄存器的内容和一个带符号的 8 位/16 位的位移量之和

        只有 BX/BP/SI/DI 可用于寄存器相对寻址

        BX/SI/DI,段地址由 DS 指明

        BP 段地址由 SS 指明

        可通过段跨越前缀更改

        eg. MOV AX,[SI+06H]MOV AX,COUNT[BX] ;COUNT为常量/变量MOV AX,[COUNT+BX] ;COUNT为常量MOV DL,ES:STRING[SI]

      • 基址变址寻址

        操作数的 EA 为基址寄存器(BX/BP)的内容与变址寄存器(SI/DI)的和

        eg. MOV AX,[BX+SI]MOV AX,[BX][SI]

        BX,段地址由 DS 指明

        BP,段地址由 SS 指明

        可添加段跨越前缀更改

      • 相对基址变址寻址

        操作数的 EA 为基址寄存器(BX/BP)、变址寄存器(SI/DI)的内容以及一个带符号的 8 位/16 位偏移量的和

        BX,段地址由 DS 指明

        BP,段地址由 SS 指明

        可添加段跨越前缀更改

        eg. MOV AX,[BX+DI+08H]、**MOV AX,MASK[BX][SI]**、MOV,[MASK+BX+SI]

  • 与转移地址有关的寻址方式(程序转移寻址)

3.1.2 数据传送类指令

  • MOV DST, SRC(字/字节操作,不影响标志位)

    注意:

    • 目的操作数不能是立即数

    • 两个操作数的寻址方式不能同时为存储器寻址

    • 两个操作数位数必须一致

      eg. MOV BYTE PTR[BX],255是对的,MOV [BX],255是错的

    • CS 不能作为目的操作数

    • 源和目的不能同时为段寄存器

    • 立即数不能直接送段寄存器,一般要以 AX 为中介

      1
      2
      MOV    AX,2000H
      MOV DS, AX

堆栈操作指令

  • PUSH SRC(字操作,不影响标志位)

    首先将 SP 减 2,然后将 SRC 的低字节存入(SP),高字节存入(SP+1)

    注意:

    • 不能用立即寻址(操作数不能是立即数)

    • 必须是字操作

  • POP DST(字操作,不影响标志位)

    首先将(SP)中的字节数据存入 DST 的低八位,(SP+1)的字节数据存入 DST 的高八位,然后将 SP 加 2

    注意:

    • 不能用立即寻址(操作数不能是立即数)

    • 必须是字操作

    • 不能使用 CS 寄存器


地址传送指令

  • LEA REG, SRC(字操作,不影响标志位)

    将 SRC 的有效地址存入指定寄存器

    • 必须用存储器寻址
  • LDS REG, SRC(字操作,不影响标志位)

    将 SRC 指明的存储单元的内容送 REG,将地址为 SRC+2 的存储单元的内容送 DS

    • 必须用存储器寻址
  • LES REG, SRC(字操作,不影响标志位)

    将 SRC 指明的存储单元的内容送 REG,将地址为 SRC+2 的存储单元的内容送 ES

    • 必须用存储器寻址

零地址指令

  • LAHF(Load AH with Flags,不影响标志位,隐含操作数为 FR 的低八位)

    将 FR 的低八位送 AH

  • SAHF(Store AH into Flags,影响标志位)

    将 AH 的内容送 FR 的低八位

  • PUSHF(Push Flags,不影响标志位)

  • POPF (Pop Flags,影响标志位)


  • XCHG DST,SRC(字/字节操作,不影响标志位)

    交换 DST 和 SRT 的数据

    注意:

    • 两操作数均不能为立即数

    • 两操作数均不能用段寄存器

    • 两操作数不能同时采用与存储器有关的寻址方式

    eg. MOV AX,VAR


换码指令

  • XLAT(字节操作,不影响标志位)

    将地址为[BX]+[AL](AL 高位补零)的内存单元当中的字节数据送至 AL

3.1.3 位操作类指令

位操作运算指令分为逻辑运算指令和移位指令
要注意每一条位操作指令如何影响标志位

  • AND/OR/XOR DST, SRC(字、字节操作)

    将 DST 和 SRT 指明的操作数安位与/或/非,结果存在 DST

    注意:

    • DST 不能是立即数

    • 对标志位的影响:CF=OF=0,SF、ZF、PF 看结果,AF 不确定

    eg. ASCII 码大小写互换:第 6 位取反,其余位不变(和 0 异或不变,和 1 异或相当于取反),XOR AL,00100000B [注]:这里期末考用到了

  • TEST DST,SRC(字/字节操作)

    将 DST 指明的操作数与 SRC 指明的操作数按位与,只做运算,不存结果,即只影响 FR

    对标志位的影响:CF=OF=0,SF、ZF、PF 看结果,AF 不确定

  • NOT OPR(字/字节操作)

    对 OPR 指明的操作数按位取反,结果仍存 OPR

    • 不能是立即数

    • 不影响任何标志位


移位指令

(个人实验供参考)关于移位大于 1 次时对 OF 位的影响:与 PPT 上说的不一样,事实上根据实验得到结论

指令 SHL 对 OF 的影响:若移位完成后的符号位与未移位时的符号位相同,则 OF 为 0,否则为 1

指令 SHR/ROL/ROR/RCL/RCR 对 OF 的影响:若移位完成后的符号位与最后一次移位完成之前的符号位相同,则 OF 为 0,否则为 1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
        .MODEL SMALL
.DATA
.CODE
START: MOV AL,10101010b
MOV CL,2
;SHL AL,CL
;SHR AL,CL
;ROL AL,CL
;ROR AL,CL
;RCL AL,CL
;RCR AL,CL
OVER: MOV AX, 4C00H
INT 21H
END START

逻辑移位指令

  • SHL OPR,1/CL(字/字节操作)

    将 OPR 指明的操作数逻辑左移,空位补零,移出来的位进 CF

    • OPR 不能是立即寻址

    • SF/ZF/PF 根据结果设置,AF 不确定

      OF:事实上根据测试,不是只在移位次数为 1 时影响;而是若移位后的符号位与未移位时的符号位不同,则 OF=1,否则 OF=0

  • SHR OPR,1/CL(字/字节操作)

    将 OPR 指明的操作数逻辑右移,空位补零,移出来的位进 CF

    • OPR 不能是立即寻址

    • SF/ZF/PF 根据结果设置,AF 不确定

      OF:最后一次移位后的符号位与最后一次的前一次移位后的符号位不同,OF=1,事实上只有移位次数为 1 的时候才有可能改变,因为大于一次时高位都补零了


算术移位指令

  • SAL OPR,1/CL(字/字节操作)

    将 OPR 指明的操作数算数左移,低位补零,移出去的位进 CF

    • OPR 不能是立即寻址

    • SF/ZF/PF 根据结果设置,AF 不确定

      OF:若移位完成后的符号位与最后一次移位完成之前的符号位相同,则 OF 为 0,否则为 1

  • SAR OPR,1/CL(字/字节操作)

    将 OPR 指明的操作数算数右移,高位补符号位,移出去的位进 CF

    • OPR 不能是立即寻址

    • SF/ZF/PF 根据结果设置,AF 不确定

      OF:最后一次移位后的符号位与最后一次的前一次移位后的符号位不同,OF=1,事实上只有移位次数为 1 的时候才有可能改变,因为大于一次时高位一直补符号位了


不带进位的循环移位指令

  • ROL OPR,1/CL(字/字节操作)

    将 OPR 指明的操组数循环左移,低位空出的位用高位移出的位补,同时移出的位进入 CF

    • 不能是立即寻址

    • 不影响 SF/ZF/PF/AF

      OF:若移位完成后的符号位与最后一次移位完成之前的符号位相同,则 OF 为 0,否则为 1

  • ROR OPR,1/CL(字/字节操作)

    将 OPR 指明的操组数循环右移,高位空出的位用低位移出的位补,同时移出的位进入 CF

    • 不能是立即寻址

    • 不影响 SF/ZF/PF/AF

      OF:若移位完成后的符号位与最后一次移位完成之前的符号位相同,则 OF 为 0,否则为 1


带进位循环移位指令

  • RCL OPR,1/CL(字/字节操作)

    将 OPR 指明的操作数连同 CF 一起循环左移(CF 在左边)

    • 不能是立即寻址

    • 不影响 SF/ZF/PF/AF

      OF:若移位完成后的符号位与最后一次移位完成之前的符号位相同,则 OF 为 0,否则为 1

  • RCR OPR,1.CL(字/字节操作)

    将 OPR 指明的操作数连同 CF 一起循环右移(CF 在右边)

    • 不能是立即寻址

    • 不影响 SF/ZF/PF/AF

      OF:若移位完成后的符号位与最后一次移位完成之前的符号位相同,则 OF 为 0,否则为 1

3.1.4 算术运算类指令

算术运算的操作数一定是定点无/带符号整数
双操作数指令至少有一个操作数在寄存器中/立即寻址
单操作数不允许立即寻址
要注意对标志位的影响

  • ADD DST,SRC(字/字节操作)

    将 DST 和 SRT 指明的操作数相加,结果保存在 DST

    • SF/ZF/PF/AF 看运行情况

    • 若两个操作数符号相同,但结果的符号与操作数的符号相反,则产生溢出,OF=1,否则 OF=0

    • 若最高位产生进位,则 CF=1,否则 CF=0,CF 可以表示无符号数的溢出

  • SUB DST,SRC(字/字节操作)

    DST 指明的操作数减 SRC 指明的操作数,结果保存在 DST

    • SF/ZF/PF/AF 看运行情况

    • 若两个操作数符号相反,但结果的符号与减数(SRC)的符号相反,则产生溢出,OF=1,否则 OF=0

    • (无符号数)若被减数小于减数,则 CF=1,否则 CF=0

  • ADC DST,SRC(字/字节操作)

    将 DST 与 SRC 指明的操作数以及当前 CF 的值相加,结果保存在 DST

    • SF/ZF/PF/AF 看运行情况

    • 若两个操作数符号相同,但结果的符号与操作数的符号相反,则产生溢出,OF=1,否则 OF=0

    • 若最高位产生进位,则 CF=1,否则 CF=0

    eg. 32 位数加法,目的操作数存放在 DX(高)和 AX(低);源操作数存放在 BX(高)、CX(低)

    1
    2
    ADD    AX, CX
    ADC DX, BX
  • SBB DST,SRC(字/字节操作)

    DST 指明的操作数减 SRC 指明的操作数,再减去当前 CF 的值,结果存 DST

    • SF/ZF/PF/AF 看运行情况

    • 若两个操作数符号相反,但结果的符号与减数(SRC)的符号相反,则产生溢出,OF=1,否则 OF=0

    • (无符号数)若被减数小于减数,则 CF=1,否则 CF=0

    eg. 32 位数减法,目的操作数存放在 DX(高)和 AX(低)中;源操作数为立即数 80004491H

    1
    2
    SUB    AX,4491H
    SBB DX,8000H
  • INC OPR

    OPR 指明的操作数+1 后存于 OPR

    • 根据结果影响 OF/SF/ZF/PF/AF

    • 不影响 CF

  • DEC OPR

    OPR 指明的操组数-1 后存于 OPR

    • 根据结果影响 OF/SF/ZF/PF/AF

    • 不影响 CF

  • CMP DST,SRC(字/字节操作)

    DST 指明的操作数减 SRC 指明的操作数,只做运算,不存结果,即只改变符号位,通常后面跟条件转移指令

    • SF/ZF/PF/AF 看运行情况

    • 若两个操作数符号相反,但结果的符号与减数(SRC)的符号相反,则产生溢出,OF=1,否则 OF=0

    • (无符号数)若被减数小于减数,则 CF=1,否则 CF=0

  • NEG OPR(字/字节运算)尚存疑?

    对 OPR 指明的操作数求补,即按位取反后加 1,结果存 OPR

    • 相当于求相反数

    • 根据运算结果影响 CF/OF/ZF/SF/PF/AF

    • 当且仅当操作数为 0 时 CF=1,否则 CF=0

    • 当且仅当字节运算时对-128 求补或字运算时对-32768 求补时 OF=1,否则 OF=0

    附:一个求负数补码的简便方法

    找到二进制表示形式下的最右边的 1,对该位左边的所有位(除去符号位)按位取反

    eg. -1 的二进制表示为 10000001B,按如上操作后变为 11111111B,即 0FFH,为-1 的补码

  • MUL SRC(字/字节操作)

    若 SRC 指明的操作数为 8 位,则将其与 AL 中的数相乘,结果存于 AX;若 SRC 指明的操作数为 16 位,则将其与 AX 中的数相乘,结果的高 16 位存于 DX,低 16 位存于 AX

    • 所有操作数都是无符号数

    • 若乘积的高半部分位 0,则 CF=OF=0;否则 CF=OF=1;反映乘法是否超过原有的位宽

    • 其余标志位无定义(不确定 0/1)

  • IMUL SRC(字/字节操作)

    若 SRC 指明的操作数为 8 位,则将其与 AL 中的数相乘,结果存于 AX;若 SRC 指明的操作数为 16 位,则将其与 AX 中的数相乘,结果的高 16 位存于 DX,低 16 位存于 AX

    • 所有操作数都是带符号数

    • 若乘积的高半部分位 0,则 CF=OF=0;否则 CF=OF=1;反映乘法是否超过原有的位宽

    • 其余标志位无定义(不确定 0/1)

  • DIV SRC(字/字节操作)

    若 SRC 为 8 位,则用 AX 中的数除以 SRC 指明的数,商存 AL,余数存 AH;若 SRC 为 16 位,则用 DX(高 16 位)和 AX(低 16 位)组成的 32 位无符号整数除以 SRC 指明的数,商存 AX,余数存 DX

    • 所有操作数都是无符号整数

    • 所有标志位均不确定

    • 若位宽不足以容纳商(商溢出),将自动转入 0 型中断处理程序,此时得到的商和余数均不确定

  • IDIV SRC(字/字节操作)

    若 SRC 为 8 位,则用 AX 中的数除以 SRC 指明的数,商存 AL,余数存 AH;若 SRC 为 16 位,则用 DX(高 16 位)和 AX(低 16 位)组成的 32 位无符号整数除以 SRC 指明的数,商存 AX,余数存 DX

    • 所有操作数都是带符号整数

    • 所有标志位均不确定

    • 商的符号根据代数除法规则确定,余数的符号同被除数

    • 若位宽不足以容纳商(商溢出),将自动转入 0 型中断处理程序,此时得到的商和余数均不确定

  • CBW (convert byte to word)

    隐含操作数 AL,若 AL 最高位为 0,则令 AH=00H,若 AL 最高位为 1,则令 AH=0FFH

    • 不影响标志位

    • 符号扩展指令用于将被除数调整为合适的位宽

  • CWD (convert word to double word)

    隐含操作数 AX,若 AX 最高位为 0,则令 DX=0000H,若 AX 最高位为 1,则令 DX=0FFFFH

    • 不影响标志位

    • 符号扩展指令用于将被除数调整为合适的位宽

  • DAA(十进制调整指令)

    隐含操作数 AL,对 AL 中的压缩 BCD 码进行修正:

    1. 若 AL 的低 4 位在 A~F 之间或 AF=1,则将 AL 的值加 06H,结果存 AL 并将 AF 置 1

    2. 若 AL 的高 4 位在 A~F 之间或 CF=1,则将 AL 的值加 60H,结果存 AL 并将 XF 置 1

    • 必须跟在 ADD 或 ADC 指令之后(AL 为目的操作数)

    • 对 OF 无定义,根据结果影响所有其余标志位

    eg. 计算两个压缩 BCD 码 28 与 68 之和

    1
    2
    3
    MOV    AL, 00101000B
    ADD AL, 01101000B
    DAA
  • DAS(十进制调整指令)

    隐含操作数 AL,对 AL 中的压缩 BCD 码进行修正:

    1. 若 AL 的低 4 位在 A~F 之间或 AF=1,则将 AL 的值减 06H,结果存 AL 并将 AF 置 1

    2. 若 AL 的高 4 位在 A~F 之间或 CF=1,则将 AL 的值减 60H,结果存 AL 并将 XF 置 1

    • 必须跟在 SUB 或 ASBB 指令之后(AL 为目的操作数)

    • 对 OF 无定义,根据结果影响所有其余标志位

    eg. 计算两个压缩 BCD 码 86 与 97 之差

    1
    2
    3
    4
    5
    MOV    AL,10000110B
    SUB AL,10010111B
    DAS
    ; 86+(-97)
    ; 0EFH-06H-60H=89H=10001001B即BCD码的-5
  • AAA(ASCII 调整指令)

    隐含操作数 AL,对 AL 中的非压缩 BCD 码(或十进制数的 ASCII 码)进行修正:

    • 必须跟在 ADD 或 ADC 指令之后(AL 为目的操作数)

    • 影响 AF/CF,对其余标志位无定义

    eg. 已知(AX)=0535H,(BL)=39H,分析指令

    1
    2
    ADD    AL,BL
    AAA

    分析:

    结果(AX)=0604H,??意义??不是很懂这个指令

  • AAS(ASCII 调整指令)

    隐含操作数 AL,对 AL 中的非压缩 BCD 码(或十进制数的 ASCII 码)进行修正:

    • 必须跟在 SUB 或 SBB 指令之后(AL 为目的操作数)

    • 影响 AF/CF,对其余标志位无定义

  • AAM(ASCII 调整指令)

    隐含操作数 AX,对 AL 中的非压缩 BCD 码修正:

    AL 中的内容除以 10,余数存 AL,商存 AH

    • 必须跟在 MUL 指令之后,两个操作数为非压缩 BCD 码(高四位均为 0

    • 根据 AL 中结果设置 SF/ZF/PF,其余标志位无定义

      eg. 已知(AL)=07H,(BL)=09H,分析指令

      1
      2
      MUL    BL
      AAM

      分析:

  • AAD(ASCII 调整指令)

    隐含操作数 AX,对 AX 中的非压缩 BCD 码修正:

    (AH)*10+(AL)结果存 AH,然后将 AH 清零

    • 必须在 DIV 指令之前,被除数存于 AX,为非压缩 BCD 码(AH 存十位,AL 存各位且 AH、AL 高 4 位均为 0)
    • 根据 AL 中结果设置 SF/ZF/PF,其余标志位无定义

    eg. 编程实现 53/3

3.1.5 字符串操作类指令

包括串传送、串比较、串扫描、从串取、存入串
一条串操作指令仅能完成 1 字节/字的操作,需要配合重复前缀指令才能实现对整个串的操作
分别用 SI 和 DI 作为源串和目的串的指针,源串默认在数据段,但可以通过段跨越前缀修改,目的串必须在附加段
每次处理完当前指向的字符后要修改段指针,修改方向由 DF 决定,DF=0 时,DI/SI 增加,DF=1 时,DI/SI 减小
DF 标志位的清零和置 1 由指令 CLD 和 STD 完成

  • REP MOVS/LODS/STOS

    1. 若 CX 为零则结束,否则转 2

    2. CX=CX-1

    3. 执行串操作指令,转 1

    • 不影响标志位
  • MOVS DST, SRC(字/字节操作)

    MOVS/MOVSW

    将 SRC 指向的字节(字)存储单元的内容送至 ES:DI 指向的字节(字)存储单元;然后根据 DF 的值将 SI 和 DI 加/减 1/2

    • 第一种形式由操作数指明字/字节操作

    • 第二种形式默认[DS:SI]送[ES:DI]

    • 别忘了设置 DF

      思考:DF 何时取 0,何时取 1?

      当源串与目的串存储空间有重合时,若源串在前,DF=1;若源串在后,DF=0

    • 不影响状态位

  • STOS DST

    STOSB/STOSW

    将 AL(AX)的值传送至 ES:DI 指向的字节(字)存储单元,然后根据 DF 的值将 DI 增加/减少 1/2

    • 第一种形式由操作数指明字/字节操作

    • 常用于缓冲区初始化

    • 不影响标志位

  • LODS SRC

    LODSB/LODSW

    将 SRC 指向的字节(字)存储单元送至 AL(AX),然后根据 DF 的值将 SI 增加/减少 1/2

    • 第一种形式由操作数指明字/字节操作

    • 不影响标志位

    • 一般不与 REP 联用

  • REPE/REPZ CMPS/SCAS

    1. 若 CX 不为 0 且 ZF=1 则转 2,否则结束

    2. CX=CX-1

    3. 执行串操作指令,转 1

    • 本身不影响标志位,影响标志位的是其后的串操作
  • CMPS SRC, DST

    CMPSB/CMPSW

    用 SRC 指向的字节(字)存储单元的内容减去 ES:DI 指向的字节(字)存储单元的内容,根据结果设置标志位,然后根据 DF 的值将 SI 和 DI 增加/减少 1/2

    • 对符号位的影响同 SUB 指令

    • 第一种形式由操作数指明字/字节操作

    • 第二种形式默认[DS:SI]-[ES:DI]

  • REPNZ/REPNE CMPS/SCAS

    1. 若 CX 不为 0 且 ZF=0 则转 2,否则结束

    2. CX=CX-1

    3. 执行串操作指令,转 1

    • 指令本身不影响标志位,影响标志位的是串操作指令
  • SCAS DST

    SCASB/SCASW

    用 AL(AX)中的内容减去 ES:DI 指向的字节(字)存储单元的内容,根据结果设置标志位,然后根据 DF 的值将 DI 增加/减少 1/2

    • 对符号位影响同 SUB 指令

    • 第一种形式由操作数指明字/字节操作

    eg. 比较两个等长的字符串是否相同,相同用 0 表示,不同用-1 表示,结果存入 result 字节单元

    1
    2
    3
    4
    5
    6
    7
    8
    9
        LEA    SI,STR1
        LEA DI,STR2
        MOV CX,LEN ;LEN是字符串长度
        CLD ;DF=0
    REPZ CMPSB
    XOR AL,AL
    JNZ RE ;不为零则相等
    NE: DEC AL
    RE: MOV RESULT,AL

3.1.6 控制转移类指令

根据功能划分:包括无条件转移、条件转移、循环、子程序调用及返回、中断及返回
根据目标地址与本指令是否在同一代码段划分:段内转移、段间转移。段内转移范围在-128~127 之间,段内转移仅需目标的有效地址(CS)不变;段间转移需要确定目标的有效地址和段地址并改变 IP 和 CS 的值
寻址方式:

  1. 相对寻址:用于段内转移,目标地址的有效地址为 IP 的当前值与指令中给出的 8 位或 16 位位移量之

  2. 段内寄存器寻址:段内转移的目标的有效地址为某 16 位寄存器的内容

  3. 段内间接寻址:段内转移的目标的有效地址为某字存储单元的内容

  4. 段间直接寻址:指令中直接给出目标的段地址和有效地址代替 CS 和 IP 的内容实现转移

  5. 段间间接寻址:目标地址为存储器中连续两个字单元的内容(低地址为有效地址,高地址为段地址

注意:所有的条件转移指令只能使用相对寻址的 8 位位移量,也就是都是段内转移,指令本身不影响标志位

  • JMP(无条件转移指令)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    ; 段内相对转移
    JMP PROG ; 16位
    JMP SHORT PROG ; 8位
    ; 段内寄存器/间接转移
    JMP BX
    JMP WORD PTR [BX+SI]
    ; 段间直接转移
    JMP FAR PTR PROC ; 4字节
    ; 段间间接转移
    JMP DWORD PTR [DI + BRCHTABLE]
    • 不影响标志位
  • 条件转移指令

    • JZ/JE JNZ/JNE

      JZ:ZF 为 1 时跳转,否则不跳转;JNZ 反之

    • JS JNS

      JS:SF 为 1 时跳转,否则不跳转;JNS 反之

    • JO JNO

      JO:OF 为 1 时跳转,否则不跳转;JNO 反之

    • JP/JPE JNP/JPO

      JP:PF 为 1 时跳转,否则不跳转;JNP 反之

    • JC/JB/JNAE JNC/JNB/JAE

      JC:CF 为 1 时跳转,否则不跳转;JNC 反之

    • JA/JNBE JNA/JBE

      JA:CF=ZF=0 则跳转,否则不跳转;JNA 反之

      其实 JA 就是高于则跳转,JNBE 就是不是低于或等于也就是高于,一个意思

    • JL/JNGE JNL/JGE

      JL:$OF \oplus SF = 1$ 则跳转,否则不跳转;JNL 反之

      jump if less 小于则转移

    • JG/JNLE JNG/JLE

      JG:$OF \oplus SF=0$ 且 ZF 为 0 则跳转,否则不跳转;JNG 反之

      jump if greater 大于则转移

    JB/JBE/JNB/JNBE/JA/JAE/JNA/JNAE 用于无符号数比较

    JL/JLE/JNL/JNLE/JG/JGE/JNG/JNGE 用于带符号数比较

    • JCXZ(jump if cx=zero)

      CX=0 则跳转,否则不转

  • 循环指令

    • LOOP OPR

      CX 减 1 存 CX,若 CX 非 0,则转移至标号 OPR 处执行,否则按照代码顺序执行下一条指令

      • 属于“直到型循环”

      • 只能使用相对寻址的 8 位位移量

      • 不影响标志位

    • LOOPZ/LOOPE

      LOOPNZ/LOOPNE

      CX 减 1 存 CX,若 CX 非零且 ZF=1(0),则转移至标号 OPR 处执行,否则按照代码顺序执行下一条指令

      • 只能用相对寻址的 8 位位移量

      • 不影响标志位

  • 子程序调用指令

    CALL DST

    DST:子程序入口地址

    • 段内调用:当前 IP 值进栈(保护断点),然后将 DST 指明的偏移地址送 IP

    • 段间调用:当前 CS 值入栈,当前 IP 值入栈(保护断点,注意顺序),然后将 DST 指明的段地址送 CS,偏移地址送 IP

  • 子程序返回指令

    作为子程序的最后一条指令,返回主程序 CALL 指令后的下一条指令继续执行

    • RET/RET N

      段内返回,出栈一个字送 IP(恢复断点)

      若带一个立即数 N,则在上述操作完成后额外出栈 N/2 个字

    • RETF/RETF N

      段间返回,出栈两个字,第一个字送 IP,第二个字送 CS(恢复断点,注意顺序)

      若带一个立即数 N,则在上述操作完成后额外出栈 N/2 个字

    不影响标志位

  • 中断指令 INT

    INT TYPE

    TYPE 为 0~255 之间的常量

    1. 当前标志寄存器 FLAGS 入栈

    2. 当前 CS、IP 值入栈(注意顺序)(保护断点)

    3. 物理地址为 $TYPE \times 4$ 的字存储单元的内容送 IP,$TYPE\times 4+2$ 的字存储单元的内容送 CS(寻找中断服务程序入口地址)

    4. IF 和 TF 清零(关中断)

      注:参见中断向量表

    • INT 指令不影响除 IF 和 TF 之外的标志位

    关于 IP 和 CS 的入栈/出栈顺序:

    可以这么记,栈是向下生长的(地址由大到小),在栈中,保存段地址的地址总是大于保存段内偏移地址的地址

  • 中断返回指令 IRET

    IRET
    出栈第一个字送 IP;出栈第二个字送 CS;出栈第三个字送 FLAGS

  • 系统功能调用

    以 21H 为总入口,再配以具体功能号(AH),常用的有:

    • 01H:从键盘输入一个字符并回显至屏幕

    • 02H:显示一个字符至屏幕(字符放在 DL)

    • 09H:显示字符串至屏幕

    • 0AH:从键盘输入字符串到缓冲区

    • 4CH:带返回码结束

  • 中断指令 INTO(溢出中断服务)
    若 OF=0,继续执行下一条指令
    若 OF=1:

    1. FLAGS 入栈

    2. CS、IP 入栈

    3. 物理地址为 10H 的字存储单元的内容送 IP,物理地址为 12H 的字存储单元的内容送 CS(类型为 4 的中断)

    4. IF 和 TF 清零

    • INTO 不影响除 IF 和 TF 以外的标志位
  • 标志操作指令(不影响其余标志位)

    • CLC,将 CF 清零

    • CMC,将 CF 取反

    • STC,将 CF 置 1

    • CLD,将 DF 清零

    • STD,将 DF 置 1

    • CLI,将 IF 清零

    • STI,将 IF 置 1

      开中断,8259A 编程中,调用某中断后若想中断嵌套,必须在中断处理程序开头加上 STI

    对于其他标志位无相应的清零或置 1 指令

  • 无操作指令 NOP(不影响标志位)

  • 停机指令 HLT
    使处理机处于停机状态,以等待一次外部中断或 RESET 信号的到来,中断处理结束后继续执行后续指令

  • 等待指令 WAIT
    等待 $\overline{TEST}$ 信号有效,每五个时钟周期测试一次,有效后顺序执行下一条指令

  • 交权指令 ESC
    ESC OPCODE, SRC
    与 WAIT 指令一同用于与协处理器配合

  • 总线封锁前缀指令 LOCK
    可以添加在任何指令之前,在该条指令执行期间保持 CPU 对总线的控制权,其他处理器不能从 CPU 抢占总线

3.2 8086 汇编语言的基本语法

  • 框架(简略模式)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
            ;采用简化版的段定义伪指令,下一个段的开始即表示上一个段的结束
    .model small
    .stack [常量(大小为常量个字节)默认1KB]
    .data
    ; ...定义的数据
    ; [变量名] DB 操作数列表
    ; DB(define word)
    ; DD(define double word)
    ; DQ
    ; DT
    ; PORTA EQU 20H 符号常量也可用=定义
    ; PTR 类型属性操作符 转换类型 类型 PTR 变量名/含变量名的表达式
    .code [段名]
    start: mov ax, @data ; @data表示代码段名
    mov ds, ax ; 装载数据段

    ; ....一些操作

    mov ax,4c00h
    int 21h ; 调用21号中断结束汇编
    end start
  • 框架(非简略模式)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    SSTACK	SEGMEN	STACK
    DB 200 DUP(0)
    SSTACK ENDS
    DATA SEGMENT
    ; ORG 3000H ; ORG规定起始地址
    ; ARY DB 100,98,-1,-2,-4,7,0,100,32,1
    ; ARRY DQ DUP(?) ; DUP复制操作符,?表示只分配存储空间
    DATA ENDS
    CODE SEGMENT
    ASSUME CS:CODE,DS:DATA,SS:SSTACK
    START: MOV AX,DATA
    MOV DS,AX
    MOV AX,STACK
    MOV SS,AX
    ; CS不需要送段寄存器
    ; ...一些操作
    MOV AX,4C00H
    INT 21H ; 调用21号中断结束汇编
    CODE ENDS
    END START
  • 标识符的属性

    • 段属性
      标号的段属性必在 CS 寄存器中

    • 偏移属性(16 位无符号数)

    • 类型属性

      • 标号:NEAR/FAR

      • 变量名:BYTE/WORD/DWORD/QWORD/TBYTE

  • 常量

    • 常数

    • 字符

    • 字符串(可以在单引号里也可以在双引号里)

    • 符号常量
      标识符 EQU/= 常量或常量表达式 该语句不占内存

      $:当前行的偏移地址

  • 变量

    • DB/DW/DD/DQ/DT

    • 类型转换:
      类型 PTR 变量名/含变量名的表达式

      JMP WORD PTR [BX]

  • 运算符(操作符)

    • 算术运算符:“+” “-” “*” “/” 和 MOD

    • 逻辑运算符:AND/OR/XOR/NOT/SHL/SHR

    • 关系运算符:EQ/NE/LT/GT/LE/GE

    • 属性运算符:PTR/SHORT/THIS/HIGH/LOW/TYPE/LENGTH/SIZE

    • 地址运算符:“[]” 、“$”、 “:”、 OFFSET、SEG

    运算符出现在操作数项内部,运算在汇编时完成

3.3 汇编语言程序设计基础

理论不多说了,还是要编

  • 顺序结构程序设计

  • 分支结构程序设计

    注意跳过不该执行的分支

    • eg. 显示 2 位压缩 BCD 码的值(0-99),不输出前导 0,并设待显示字节数据已用 DB 伪指令存至变量 BCD 中

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      	  ; 核心部分
      mov dl, bcd
      test dl, 0F0H ; 按位与看看是一位数还是两位数
      jz one
      two: mov cl, 4
      shr dl, cl ; 把BCD码的十位移到ASCII的低4位
      add dl, 30h
      mov ah, 02h
      int 21h
      mov dl, bcd
      and dl, 0fh
      add dl, 30h
      one: mov ah, 02h
      int 21h
    • 多分支结构
      跳跃表法
      eg. 根据 BX 的低四位哪一位为 1(由低到高)在屏幕上显示 1、2、4、8

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
              .model small
      .data
      var equ ? ; 测试数据
      tab dw foo1, foo2, foo3, foo4 ; ***
      .code
      start: mov ax, @data
      mov ds, ax
      mov bx, var
      xor si, si
      find: shr bx, 1
      jnc no
      mov ah, 02h
      jmp tab[si]
      no: add si, 2
      jmp find
      foo1: mov dl,'1'
      jmp over
      foo2: mov dl,'2'
      jmp over
      foo3: mov dl,'4'
      jmp over
      foo4: mov dl,'8'
      jmp over
      over: int 21h
      mov ax,4c00h
      int 21h
      end start

      DW 标识符是将该标识符(标号、变量名、etc…)对应的段内偏移地址存入一个字单元,类似的,可用 DD 将某标识符的偏移地址和段地址存入两个相邻的字单元(双字,偏移地址放在低地址单元,段地址放在高地址单元

  • 循环结构

    • 计数控制

    • 条件控制(无条件转移指令、条件转移指令)

      eg. 输入若干学生姓名,直接按回车则结束,将其中最大者(按字典序)输出。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      		.model  small
      .data
      maxlen db 11h ;一个学生姓名的最大长度+1(回车)
      actlen db ? ;实际输入的字符个数
      nmbuf db 11h dup(0) ;namebuffer
      rslt db 'Result: ' ;
      longnm db 0dh, 0ah, '$' ;初始化,一开始肯定比'a'小就对了
      db 10h dup(0) ;最大的名字
      crlf db 0dh, 0ah, '$' ;回车换行
      .code
      start: mov ax, @data
      mov ds, ax
      mov es, ax
      cld
      next: lea si, nmbuf
      lea di, longnm
      lea dx, maxlen ;把最大可输入字符数存到缓冲区第一个字节单元
      mov ah, 0ah ;输入姓名
      int 21h

      lea dx, crlf ;输出回车换行
      dec ah ;09H号,输出字符串
      int 21h

      mov cl, actlen
      xor ch, ch
      jcxz otpt ;若CX=0则跳转,CX=0即只键入了一个回车,结束

      repe cmpsb ;比较nmbuf和longnm的大小 SI-DI
      jng next ;/js
      lea si, nmbuf ;更新当前的最大名字
      lea di, longnm
      mov cl, actlen
      rep movsb

      mov byte ptr [di], 0dh ;回车换行结束
      mov byte ptr [di+1], 0ah
      mov byte ptr [di+2], '$'

      jmp next
      otpt: mov dx, offset rslt ;因为rslf后面存的就是结果,结果里才有'$'所以一直输出到结束
      int 21h
      mov ax, 4c00h
      int 21h
      end start
      • 双重循环

        eg. 改进的冒泡排序

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
                ;改进的冒泡排序,递增
        .model small
        .data
        COUNT EQU 11
        FLAG DB 1
        .CODE
        START: MOV AX,@DATA
        MOV DS,AX
        MOV DI,3000H
        MOV CX,COUNT
        DEC CX ;外层循环次数
        OLP: MOV DX,CX ;暂存外层循环
        CMP FLAG,0 ;如果上一轮没有进行交换
        JE OVER ;提前结束[优化]
        MOV FLAG,0
        MOV DI,3000H

        ILP: MOV AL,[DI]
        CMP AL,[DI+1] ;ax-[DI+1]
        JB STEP ;小于则直接比较下一组
        XCHG AL,[DI+1] ;大于则交换
        MOV [DI],AL
        MOV FLAG,1 ;一轮中发生交换将FLAG置1
        STEP: INC DI
        LOOP ILP
        MOV CX,DX ;恢复CX继续计数
        LOOP OLP

        OVER: MOV AX,4C00H
        INT 21
        END START

  • 子程序结构

    格式:

    1
    2
    3
    过程名    PROC    [属性]
    … ;子程序主体部分
    过程名 ENDP

    属性为 NEAR/FAR

    eg. N 的阶乘

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
              	;N的阶乘
    STACK SEGMENT STACK
    DB 200 DUP(0)
    STACK ENDS
    DATA SEGMENT
    N DW 7
    RESULT DW ?
    DATA ENDS
    CODE SEGMENT
    ASSUME CS:CODE,SS:STACK,DS:DATA
    START: MOV AX,DATA
    MOV DS,AX
    MOV AX,N
    MOV DX,1
    CALL FACT
    MOV RESULT,DX
    MOV AX,4C00H
    INT 21H

    FACT PROC
    CMP AX,0
    JNE STEP ;没结束
    MOV DX,1
    RET

    STEP: PUSH AX
    DEC AX
    CALL FACT ;递归调用
    POP AX
    MUL DX
    MOV DX,AX
    RET
    FACT ENDP

    CODE ENDS
    END START
    • 子程序的参数传递——寄存器传参
      适用于参数较少的时候

    • 子程序的参数传递——地址表传参
      适用于参数较多的情况

      eg. 计算数组的累加和

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
              .model small
      .data
      ary dw 10 dup(?)
      cnt dw 10
      sum dw ?
      tbl dw 3 dup(?)
      .code
      main proc far
      begin: mov ax, @data
      mov ds, ax
      mov tbl, offset ary
      mov tbl+2, offset cnt
      mov tbl+4, offset sum
      mov bx, offset tbl
      call addtab
      mov ax, 4c00h
      int 21h
      main endp
      addtab proc near
      push ax
      push cx
      push si
      push di
      mov si, [bx] ;数组首地址
      mov di, [bx+2] ;数组元素个数
      mov cx, [di] ;数组元素个数送CX
      mov di, [bx+4] ;sum
      xor ax, ax ;ax存每次相加后的结果
      next: add ax, [si]
      add si, 2
      loop next
      mov [di], ax ;结果送sum
      pop di
      pop si
      pop cx
      pop ax
      ret
      addtab endp
      end begin
    • 子程序的参数传递——堆栈传参
      适用于子程序有嵌套、递归调用的情况,主程序将参数压栈,子程序将参数弹栈。使用堆栈传参要注意对栈的管理,最好可以画个图。

      eg. 数组累加

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
              .model small
      .data
      ary dw 10 dup(?)
      cnt dw 10
      sum dw ?
      .stack
      dw 100 dup(?)
      btm dw ? ;栈是向下生长的
      .code
      main proc far
      begin: mov ax, @data
      mov ds, ax
      mov sp, offset btm ;栈顶指针,当前指向栈底
      mov bx, offset ary ;数组首地址
      push bx
      mov bx, offset cnt ;数组元素个数
      push bx
      mov bx, offset sum ;数组元素和
      push bx
      call addstk
      mov ax, 4c00h
      int 21h
      main endp
      addstk proc near
      push bp
      mov bp, sp
      push ax
      push cx
      push si
      push di
      mov si, [bp+8] ;&ary
      mov di, [bp+6] ;&cnt
      mov cx, [di] ;数组元素个数
      mov di, [bp+4] ;&sum
      xor ax, ax
      next: add ax, [si]
      add si, 2
      loop next
      mov [di], ax
      pop di
      pop si
      pop cx
      pop ax
      pop bp
      ret 6 ;额外弹出3个字(丢弃不再需要的参数)
      addstk endp
      end begin

      BP 的专门用途正是堆栈传参,BP 寄存器默认与 SS 段寄存器配合

      递归式累加代码:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      ; 元素个数用堆栈传递,累加和用AX传递
      .model small
      .data
      ary dw 10 dup(2)
      cnt dw 10
      sum dw ?
      .stack
      dw 100 dup(?)
      btm dw ?
      .code
      main proc far
      begin: mov ax, @data
      mov ds, ax
      mov sp, offset btm ;栈顶指针,初始指向栈底
      push cnt
      mov bx, offset ary
      push bx
      xor ax, ax
      call addrec
      mov sum, ax
      mov ax, 4c00h
      int 21h
      main endp
      addrec proc near
      push bp
      mov bp, sp
      push bx
      mov bx, [bp+6] ;cnt
      test bx, bx ;cnt=0?
      jz back
      recur: dec bx
      push bx
      mov bx, [bp+4]
      add bx, 2
      push bx
      call addrec
      mov bx, [bp+4]
      add ax, [bx]
      back: pop bx
      pop bp
      ret 4
      end begin

      当 CNT=2 时堆栈的变化如下图:(借此了解一下栈帧)

    • 子程序参数传递——结构化参数

      格式:

      结构名 STRUC
      … …
      结构名 ENDS

      结构变量名 结构名 <预赋值说明(给出各字段的值,用逗号分隔,不填表示缺省)>

  • 宏定义

    • 格式:
      宏名 MACRO [形参列表]
      … ; 宏定义体
      ENDM

    • 宏名必须以字母开头,形参可缺省,也可有多个形参(逗号分隔)

    • 宏定义中出现标号时,必须用 LOCAL 伪指令将其声明为局部标号,否则多次宏调用将出现重复标号问题

      注意:LOCAL 伪指令只能用于宏定义体内部,必须是 MACRO 伪指令后的第一条语句,在 MARCO 和 LOCAL 之间不能有注释

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      ; 将ASCII码转化为真值
      ASCTOH MACRO
      LOCAL ASCTOH1, ASCTOH2
      CMP AL, ‘9’
      JBE ASCTOH1
      CMP AL, ‘a’
      JB ASCTOH2
      SUB AL, 20H
      ASCTOH2:
      SUB AL, 7
      ASCTOH1:
      SUB AL, 30H
      ENDM
  • 宏调用与宏展开

    • 宏调用

      格式:宏名 [实参列表]

      宏调用也称宏指令,对汇编语言源程序进行汇编时,汇编程序将对每一个宏调用作宏展开

    • 宏展开

      即以宏定义体替换宏名,并将宏定义提中出现的形参用与之位置相同的实参替换

    • 宏指令名可以与指令或伪指令的助记符相同,宏的优先级最高
      可以用 PURGE 伪指令取消宏定义以恢复指令的原始含义,如 PURGE ADD

      eg. 显示一个字符的宏定义

      1
      2
      3
      4
      5
      6
      7
      8
      9
      DISPCH  MACRO    CHAR
      MOV AH, 2
      MOV DL, CHAR
      INT 21H
      ENDM
      ; 宏调用
      DISPCH ‘Y’
      DISPCH BL
      DISPCH BYTE_VAR

      eg. 实参作为指令操作码助记符的一部分

      宏展开时,’&’ 前后的符号将合并

      1
      2
      3
      4
      5
      6
      7
      8
      9
      LEAP     MACRO    COND, LAB
      J&COND LAB
      ENDM
      ;宏调用
      LEAP Z, THERE
      LEAP NC, HERE
      ;宏展开
      JZ THERE
      JNC HERE
  • 重复汇编

    格式:

    1
    2
    3
    REPT    表达式
    ... ;重复块
    ENDM
  • 宏与子程序对比

    • 宏是文本替换,子程序是流程转移
    • 宏展开发生在程序执行之前的汇编阶段,程序执行时已经没有宏了;子程序则是在程序执行时才被执行
    • 宏的速度更快,函数的空间更小
    • 程序较短且要求执行较快时适合采用宏实现;程序段较长时适合采用子程序
  • 条件汇编

    汇编程序根据条件决定是否对某一段源代码进行汇编

    1
    2
    3
    4
    5
    IFXX    参数
    … ;参数满足条件则汇编此块
    [ELSE]
    … ;参数不满足条件则汇编此块
    ENDIF
    • IF 表达式:计算表达式的值,若结果不为零则满足条件

    • IFE 表达式:计算表达式的值,若结果为零则满足条件

    • IFDEF 符号:若符号已在程序中定义,或者已经用 EXTERN 伪指令声明为外部符号,则满足条件

    • IFNDEF 符号:若符号未在程序中定义且未用 EXTERN 伪指令声明为外部符号,则满足条件

    • IFB <自变量>:若自变量为空则满足条件

    • IFNB <自变量>:若自变量非空则满足条件

      eg. GOTO L, X, REL

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
          ;宏定义
      GOTO MACRO L, X, REL
      IFB <REL>
      JMP L
      ELSE
      MOV CX, X
      L: DEC CX
      ADD X, CX
      AND CX, CX
      J&REL L
      ENDIF
      ENDM
      ;宏调用

      SUM DW 100

      GOTO NEXT, SUM, NZ
      GOTO EXIT

      ;宏展开
      MOV CX, SUM
      NEXT: DEC CX
      ADD SUM, CX
      AND CX, CX
      JNZ NEXT
      JMP EXIT

练习

  1. 如何将 AX 寄存器清零

  2. 比较 REP 指令与 LOOP 指令:循环类型、影响标志位?

  3. MOV BX,OFFEST LISTLEA BX, LIST的区别?

    OFFSET 属于运算符,在汇编时完成,属于立即寻址
    LEA 则是在程序运行时执行,属于直接寻址

  4. 下面的代码完成了什么操作?如果直接执行mov ax, dvar会怎么样?

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    .MODEL SMALL
    .DATA
    dvar dd 12347777h, 87651111h, ?
    .CODE
    START: mov ax,@data
    mov ds,ax
    mov ax, word ptr dvar[0] ;ax=7777h
    mov dx, word ptr dvar[2] ;dx=1234h
    add ax, word ptr dvar[4] ;ax=8888h
    adc dx, word ptr dvar[6] ;dx=9999h
    mov word ptr dvar[8], ax ;dvar[8]=88h dvar[9]=88h
    mov word ptr dvar[10], dx ;dvar[10]=99h dvar[11]=99h
    mov ax, dvar ;ax=7777h(warning)
    OVER: MOV AX, 4C00H
    INT 21H
    END START

    小端存储,它是这样存的:

    高地址
    87H dvar[7]
    65H dvar[6]
    11H dvar[5]
    11H dvar[4]
    12H dvar[3]
    34H dvar[2]
    77H dvar[1]
    77H dvar[0] 低地址