汇编语言(以8086为例)

汇编语言(以8086为例)

【通俗易懂的汇编语言(王爽老师的书)】

01-序言

P3 由机器指令到汇编指令

机器语言: 是机器指令的集合。

机器指令: 是一台机器可以正确执行的命令。机器指令由一串二进制数表示,例如01010000。

由于机器指令的可读性极差,所以有了汇编语言与汇编指令。

‍

汇编语言: 的主体是汇编指令。

汇编指令和机器指令表达的意思是相同的,他们的差别在于指令的表示方法上:汇编指令是机器指令便于记忆的书写形式;汇编指令是机器指令的助记符。

  • 机器指令:1000100111011000
  • 汇编指令:MOV AX BX
  • 操作:将寄存器BX的内容送到AX中

‍

工作过程: 汇编语言-> 编译器-> 机器码-> 计算机执行

‍

汇编语言程序包含:

  • 汇编指令——机器码的助记符
  • 伪指令——由编译器执行
  • 其他符号——由编译器识别

‍

P4 计算机的组成

​image​

CPU想要工作,就必须向它提供指令和数据。而指令和数据在存储器(内存)中存放。

‍

指令和数据的表示: 数据和指令存储在内存或磁盘上;数据和指令都是二进制信息。

‍

存储单元: 存储器被划分为若干个存储单元,每个存储单元从0开始顺序编号;实际的内存空间很“大”。例如8086有20条数据线,寻址空间为1MB。

​

总线: 从物理上将,总线是一根根导线的集合;逻辑上则将总线分为地址总线、数据总线、控制总线三种总线。

CPU通过地址总线来指定存储单元,地址总线的宽度决定了可寻址的存储单元的大小,N根地址总线对应2N的寻址空间。

CPU与内存或其他器件之间的数据传输是通过数据总线来进行的,数据总线的宽度决定了CPU和外界的数据传送的速度。

CPU通过控制总线对外部器件进行控制,控制总线是一些不同控制线的集合,控制总线的宽度决定了CPU对外部器件的控制能力。

​image​image​image​​​

‍

P5 内存的读写和地址空间

CPU想要进行数据的读写,必须和外部器件进行三类信息的交互:

  • 存储单元的地址(地址信息)
  • 器件的选择,读/写命令(控制信息)
  • 读或写的数据(数据信息)

‍

内存地址空间: 可用于存储数据和指令的内存地址的范围。由地址总线决定。

从CPU看地址空间:

  • 将各类存储器看作一个逻辑存储器——统一编址
    每个物理存储器在这个逻辑存储器中占有一个地址段,即一段地址空间(下图左侧为8086)
    ​image​
  • 独立编址

‍

P6 语言实践环境搭建

本课以8086CPU为例进行讲解。

因此实践方案为——DOS环境。具体软件为DOSBox

‍

02-访问寄存器和内存

P7 本章导言

​​image​​

‍

P8 寄存器及数据存储

寄存器: 是CPU内部的信息存储单元

8086CPU有14个寄存器: 8086CPU所有的寄存器都是16位的,可以存放两个字节,存放的最大值为 216-1

  • 通用寄存器:AX、BX、CX、DX
  • 变址寄存器:SI、DI
  • 指针寄存器:SP、BP
  • 指令指针寄存器:IP
  • 段寄存器:CS、SS、DS、ES
  • 标志寄存器:PSW

​​image​​

‍

但是有个问题,8086上一代CPU中的寄存器都是8位的,如何保证程序的兼容性?

解决方案: 将通用寄存器均分为两个独立的8位寄存器使用。例如,AX可以分为AH(high)和AL(low)。

‍

8086是16位CPU,所以8086的字长(word size) 为16bit

一个字(word) 可以存放在一个16位寄存器中,这个字的高位字节存放在这个寄存器的高8位寄存器,这个字的低位字节存放在这个寄存器的低8位寄存器。

​image​

‍

P9 mov和add指令

在用中学

​​image​​

懂了吧!那么直接开始做题

例01:注意溢出哦,溢出直接舍掉

​image​

例02:注意溢出哦,溢出直接舍掉,不能进到AH中

​image​

‍

P10 确定物理地址的方法

CPU访问内存单元时要给出内存单元的地址。

