本文将结合老师说的考试范围与PPT,对所涉及的知识点作个人总结,面向考试复习(高星,yyds

顺序有点乱,如果有时间会再调一下。

一、子程序与主程序

(一)什么是子程序

把功能相对独立的程序段单独编写和调试,作为一个相对独立的模块供程序使用,就形成子程序

子程序可以实现源程序的模块化,可简化源程序结构,可以提高编程效率

参数传递是子程序设计的重点和难点

子程序的调用和返回是由指令CALL和RET(return)来完成的

•CALL指令分成4种类型(类似JMP)

CALL label ;段内调用、相对寻址

CALL r16/m16 ;段内调用、间接寻址

CALL far ptr label ;段间调用、直接寻址

CALL far ptr mem ;段间调用、间接寻址

返回时,RET直接从当前栈顶取内容作为返回地址。因此要保证RET指令执行前堆栈栈顶的内容刚好是返回的地址。

例:子程序的常见格式(实现回车换行的子程序):

注意:

  1. 对简化段定义格式,在tiny和small下,过程(PROC)的默认属性为near;对完整段定义格式下,过程的默认属性为near。
  2. 进行过程设计时,需要注意寄存器的保护和恢复,即开始时将要修改的寄存器内容压入栈,结束后再逆序弹出

(二)如何进行参数传递

主程序在调用子程序时,通常需要提供一些数据,即入口参数(输入参数)

子程序执行结束后要返回主程序数据,即出口参数(输出参数)

参数的形式分为两种

① 数据本身(传值)②数据的地址(传址)

下面介绍如何传递参数

1.寄存器传递参数(共享寄存器)

把参数存于约定的寄存器中,可以传值,也可以传址。

上图的子程序将和存在了al中,返回后再将其mov到result中,实现了参数传递。

注:子程序对带有入口参数的寄存器可以保护,也可以不保护;上图未保护

​ 子程序对带有出口参数的寄存器不能保护和恢复

2.变量传递参数(共享变量)

主程序和子程序直接采用同一个变量名共享同一个变量。

类比于C++中的加引用,直接改变了变量的值

上图的子程序直接将al中的值mov到了result,随后返回到主程序。

3.堆栈传递参数(共享堆栈)

主程序将子程序的入口参数压入堆栈,子程序从堆栈中取出参数

子程序将出口参数压入堆栈,主程序弹出堆栈取得它们

前方高能

入口参数为数组的偏移地址和数组的元素个数,通过压入堆栈进行传递。

程序在保护bp后,将bp置为栈顶,并通过偏移位置来分别寻址获得压入的偏移地址和元素参数。最后按反序弹出栈内值和址。

上述程序堆栈的使用情况如下图

由于主程序压入了2个参数,使用了堆栈区的4字节,故采用上述办法平衡堆栈。

注:由于寄存器的保护也存于堆栈中,所以在子程序退出时要特别注意pop的顺序

二、缓冲区

(一)如何定义缓冲区

该例表示在内存中申请一个缓冲区为83个字节,首地址给BUF

缓冲区分为三个部分

第一个字节内放的是事先填入最多欲接收的字符个数(包括回车字符,可以是1~255),在例中为81,表示申请的存放数据的缓冲区的字节数为81个。

第二个字节 ‘ ?‘表示的是实际存放的字节个数(不包括回车)

就是说,你放入2个字节的数据,“?”变成2,放10个字节的数据,变成10);

DB表示的是分配一个或多个字节;

输入的数据(字符串)从第三个字节开始存放,存放至第82个字节,第81个字节存放回车符(0DH),0DH作为输入数据的结束

DUP(0)表示的是存放数据的81个字节初始值全为0,即为:81 0 0 0 0······(第82个字节)0 ODH。

注:实际输入的字符数多于定义数时,多出的字符丢掉,且响铃

(二)如何使用缓冲区

下例实现了字符串的输入

三、串操作指令

串操作指令的操作对象是以字(W)为单位的字串,或是以字节(B)为单位的字节串

串操作指令采用了特殊的寻址方式

  1. 源操作数用寄存器SI间接寻址,默认在数据段DS中,即DS:[DI]
  2. 目的操作数用寄存器DI间接寻址,默认在附加段ES中,即ES:[SI]
  3. 每执行一次串操作,SI和DI将自动修改
  4. 源数据串可以段跨越,目的串不可。

注:由于要自动修改SI与DI,所以用户需要在进行串操作之前改变方向标志DF先确定增加或减小的方向

即:执行CLD(DF=0,主存地址增大,较为常用)或执行STD(DF=1,主存地址减小)

串操作经出配合重复前缀指令,通过计数器CX控制重复执行串操作指令的次数。

(一)串传送指令

①串传送 MOVSB/W(move string)

把字节从主存的源地址传送至目标地址

MOVSB 字节串传送:ES:[DI]←DS:[SI]

②串存储 STOSB/W(store string)

AL或AX数据传送至目标地址

STOSB 字节串存储:ES:[DI]←AL(AL传字节)

STOSW 字串存储: ES:[DI]←AX(AX传字)

③串读取 LODSB/W(load string)

把指定主存单元的数据传送给AL或AX

LODSB 字节串读取: AL←DS:[SI]

LODSW 字串读取: AX←DS:[SI]

④REP重复前缀指令

REP ;每执行一次串指令,CX减1直到CX=0,重复执行结束

即:当数据串没有结束(CX≠0),则继续传送

(二)串检测指令

①串比较指令CMPS(compare string)

将主存中的源操作数减去至目的操作数,以便设置标志,进而比较两操作数之间的关系

CMPSB 字节串比较:DS:[SI]-ES:[DI]

