汇编语言(以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对外部器件的控制能力。

imageimageimage​​​

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 @   Baizzzzzz  阅读(134)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示