所有的内存单元构成的存储空间是一个一维的线性空间,每个内存单元在这个空间中都有唯一的地址,这个唯一的地址称为物理地址。

‍

8086有20位地址总线,可传送20位地址,寻址能力为1M。

8086是16位结构的CPU,运算器一次最多可以处理16位的数据,寄存器的最大宽度为16位。

那么在8086内部处理、传输、暂存的地址也是16位,寻址能力也只有16位。可是它有20位地址总线,剩下的难道浪费了吗?

8086给出了一个解决方案:用两个16位地址(段地址、偏移地址)合成一个20位的物理地址。

地址加法器合成物理地址的方法:物理地址 = 段地址*16+偏移地址

对于一个物理地址,可以通过不同的段地址和偏移地址获得。

​image​​​

‍

P11 内存的分段表示法

已知8086CPU用“物理地址 = 段地址*16+偏移地址”的方式给出内存单元的物理地址。

段地址,就是分段的方式管理内存。但是要注意,内存本身并没有分段,段的划分来自于CPU。

‍

根据合成物理地址的方法,可以得出两个结论:

  1. 因为物理地址 = 段地址*16+偏移地址,段地址被*16了,所以一个段的起始地址一定是16的倍数(即最后一位一定为0,12340H这样)
  2. 偏移地址为16位,16位地址的寻址能力为64K,所以一个段的最大长度为64K

‍

8086中存储单元地址的表示方法:

例如,数据在21F60H内存单元中,段地址是2000H,那么有两种表示方法:

  1. 数据存在内存 2000:1F60 单元中
  2. 数据存在内存的 2000H 段中的 1F60H 单元中

‍

物理地址 = 段地址*16+偏移地址,那段地址和偏移地址分别怎么来呢?

段地址很重要!所以8086提供了4个段寄存器,专门用于存放段地址:

  • CS——代码段寄存器
  • DS——数据段寄存器
  • SS——栈段寄存器
  • ES——附加段寄存器

而偏移地址可以用多种方法提供——8086有丰富的取址方式

‍

P12 Debug的使用

Debug是DOS系统中著名的调试程序,也可以运行在windows系统上

使用Debug程序,可以查看CPU各种寄存器中的内容、内存的情况,并且在机器指令级跟踪程序的运行

‍

具体操作:

打开DOSBox,先进行挂载,选中工作目录

mount c d:\0105\MASM	//将Dos里的c盘,绑定到本机上d:\0105\MASM这个目录
c:	//切换到c盘
dir	//ls,确定一下挂载是否成功

debug的使用

debug	//启动程序,看到'-',说明启动成功

查看寄存器:R命令

r	//查看寄存器内容
r [寄存器名]	//改变指定寄存器内容,输入在冒号时输入改变值
r[寄存器名]	//不加空格也可以

​​TZ0PPIWOE3I5I65E478​​

‍

查看内存中的内容:D命令

d	//列出预设地址内存处,128个字节的内容
d [段地址:偏移地址]	//列出内存中指定地址处,128个字节的内容dd 
d [段地址:偏移地址] [结尾偏移地址]	//列出内存中指定地址处,指定范围的内容

​image​

​X691J50H73TGUNBE​

‍

改变内存中的内容:E命令

e [段地址:偏移地址] [数据1] [数据2]		//默认是16进制,不需要加'H'
e [段地址:偏移地址]	//逐个询问式修改。空格=接受,继续。回车=结束

​HSO3JP1D21XVM90​

​7LCCEB8XT3E4AV@9NYW​

‍

将机器指令翻译成汇编指令:U命令

u [段地址:偏移地址]

​ZGK@96Z0A1I7Y1DQEWZH​

‍

以汇编指令的格式在内存中写入机器指令:A命令

a [段地址:偏移地址]	//逐个询问式。空白内容时回车即可退出。

​image​

​A8CTL958FED_L575HWTX​

‍

执行机器指令:T命令

t	//执行 CS:IP 处的指令

​12XHWIAUNQFUB79LQC4UG​

‍

退出debug:Q命令

q	//quit

​8ONYRESZAZSRECNHKC02​

‍

P13 CS、IP与代码段

CS: 代码段寄存器

IP: 指令指针寄存器

CS:IP: CPU将内存中 CS:IP 指向的内容当做指令执行

‍