②串扫描SCAS(scan string)

AL/AX减去至目的操作数,以便设置标志,进而比较AL/AX与操作数之间的关系

SCASB 字节串扫描:AL-ES:[DI]

SCASW 字串扫描: AX-ES:[DI]

③REPZ/REPE重复前缀指令

每执行一次串指令,CX减1并判断ZF是否为0,

只要CX=0或ZF=0,重复执行结束。

即:当数据串没有结束(CX≠0),并且串相等(ZF=1),则继续比较

④REPNZ/REPNE重复前缀指令

每执行一次串指令,CX减1并判断ZF是否为0,

只要CX=0或ZF=0,重复执行结束。

即:当数据串没有结束(CX≠0),并且串不相等(ZF=0),则继续比较

REPNZ和LOOP的区别:

REPNZ是先执行一次指令,之后将CX减一,判断CX是否为0。

而LOOP是先将CX减一,然后判断CX是否为0,不为0则继续执行指令。

例:

在上例中,指令repz cmpsb结束有两种情况

第一种:ZF=0,即出现不相等的字符

第二种:CX=0,即比较完了所有字符

注意,在这种情况下,如果ZF=0,则说明最后一个字符不相等,ZF=1才能说明两个字符串相同

所以,重复比较结束后,需要通过jnz指令 来判断zf位,若其=0,则字符串不相等。

总流程图如下

下例为SCAS在字符串中查找空格字符的用法

四、常用DOS命令

调用DOS功能一般方法如下:

1、在AH寄存器中设置系统功能调用号,说明选择的功能

2、在指定寄存器中设置入口参数。

3、用中断调用指令 INT 21H 执行功能调用。

(一)字符输出(02H号)

入口参数:DL=字符的ASCII码

注:该功能可以识别响铃字符(07H),回车(0DH),换行(0AH)。

(二)字符串输出(09H号)

入口参数:DS:DX=欲显示字符串在主存中的首地址。

注:顺序为先回车(0DH),再换行(0AH),且字符串应以’$’(24H)结束。

(三)字符输入(01H号)

出口参数:AL=字符的ASCII码

调用此功能时,若无键按下,则会一直等待,直到按键后才读取该键值

(四)字符串输入(0AH号)

入口参数:DS:DX=缓冲区首地址

关键要定义好缓冲区

五、8086的机器代码格式

机器码我都不怎么懂,直接搬PPT了= =

例1:

MOV AX,BX ;机器代码是 89 D8(16进制)

第1个字节89是操作码(含w=1表示16位操作)

第2个字节D8(11 011 000)是 “mod reg r/m

reg=011表示目的操作数为BX

mod=11时,为寄存器寻址方式

mod=11和r/m=000表示源操作数为AX

例2:

MOV AL,[BX+SI+6] ;机器代码是 8A 40(16进制) 06

前一个字节8A是操作码(含w=0表示8位操作)

中间一个字节40(01 000 000)(将16进制转为2进制,然后按2 3 3拆开)是 “mod reg r/m”字节

reg=000表示目的操作数为AL

mod=01时,为带有8位位移量的存储器寻址方式

mod=01和r/m=000表示源操作数为[BX+SI+D8]

最后一个字节就是8位位移量[D8]=06

六、常用的ASCII码

回车:0DH 换行:0AH 响铃:07H

空格:20H

数字0~9:30H~39H

大写字母A~Z:41H~5AH

小写字母a~z:61H~7AH

七、BCD码

Binary Coded Decimal(二进制编码的十进制数),即一个十进制数位(0-9)在计算机中用4位二进制编码表示。常用的BCD码是8421BCD码,即用4位二进制编码的低19个编码表示0-9这十个数字,如图。

例:0100 1001 0111 1000.0001 0100 1001 十进制真值:4978.149(上图对应)

00111010B=3AH F2H=11110010B

10H=00010000B=16D ABH=10101011B=171D

压缩BCD码:一个字节表达两位BCD码 10000111B(87H)

非压缩BCD码:一个字节表达一位BCD码低4位表达数值,高4位常设置为0

00001000 00000111B(0807H)

八、变量的定义

(一)符号常数

利用一个标识符表达的一个数值

例:

注:在5.x版本中,字符串是用引号括起来的

例:calldos equ "int 21h"

EQU用于数值等价时不能重复定义符号名,但”=“允许有重复赋值

X=7 X EQU 7 都是正确的

X=X+5 但 X EQU X+5是错误的

(二)变量定义伪指令

变量定义(Define)伪指令为变量申请固定长度的存储空间,并可同时将相应的存储单元初始化

其汇编格式为:变量名 伪指令 初值表

变量名:

  1. 变量名为用户自定义标识符,表示初值表首元素的逻辑地址;用这个符号表示地址,常称为符号地址
  2. 变量名可以没有,此时无符号地址。

初值表:

  1. 初值表是用逗号分隔的参数

  2. 主要由数值常数、表达式或?、DUP组成

    ?——表示初值不确定,即未赋初值

    DUP——表示重复初值

    DUP的格式为:重复次数 DUP(重复参数)

(三)定义实例

1.字节单元定义实例

DB伪指令用于分配一个或多个字节单元。初值表中每个数据一定是字节量(Byte),存放8位数据。

2.字单元定义实例

DW伪指令用于分配一个或多个字单元。初值表中每个数据一定是字量(Word),存放16位数据。

3.字变量和字常量的应用(重要)

即:字变量在程序中当作mem,即取其偏移地址元素的数值。

结语

只花了一天的时间去复习整理汇编语言,希望别挂科就好

后面看到这篇的人一定要好好学汇编啊。

张海英你没有心(确信)