8086工作过程简要描述:

  1. 从CS:IP指向的内存单元读取指令,读取的指令进入指令缓冲器;
  2. IP = IP+所读取指令的长度,从而指向下一条指令;
  3. 执行指令。转到步骤(1),重复这个过程

‍

P14 jmp指令

当我们需要修改下一条将要执行的指令时,本质上是需要修改CS、IP的值

那么该如何改变CS、IP的值呢?

使用debug直接修改——不靠谱;

用mov指令修改CS、IP寄存器——有些操作时不合法的​

7337CCVMKKR3ZWFKTC17​

所以答案是,jmp指令: 修改CS、IP的指令

使用方法:

  • 同时修改CS、IP的内容
    ​jmp [段地址:偏移地址]​。例如:jmp 2000:3​
    功能:用指令中给出的段地址修改CS,偏移地址修改IP
  • 仅修改IP的内容
    ​jmp [某一合法寄存器]​。例如:jmp ax​
    功能:类似于mov IP,ax​

‍

jmp指令实践:

​P@QKW7JPO@JPZDESNPX​​KN@F8RMG@38EP6A79​​​​​

‍

P15 内存中字的存储

对于8086CPU,16位作为一个字。

16位的字存储在一个16位的寄存器中,高8位放高字节,低8位放低字节。

16位的字在内存中需要2个连续字节存储,低位字节存放在低地址单元,高位字节存放在高地址单元。

例如,存放4E20H 和 0012H

​​HWXE_@SXR7PKKWZLX​​

‍

字单元: 由两个地址连续的内存单元组成,存放一个字型数据(16位)

原理: 8086一个字是16位,需要内存中两个连续的字节来存储。

‍

P16 用DS和[address]实现字的传送

CPU要读取一个内存单元的时候,必须先给出这个内存单元的地址。而内存地址由段地址和偏移地址组成。怎样同时给出两个地址呢?

解决方案:DS和[address]配合

  • 用DS寄存器存放要访问的数据的段地址
  • 偏移地址用[...]的形式直接给出
  • 注意:不能直接给DS赋值,只能通过通用寄存器给DS赋值
  • 注意区分是,读写一个字还是一个字型

​77I6G1GTVG6DEOMZW​

​image​

‍

P17 DS与数据段

要求:实现对内存单元中数据的访问

处理方法:(DS):([address])​。用DS存放数据段的段地址;用相关指令访问数据段中的具体单元,单元地址由[address]指出

将123B0H~123BAH的内存单元定义为数据段:

​FTIFHTWWK8@G6@G3I​

练习:

​RKMIT5SQROBW@NHC2​

‍

总结(不一定完全)

用mov指令操作数据:

指令形式 示例
mov 寄存器, 数据 mov ax,8
mov 寄存器, 寄存器 mov ax,bx
mov 寄存器, 内存单元 mov ax,[0]
mov 内存单元, 寄存器 mov [0],ax
mov 段寄存器, 寄存器 mov ds,ax
mov 寄存器, 段寄存器 mov ax,ds
mov 内存单元, 段寄存器 mov [0],ds
mov 段寄存器, 内存单元 mov ds,[0]

add和sub指令:

指令形式 示例
add 寄存器, 数据 add ax,8
add 寄存器, 寄存器 add ax,bx
add 寄存器, 内存单元 add ax,[0]
add 内存单元, 寄存器 add [0],ax

‍

用DS和[address]形式访问内存中数据段方法小结:

  • 字在内存中存储时,要用两个地址连续的内存单元来存放。字的低位字节存放在低地址单元中,高位字节存放在高地址单元中
  • 用mov指令访问内存单元时,可以在mov指令中只给出单元的偏移地址,此时段地址默认在DS寄存器中
  • [address]表示一个偏移地址位address的内存单元
  • 在内存和寄存器之间传送字型数据时,高地址单元和高8位寄存器对应,低地址单元和低8位寄存器对应
  • mov 、add 、sub是具有两个操作对象的指令,访问内存中的数据段。
    jmp是具有一个操作对象的指令,对应内存中的代码段

‍

P18 栈及栈操作的实现

栈:先进后出。每次操作最顶上的元素。

栈有两个基本的操作:入栈和出栈

‍

现在的CPU都有栈的设计,例如8086就提供相关的指令,支持用栈的方式访问内存空间。

主要有两个指令:

  • push:入栈。push ax​,将ax的数据送入栈中
  • pop:出栈。pop ax​,从栈顶取出数据送入ax

push ax:

  1. SP = SP-2
  2. 将ax中的内容送入SS:SP指向的内存单元处,SS:SP此时指向新栈顶

pop ax:

  1. 将SS:SP指向的内存单元处的数据送入ax中
  2. SP = SP+2,SS:SP指向当前栈顶下面的单元,以当前栈顶下面的单元为新的栈顶。

push、pop实质上就是一种内存传送指令,可以在寄存器和内存之间传送数据。与mov指令不同的是,Push和pop指令访问的内存单元的地址不是在指令中给出的,而是由SS:SP指出。

‍

提问:

  1. CPU如何知道一段内存空间被当作栈使用?
  2. 执行push和pop的时候,如何知道哪个单元是栈顶单元?

回答:

在8086CPU中,由两个与栈相关的寄存器——SS和SP

栈段寄存器SS——存放栈顶的段地址,栈顶指针寄存器SP——存放栈顶的偏移地址

任何时刻,​**SS:SP**​指向栈顶元素。

注意,栈空间是从高地址向低地址增加的。

​J6PC1R95BOSTCTZPWF8​

‍

如何避免栈顶超界问题?

8086CPU并不能保证栈不会超界。

‍

P19 关于“段”的总结

‍

物理地址 = 段地址*16+偏移地址

  • 编程时,可以根据需要,将一组内存单元定义为一个段
  • 起始地址为16的倍数,长度小于等于64K的一组地址连续的内存单元,定义为一个段
  • 将一段内存定义为一个段,用一个段地址指示段,用偏移地址访问段内单元——在程序中可以完全由程序员安排。

‍

目前为止已经学习了三种段:

  • 数据段
    将段地址放在DS中
    用mov、add、sub等访问内存单元的指令时,CPU将我们定义的数据段中的内容当作数据段来访问
  • 代码段
    将段地址放在CS中,将段中第一条指令的偏移地址放在IP中。CS:IP指向即将执行的指令
    CPU将执行我们定义的代码段中的指令
  • 栈段
    将段地址放在SS中,将栈顶单元的偏移地址放在SP中。SS:SP指向栈顶
    CPU在需要进行栈操作(push、pop)时,将我们定义的栈段当作栈空间来使用。

‍

03-汇编语言程序

P20 本章导学

​A57OR602USYNANCMVBU​

‍

P21 用汇编语言写的源程序

汇编程序结构

汇编程序: 包含汇编指令和伪指令的文本。

汇编程序的注释是;​,默认为10进制

汇编程序->编译器->机器码

汇编程序可以是:

  • 在Debug中直接写入指令编写的汇编程序
    适用于功能简单、短小精悍的程序
    只需要包含汇编指令即可
  • 单独编写成源文件后再编译为可执行文件的程序
    适用于编写大程序
    不只有汇编指令,还有指导编译器工作的伪指令
    源程序由一些段构成,这些段存放代码、数据,或将某个段当作栈空间

​Y3DIS5R363N_29GQNW9MC

‍

伪指令

​YUNDWIYLSWNMOH174ZG​​

程序中的三种伪指令:

  • 段定义
    一个汇编程序是由多个段组成的,这些段被用来存放代码、数据或者当作栈空间来使用
    一个有意义的汇编程序中至少要有一个段,这个段用来存放代码
    定义程序中的段:每个段都需要有段名
    格式:段名 segment​——段的开始;段名 ends​——段的结束
  • end(不是ends)
    汇编程序的结束标记。若程序结尾处不加end,编译器在编译程序时,不知道程序在何处结束。
  • assume(假设)
    含义是,假设某一段段寄存器和程序中的某个用segment...ends​定义的段相关联。
    格式:assume 寄存器:段名​
    例如,assume cs:codesg​指cs寄存器与codesg这个段关联,将定义的codesg当作程序的代码段来使用

‍

如何写出一个程序来

  1. 定义一个段
  2. 实现处理任务
  3. 指出程序在何处结束
  4. 段与段寄存器关联
  5. 加上程序返回的代码

以实现2*3的程序为例:

​_ZY_HVERU6BMAI​

‍

程序中可能的错误

  • 语法错误
    程序在编译时被编译器发现的错误,容易被发现
  • 逻辑错误
    在运行时发生的错误,不容易被发现

‍

P22 由源程序到程序运行

由源程序到程序运行的过程

编写 -> 源程序文件.asm​ -> 编译 -> 目标文件.obj​ -> 连接 ->可执行文件.exe​

‍

编译

软件/指令:masm​

​2BQXQ7BRYC4OWFC1KOF

image​

​​PK2Q9WH35EF2U@6IM​​

‍

连接

软件/指令:link​

​LN4K1145F4LIV097L1​

​image​

​image​

‍

P23 用debug跟踪程序的执行

用debug装载程序:debug file.exe​​

有256(100H)字节的程序段前缀(PSP),作为数据区

​​image​​

用p命令/g命令执行:

​image​

‍

​image​

‍

p24 [...]​和(...)​​

​image​

  • ​[...]​:表示一个内存单元。是汇编语法规定的表示形式
  • ​(...)​:表示一个内存单元(只能用物理地址)或寄存器中的内容。是为学习方便大家约定的内容。

​image​

‍

​G@C0@M74LHNVA2KJ2OIW4​

‍

p25 Loop指令

功能:实现循环(计数型循环)

指令格式:​loop 标号​

CPU执行loop指令时的操作:

  1. (cx) = (cx) -1
  2. 判断cx中的值,不为零则转至标号处执行程序;如果为零则向下执行。

注意:cx中要提前存放循环次数,循环多少次则cx设置为多少;并且需要定义一个标号。

​​image​​

​S5E7M82VHGOE267C7MP9L​

用loop指令编程实例:

​R44CR_YWUTJUJT59B8F​

​ZZA3G7X2YG551@2XP55​

‍

p26 Loop指令使用再例

​YGYU1FCANH@QKS7TLBAF

注意,一定要分析,累加之后,是否有可能超过dx的存储能力

‍

如果你在编写的时候遇到了这个问题:mov ax,[6]​被编译成了mov ax,6​

别急,看下一章

‍

p27 段前缀的使用

​RG2_MSMCQ97E753​

为了解决这个“异常”现象,对策是:在[idata]前面显式地写上段寄存器。

​ED22WYIJ9BUOQWCRF​

这些出现在访问内存单元的指令中,用于显式的指明内存单元的段地址的'ds、cs、ss、es',在汇编语言中被称为段前缀​。

‍

​3VIPJLNOAZ68333526​

‍

p28 在代码段中使用数据

​EG6KNMNRW7A9JFHJQV7

对策:

  • 在程序的段中存放数据,运行时由操作系统分配空间。
  • 段的类别:数据段、代码段、栈段
  • 各类段中均可由数据
  • 可以在单个的段中安置,也可以将数据、代码、栈放入不同的段中

‍

​XI9NBDBRQJK2KXE6UH5​

  • dw(define word):定义一个字
  • db:定义一个字节
  • dd:定义一个双字

‍

​6KF86EMQT5VSWIQ7​

直接在代码段中添加数据的程序有问题,因为CPU并不知道代码段是从cs:0010​开始的,还将IP设置为0000。

所以怎么让代码从cs:0010​开始呢?

用​标号​标记程序的开始

​QBT5L0QDCGJB@8NW6M9FM​

‍

p29 在代码段中使用栈

​CVP2K@5FCQ1906AMU1F5L​

​K7V77OHRIQZ_QY7LD​

‍

p30 将数据、代码、栈放入不同段

将数据、栈、代码放在一个段的缺点:

  • 程序显得混乱,编程和阅读时都要注意何处是数据、何处是栈、何处是代码;
  • 只能应用于要处理的数据很少的,栈空间也小,代码也少的情况。

解决方法:将数据、代码、栈放入不同段

注意代码段仍然需要标号标记

注意:DS是程序开始的位置,但是后面紧跟着100H的PSP,所以DS:100H​才是数据开始的地方。

​9WFPJMQ7@ULP99N8R1S_D​

‍

04-内存寻址方式

P31 本章导学

​HA5HIO3NRYCAP0A43​

P32 处理字符问题

汇编程序中,用'abc'​的方式指明数据是以字符形式给出的。编译器将它们转化成相对应的ASCII码。ascii码是一字节大小的数据。

​OEK0NOT4KS4RR4QOXM6

可根据这个,做大小写转换:

  • 小写转大写:and 1101 1111
  • 大写转小写:or 0010 0000

​9RX3WDXODAQA15LV​

‍

P33 [bx+idata]方式寻址

​[bx+idata]​表示一个内存单元,它的偏移地址为(bx)+idata,即bx中的数据加上idata

​mov ax,[bx+idata]/mov ax,[idata+bx]​的含义:(ax) = ((ds)*16+200+(bx))​。

​mov ax,[bx+idata]​的其他常见写法:mov ax,200[bx]/mov ax,[bx].200​

应用: 做数组处理。可将(ds)*16+idata​看作基址,将bx看做偏移量。

‍

P34 SI和DI寄存器

SI和DI是8086CPU中和BX功能相近的寄存器。

SI: source index,源变址寄存器。

DI: destination index,目标变址寄存器。

区别: SI和DI不能分成两个8位寄存器来用。

应用问题: 用寄存器SI和DI实现将字符串'welcome to masm!'复制到它后面的数据区中。

解决方法: 用DS:SI​指向要复制的原始字符串,用DS:DI​指向目的空间。用一个循环来完成复制

‍

P35 [bx+si]和[bx+di]方式寻址

[bx+si]:表示一个内存单元,偏移地址为(BX)+(SI)​。将BX称作基址,SI称作变址。 基址变址寻址。

‍

P36 [bx+si+idata]和[bx+di+idata]方式寻址

[bx+si+idata]:表示一个内存单元,偏移地址为(BX)+(SI)+Idata​。

其他不同的写法:mov ax,[bx+200+si] / mov ax,[200+bx+si] / mov ax,200[bx][si] / mov ax,[bx].200[si] / mov ax,[bx][si].200​

‍

P37 不同寻址方式的灵活应用

对内存的寻址方式

形式 名称 特点 意义 示例
[idata] 直接寻址 用一个常量/立即数来表示地址 用于直接定位一个内存单元 mov ax,[200]
[bx] 寄存器间接寻址 用一个变量来表示内存地址 用于间接定位一个内存单元 mov bx,0
mov ax,[bx]
[bx+idata] 寄存器相对寻址 用一个变量和一个常量表示地址 可在一个起始地址的基础上,用变量间接定位内存单元 mov bx,4
mov ax[bx+200]
[bx+si] 基址变址寻址 用两个变量表示地址 mov ax,[bx+si]
[bx+si+idata] 相对基址变址寻址 用两个变量和一个常量表示地址 mov ax,[bx+si+200]

‍

案例1:将datasg段中每个单词的头一个字母改为大写字母

​TOJDAF7V1KA9JOZCR​

​V414M54N85I11OW8R55​

案例2:将datasg段中每个单词都改为大写字母

如何解决需要进行双重循环,但只有一个cx的冲突:

法一: 用dx暂存cx

缺陷: CPU中寄存器有限,这样的话dx就会被占用,太浪费

​_PIPP7A5IRRIS33W34​

​法二: ​用固定空间保存数据

缺陷: 在运行过程中,该数据有被覆盖的风险

​Y1F583C20L4ERQDJ3​

法三: 用栈保存数据

​AGT7_HT1J6IHK2YE91EE​

‍

P38 不同寻址方式演示

​UP3ES0WN_UQ2FWFE​

‍

P39 用于内存寻址的寄存器

只有​**bx、bp、si、di**​可以用在​ **[...]**​内对内存单元进行寻址

bx以外的通用寄存器、段寄存器不可以用在[...]内

**bx、bp、si、di**​的搭配:

​DN3GKTC@_T6USXC9J

bx、bp的区别: bx默认ds段;bp默认ss段

‍

P40 在哪里?有多长?

​M8@0REA9RRASEJ0D1

​ERR892_ZEIIL6BHJT2I​​

‍

P41 寻址方式的综合应用

要求: 编程修改内存中的过时数据。

​C85T4C6F387CR​

‍

P42 用div指令实现触发

​YV4GKKZZ3@L35U5R_UL7​

切记,提前在默认的寄存器中设置好被除数,且默认寄存器不作别的用处。

‍

P43 用dup设置内存空间

功能:dup和db、dw、dd等数据定义伪指令配合使用,用于进行数据重复。

​IV7RYXO57EBOLVL4W6I​

使用格式:db [重复次数] dup ('重复的内容')​

‍

05-流程转移与子程序

P44 本章导学

​ZAJHTY3KUPI8OM8EH​

P45 ”转移“综述

需求: 在时间过程中,长需要改变程序执行的流程

转移指令:

  • 可以控制CPU执行内存中某处代码的指令
  • 可以修改IP,或同时修改CS和IP的指令

转移指令的分类:

  • 按转移行为
    段内转移:只修改IP,如jmp ax​
    段间转移:同时修改CS和IP,如jmp 1000:0​
  • 根据指令对IP修改的范围不同
    段内短转移:IP修改范围为-128~127​,用一个字节来表示
    段内近转移:IP修改范围为-32768~32767​,用一个字来表示
  • 按转移指令
    无条件转义指令:jmp
    条件转移指令:jcxz
    循环指令:loop
    过程
    终端

P46 操作符offset

格式:​offset 标号​。如offset start​

用法: 通过offset​获取标号所在指令的偏移地址

​@U9GJ2H2BG2QETBIDO​

P47 jmp指令

jmp指令的功能:无条件转移,可以只修改IP,也可以同时修改CS和IP

jmp指令的用法:jmp short 标号​

​image​

注意:jmp short​的机器指令中,包含的是跳转目标指令和IP的相对位置,而不是目标地址

‍

两种段内转移:

  • ​jmp short 标号​:
    功能:(IP)=(IP)+8位位移
    核心:8位位移 = "标号"的地址-jmp指令后的第一个字节的地址;8位位移由编译程序在编译时算出
  • ​jmp near ptr 标号​:
    功能:(IP)=(IP)+16位位移
    核心:8位位移 = "标号"的地址-jmp指令后的第一个字节的地址;8位位移由编译程序在编译时算出

​image​

‍

远转移:​jmp far ptr 标号​直接指明了跳转到的目的地址,即包含了标号的段地址CS和偏移地址IP

​image​

‍

转移地址在寄存器中的jmp:​jmp 16位寄存器​

功能:IP = (16位寄存器)

例如:jmp ax​

‍

转移地址在内存中的jmp指令

注意:段地址在高位,偏移地址在低位;段地址和偏移地址各用一个字保存

​image

‍

​image​

‍

P48 其他转移指令

jcxz指令

格式:​jcxz 标号​

功能: 如果(cx)=0,则跳转到标号处执行;当(cx)≠0时,程序向下执行

​image​

‍

loop指令

​image​

‍

​image​

‍

P49 call 指令和 ret 指令

​call 标号​:调用子程序

​ret​:从子程序返回

实质: 都是流程转移指令,它们都修改IP,或同时修改CS和IP

‍

call指令

call指令进行的两步操作:

  1. 将当前的 IP 或 CS和IP 压入栈中;
    相当于:push IP​
  2. 转移到标号处执行指令
    相当于:jmp near ptr 标号​

​image​

​image​

​image​

​image

ret指令

​image​

‍

P50 call 和 ret 的配合使用

​image​

​image​

‍

P51 mul指令

​image​

‍

P52 汇编语言的模块化程序设计

​image​

​image​

​image​

​image​

‍

P53 寄存器冲突的问题

​image​

​image​

实际上就是计组里讲的,“保护现场“

​image​

P54 标志寄存器

​​

​9)JJM`@Y~A72)%_H%SRFK_1​

​image​

​image​

​image​

​image​

​image​

‍

P55 带进(错)位的加减法

adc

格式:​adc 操作对象1,操作对象2​

功能: 操作对象1 = 操作对象1+操作对象2+CF

adc是带进位加法指令,利用了CF位上记录的进位值

​image​

‍

​image​

两个讨论的回答:

  • 不可以。sub ax,ax​是为了将CF置为零
  • 不可以。inc di​是不会产生进位的;但add di,2​是有可能产生进位标记的

sbb

格式:​sbb 操作对象1,操作对象2​

功能: 操作对象1 = 操作对象1-操作对象2-CF

sbb是带借位减法指令,利用了CF位上记录的借位值

​image​

‍

P56 cmp和条件转移指令

cmp

格式:​cmp 操作对象1,操作对象2​

功能: 操作对象1-操作对象2

注意: cmp是比较指令,功能相当于减法指令,只是不保存结果,只影响标志寄存器

应用: 用标志寄存器的值来确定比较结果

​image​

​image​

​image​

条件转移指令

​image​

​image​

‍

P57 条件转移指令应用

​image​

‍

P58 DF标志和串传送指令

串传送指令

​image​

‍

rep指令

​image​

‍

**rep+movsb/movsw**​能高效地成片传送数据

‍

06-中断及外部设备操作

P59 阶段导学

​6HIN8B@E9{KC6@1SYZ@8{52​

P60 移位指令

​​

  • 逻辑左移(SHL):
    将最高位(最左边的)移入CF中,其他位向左移一位,末尾补零
    相当于,X=X*2
  • 循环左移(ROL):
    将最高位(最左边的)移入CF中,其他位向左移一位,末尾最高位
  • 逻辑右移(SHR):
    将最低位(最右边的)移入CF中,其他位向右移一位,首位补零
    相当于,X=X/2
  • 算术右移(SAR):
    将最低位(最右边的)移入CF中,其他位向右移一位,最高位不变
    最高位不变是为了保证“符号”不变。通常情况下,最高位是符号位

​image​

当移动位数大于1时,必须使用cl​表示移动位数。

‍

P61 操作显存数据

​image​

屏幕上的内容 = 显存中的数据。 所以想要操作屏幕上的内容,就要操作显存中的数据。

更具体的说,就是需要操作B8000h~BFFFFh​,即显示缓冲区中的数据。

​image​

每一个显示内容需要两个字节。 低位字节存储要显示符号的ASCII码,高位字节存储显示属性,即颜色。其中高位字节中内容的前四位,是存储的背景颜色;后四位是存储的前景颜色。

​image​

‍

P62 描述内存单元的标号

​image​

简化版offset。

当没有冒号的时候,被称为数据标号,数据标号能同时描述内存地址和单元长度(即db=字节,dw=字)

​image​

‍

​image​

数据标号描述的内存地址,是包括段地址的。

扩展用法:将标号当做数据来定义(用c语言来做通俗解释就是:指针的指针)

‍

P63 数据的直接定址表

​image​

​image image​

直接定址表

问题求解思路: 利用表,在两个数据集合之间建立一种映射关系,用查表的方法根据给出的数据得出其在另一集合中的对应数据。

优点:

  • 算法清晰和简洁
  • 加快运算速度
  • 使程序易于扩充
  • 空间换时间的方案

‍

​image​

​image​

‍

P64 代码的直接定址表(NO)

​image​

​image​

​image​

‍

P65 中断及其处理

​image​

​image​

​image​

低位保存IP,高位保存CS

​image​

​image​

‍

P66 编制中断处理程序

​image​

中断向量表:0000:0000~0000:03FF​

​image​

​image​

​image​

​image​

​image​

​image​

‍

P67 单步中断

​image​

​image​

​image​

‍

P68 由int指令引发的中断

​image image​

​image​

image​

‍

P69 BIOS和DOS中断处理

​image​

​image​

​image​

​image​

​image​

​image​

‍

P70 端口的读写

​image​

​image​

​image​

​image​

​image​

‍

P71 操作CMOS RAM芯片

​image​

  • 128 个字节的 RAM 中存储:内部实时钟、系统配置信息、相关的程序(用于开机时配置系统信息)。
  • CMOS RAM 芯片靠电池供电,关机后其内部的实时钟仍可正常工作, RAM 中的信息不丢失。
  • 该芯片内部有两个端口,端口地址为70h和71h,CPU 通过这两个端口读写CMOS RAM:
    70h地址端口,存放要访问的CMOS RAM单元的地址;
    71h数据端口,存放从选定的单元中读取的数据,或要写入到其中的数据。
  • 读取CMOS RAM的两个步骤:
    将要读取的单元地址送入70h地址端口;
    从数据端口71h读出指定单元的内容。

​image​

​image​

‍

P72 外设连接与中断

​image​

​image​

​image​

‍

P73 PC机键盘的处理过程

​image​

断码 = 通码+80H

​image​

​image​

​image​

‍

P74 定制键盘输入处理

​image​

​image​

​image​

​image​

​image​

‍

P78 磁盘读写

​image​

​image​

​image​

​image​

​image​

‍

‍

‍

‍

‍

posted @ 2024-06-19 19:01  Baizzzzzz  阅读(982)  评论(0)    收藏  举报