小甲鱼大全课件

发布时间:2020-09-13 01:18:22   来源:文档文库   
字号:

引言

汇编语言是直接在硬件之上工作的编程语言,首先要了解硬件系统的结构,才能有效的应用汇编语言对其编程。

在本章中,对硬件系统结构的问题进行一部分的探讨,以使后续的课程可在一个好的基础上进行。

当课程进行到需要补充新的基础知识(关于编程结构或其他的)时候,再对相关的基础知识进行介绍和探讨。 本书的原则是,以后用到的知识,以后再说。

汇编课程的研究重点放在如何利用硬件系统的编程结构和指令集有效灵活的控制系统进行工作。

机器语言

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

机器指令展开来讲就是一台机器可以正确执行的命令。

指令:01010000 (PUSH AX)

电平脉冲:

电子脉冲示例图

早期的程序员们将01数字编程的程序代码打在纸带或卡片上, 1打孔,0不打孔,再将程序通过纸带机或卡片机

输入计算机,进行运算。

后来呢,逐渐使用高科技……但打洞洞是始祖

S = 768 + 12288 - 1280

汇编语言的产生

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

汇编指令和机器指令的差别在于指令的表示方法上。汇编指令是机器指令便于记忆的书写格式。

汇编指令是机器指令的助记符。

机器指令:000

操作:寄存器BX的内容送到AX

汇编指令:MOV AX,BX

这样的写法与人类语言接近,便于阅读和记忆。

寄存器:简单的讲是CPU中可以存储数据的器件,一个 CPU中有多个寄存器。

AX是其中一个寄存器的代号,

BX是另一个寄存器的代号。

更详细的内容我们在以后的课程中将会讲到。

计算机能读懂的只有机器指令,那么如何让计算机执行程序员用汇编指令编写的程序呢?

汇编语言的组成

汇编语言由以下3类组成:

1 汇编指令(机器码的助记符)

2 伪指令(由编译器执行)

3 其它符号(由编译器识别)

汇编语言的核心是汇编指令,它决定了汇编语言的特性。

存储器

CPU是计算机的核心部件•它控制整个计算机的运作并进行运算,要想让一个 CPU工作,就必须向它提供指令和数

据。

指令和数据在存储器中存放,也就是平时所说的内存。

在一台PC机中内存的作用仅次于CPU

离开了内存,性能再好的 CPU也无法工作。

磁盘不同于内存,磁盘上的数据或程序如果不读到内存中,就无法被 CPU使用。

指令和数据

指令和数据是应用上的概念。

在内存或磁盘上,指令和数据没有任何区别,都是二进制信息。

二进制信息:

000

> 89D8H (数据)

000

> MOV AX,BX (程序)

存储单元

存储器被划分为若干个存储单元,每个存储单元从 0开始顺序编号;

例如:

一个存储器有128个存储单元,

编号从0127

存储器

对于大容量的存储器一般还用以下单位来计量容量(以下用 B来代表Byte):

1KB=1024B

1MB=1024KB

1GB=1024MB

B=1024GB

磁盘的容量单位同内存的一样,实际上以上单位是微机中常用的计量单位。

CPU对存储器的读写

CPU要想进行数据的读写,必须和外部器件(标准的说法是芯片)进行三类信息的交互: 存储单元的地址(地址信息)

器件的选择,读或写命令(控制信息)

读或写的数据(数据信息)

那么CPU是通过什么将地址、数据和控制信息传到存储芯片中的呢? 电子计算机能处理、传输的信息都是电信号,电信号当然要用导线传送。

在计算机中专门有连接CPU和其他芯片的导线,通常称为总线。

物理上:一根根导线的集合;

逻辑上划分为:

地址总线

数据总线

控制总线

总线在逻辑上划分的图示:

上节课我们知道CPU是如何进行数据读写的。可是我们如何命令计算机进行数据的读写呢? 对于8086CPU下面的机器码能够完成从3号单元读数据:

机器码:000

含义:从3号单元读取数据送入寄存器 AX

CPU接收这条机器码后将完成上面所述的读写工作。

地址总线

CPU是通过地址总线来指定存储单元的。

地址总线上能传送多少个不同的信息, CPU就可以对多少个存储单元进行寻址。

那么,地址总线如何发送地址信息呢?

地址总线

一个CPUN根地址总线,则可以说这个 CPU的地址总线的宽度为N

这样的CPU最多可以寻找2N次方个内存单元。

CPU与内存或其它器件之间的数据传送是通过数据总线来进行的。

数据总线的宽度决定了 CPU和外界的数据传送速度。

我们来分别看一下它们向内存中写入数据 89D8H时,是如何通过数据总线传送数据的:

8位数据总线上传送的信息

8位数据总线上传送的信息

16位数据总线上传送的信息

16位数据总线上传送的信息

控制总线

CPU对外部器件的控制是通过控制总线来进行的。在这里控制总线是个总称,控制总线是一些不同控制线的集合。

有多少根控制总线,就意味着 CPU提供了对外部器件的多少种控制。

所以,控制总线的宽度决定了 CPU对外部器件的控制能力。

控制总线上发送的控制信息

控制总线上发送的控制信息

前面所讲的内存读或写命令是由几根控制线综合发岀的:

其中有一根名为读信号输出控制线负责由 CPU向外传送读信号,CPU向该控制线上输出低电平表示将要读取数据;

有一根名为写信号输出控制线负责由 CPU向外传送写信号。

、结(1)汇编指令是机器指令的助记符,同机器指令一一对应。

(2)每一种CPU都有自己的汇编指令集。

(3)CPU可以直接使用的信息在存储器中存放。

(4)在存储器中指令和数据没有任何区别,都是二进制信息。

(5)存储单元从零开始顺序编号。

(6) 一个存储单元可以存储 8bit (用作单位写成“ b”),即8位二进制数。

(7)1B = 8b 1KB = 1024B 1MB = 1024KB 1GB = 1024MB

(8)每一个CPU芯片都有许多管脚,这些管脚和总线相连。也可以说,这些管脚引出总线。

一个CPL可以引岀三种总线的宽度标志了这个 CPU的不同方面的性能:

地址总线的宽度决定了 CPU的寻址能力;

数据总线的宽度决定了 CPU与其它器件进行数据传送时的一次数据传送量;

控制总线宽度决定了 CPU对系统中其它器件的控制能力。

在汇编课程中,我们从功能的角度介绍了这三类总线,对实际的连接情况不做讨论。

内存地址空间(概述)

什么是内存地址空间呢?

一个CPU的地址线宽度为10,那么可以寻址1024个内存单元,这1024个可寻到的内存单元就构成这个 CPU勺内存地 址空间。下面深入讨论。

首先需要介绍两部分基本知识,主板和接口卡。

主板

在每一台PC机中,都有一个主板,主板上有核心器件和一些主要器件。

这些器件通过总线(地址总线、数据总线、控制总线)相连。

接口卡

计算机系统中,所有可用程序控制其工作的设备,必须受到 CPU的控制。

CPU对外部设备不能直接控制,如显示器、音箱、打印机等。直接控制这些设备进行工作的是插在扩展插槽上的接

口卡。

各类存储器芯片

从读写属性上看分为两类: 随机存储器(RAM和只读存储器(ROM

从功能和连接上分类:

随机存储器RAM

接口卡上的RAM

装有BIOSROM

BIOS: Basic Input/Output System ,基本输入输岀系统。

BIOS是由主板和各类接口卡(如:显卡、网卡等)厂商提供的软件系统,可以通过它利用该硬件设备进行最基本的 输入输岀。在主板和某些接口卡上插有存储相应 BIOSROM

PC机中各类存储器的逻辑连接情况

内存地址空间

上述的那些存储器在物理上是独立的器件。

但是它们在以下两点上相同:

1 都和cpu勺总线相连。

2 CPU对它们进行读或写的时候都通过控制线发岀内存读写命令。

将各各类存储器看作一个逻辑存储器:

将各各类存储器看作一个逻辑存储器

假设,上图中的内存空间地址段分配如下:

地址07FFFH32KB空间为主随机存储器的地址空间;

地址8000H9FFFH8KB空间为显存地址空间;

地址A000HFFFFH24KB空间为各个ROM勺地址空间。

所有的物理存储器被看作一个由若干存储单元组成的逻辑存储器;

每个物理存储器在这个逻辑存储器中占有一个地址段,即一段地址空间;

CPU在这段地址空间中读写数据,实际上就是在相对应的物理存储器中读写数据。

不同的计算机系统的内存地址空间分配情况是不同的。

8086PC机的内存地址空间分配

8086PC机的内存地址空间分配

最终运行程序的是 CPU我们用汇编编程的时候,必须要从 CPU角度考虑问题。

我们学习这门课程的核心思维

CPU来讲,系统中的所有存储器中的存储单元都处于一个统一的逻辑存储器中, 它的容量受CPU寻址能力的限制

这个逻辑存储器即是我们所说的内存地址空间。

CPU既述

一个典型的CPU由运算器、控制器、寄存器等器件组成,这些器件靠内部总线相连。

区别:

内部总线实现CPU内部各个器件之间的联系。

外部总线实现CPU和主板上其它器件的联系。

寄存器概述

8086CPU14个寄存器 它们的名称为:

AXBXCX DX SIDISP BPIPCS SS DS ES PSW/

这些寄存器我们以后会陆续介绍,因为“以后用到的知识以后再讲一一减负”

通用寄存器

8086CPU所有的寄存器都是16位的,可以存放两个字节。

AXBXCX DX通常用来存放一般性数据被称为通用寄存器。

下面以AX为例,我们看一下寄存器的逻辑结构。

寄存器的逻辑结构

一个16位寄存器可以存储一个16位的数据。(数据的存放情况)

数据:18

二进制表示:10010

在寄存器AX中的存储:

寄存器AX

数据:20000

二进制表示:000

在寄存器AX中的存储:

寄存器AX

一个16位寄存器所能存储的数据的最大值为多少?

答案:2F6-1

8086上一代CPI中的寄存器都是8位的,为保证兼容性,这四个寄存器都可以分为两个独立的 8位寄存器使用。

AX可以分为AHAL;

BX可以分为BHBL;

CX可以分为CHCL;

DX可以分为DHDL

8086CPU8位寄存器存储逻辑

AX为例,8086CPU16位寄存器分为两个8位寄存器的情况:

8086CPU16位寄存器

AX的低8位(07位)构成了 AL寄存器,高8位(8~15位)构成了 AH寄存器。

AHAL寄存器是可以独立使用的8位寄存器。

8086CPU8位寄存器数据存储情况

8086CPU8位寄存器数据存储情况

8086CPU8位寄存器数据存储情况

一个8位寄存器所能存储的数据的最大值是多少?

答案:2A8-1 o

字在寄存器中的存储

一个字可以存在一个16位寄存器中,这个字的高位字节和低位字节自然就存在这个寄存器的高 8位寄存器和低8位寄

存器中。

字在寄存器中的存储

关于数制的讨论

由于一个内存单元可以存放 8位数据,CPU中的寄存器又可存放n8位数据。也就是说,计算机中的数据大多 是由1N8位数据构成的。

用十六进制来表示数据可以直观的看出这个数据是由哪些 8位数据构成的。

每两位对应一个八位的二进制数据(修正视频)!

几条汇编指令

汇编指令

CPU执行下表中的程序段的每条指令后,对寄存器中的数据进行的改变。

汇编指令

汇编指令

物理地址

CPU访问内存单元时要给岀内存单元的地址。所有的内存单元构成的存储空间是一个一维的线性空间。

我们将这个唯一的地址称为物理地址。

16位结构的CPU

概括的讲,16位结构描述了一个CPU具有以下几个方面特征:

1 运算器一次最多可以处理16位的数据。

2 寄存器的最大宽度为16位。

3 寄存器和运算器之间的通路是16位的。

8086CPU给出物理地址的方法

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

8086内部为16位结构,它只能传送16位的地址,表现岀的寻址能力却只有 64K

问题:那么,8086CPU如何用内部16位的数据转换成20位的地址呢?

自问自答:8086CPU采用一种在内部用两个16位地址合成的方法来形成一个 20位的物理地址 8086CPU如何用内部16位的数据转换成20位的地址

8086CPU读写内存时,发生了这么一些事:

CPU中的相关部件提供两个16位的地址,一个称为段地址,另一个称为偏移地址

段地址和偏移地址通过内部总线送入一个称为地址加法器的部件

地址加法器将两个16位地址合并成一个20位的地址

地址加法器工作原理

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

例如:8086CPU访问地址为123C8H的内存单元

8086CPU访问地址为123C8H的内存单元

由段地址X 16引发的血案

“段地址X 16”有一个更为常用的说法就是数据左移 4位。(二进制位)

进制转换

我们通过观察移位次数和各种形式数据的关系:

一个数据的二进制形式左移1位,相当于该数据乘以2;

一个数据的二进制形式左移 N位,相当于该数据乘以2N次方

地址加法器如何完成段地址X 16的运算?没错,以二进制形式存放的段地址左移 4位。

一个馒头引发的分析……

经过进一步的思考,我们可以看出:

一个数据的十六进制形式左移1位,相当于乘以16;

一个数据的十进制形式左移1位,相当于乘以10; 一个数据的X进制形式左移1位,相当于乘以X

段地址X 16+偏移地址=物理地址”的本质含义

两个比喻说明:

说明“基础地址+偏移地址=物理地址”的思想:第一个比喻

比如说,学校、体育馆同在一条笔直的单行路上(学校位于路的起点 0米处)。

读者在学校,要去图书馆,问我那里的地址,我可以用几种方式描述这个地址? 段地址X 16+偏移地址=物理地址

(1)从学校走2826m到图书馆。这2826可以认为是图书馆的物理地址。

(2)从学校走2000m到体育馆,从体育馆再走826m到图书馆。 第一个距离2000m是相对于起点的基础地址

第二个距离826m是将对于基础地址的偏移地址。

说明“段地址X 16+偏移地址=物理地址”的思想:第二个比喻

比如我们只能通过纸条来通信,读者问我图书馆的地址,我只能将它写在纸上告诉读者。

显然我必须有一张可以容纳 4位数据的纸条才能写下2826这个数据:

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

不巧的是,没有能容纳4位数据的纸条,仅有两张可以容纳 3位数据的纸条。

这样我只能以这种方式告诉读者 2826这个数据:

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

段的概念

误认识:

内存被划分成了一个一个的段,每一个段有一个段地址。 其实是:

内存并没有分段,段的划分来自于 CPU由于8086CPU用 “(段地址X 16+偏移地址=物理地址”的方式给岀内存单 元的物理地址,使得我们可以用分段的方式来管理内存。

分段的方式来管理内存

分段的方式来管理内存

以后,在编程时可以根据需要,将若干地址连续的内存单元看作一个段,用段地址X 16定位段的起始地址(基础地

址),用偏移地址定位段中的内存单元。

两点需要注意

段地址X 16必然是16的倍数,所以一个段的起始地址也一定是 16的倍数;

偏移地址为16位,16位地址的寻址能力为64K,所以一个段的长度最大为64K

内存单元地址小结

CPU访问内存单元时,必须向内存提供内存单元的物理地址。

8086CPU在内部用段地址和偏移地址移位相加的方法形成最终的物理地址。

思考两个问题

1.观察下面的地址,读者有什么发现?

内存单元

结论:CPU可以用不同的段地址和偏移地址形成同一个物理地址。

2.如果给定一个段地址,仅通过变化偏移地址来进行寻址,最多可以定位多少内存单元?

结论:偏移地址16位,变化范围为0FFFFH仅用偏移地址来寻址最多可寻 64K个内存单元。

比如:给定段地址1000H,用偏移地址寻址,CPU的寻址范围为:10000H1FFFFH

小结

8086PC机中,存储单元的地址用两个元素来描述。即段地址和偏移地址。

数据在21F60H内存单元中。”对于8086PC机的两种描述:

数据存在内存2000:1F60单元中;

数据存在内存的2000段中的1F60H单元中。

可根据需要,将地址连续、起始地址为 16的倍数的一组内存单元定义为一个段。

检测点

段寄存器

段寄存器就是提供段地址的。

8086CPUW4个段寄存器:CS DS SS ES

8086CPU要访问内存时,由这4个段寄存器提供内存单元的段地址。

CSIP

CSIP8086CPU中最关键的寄存器,它们指示了 CPU当前要读取指令的地址。

CS为代码段寄存器;

IP为指令指针寄存器。

8086PC读取和执行指令相关部件

8086PC读取和执行指令相关部件

8086PC读取和执行指令演示

8086PC工作过程的简要描述

CS:IP指向内存单元读取指令,读取的指令进入指令缓冲器;

IP = IP + 所读取指令的长度,从而指向下一条指令;

执行指令。 转到步骤 (1),重复这个过程。

8086CPU加电启动或复位后( 即CPU刚开始工作时)CSIP被设置为CS=FFFFH IP=OOOOH

即在8086PC机刚启动时,CPU从内存FFFFOH单元中读取指令执行。

FFFFOH单元中的指令是8086PC机开机后执行的第一条指令。

在任何时候,CPUCS IP中的内容当作指令的段地址和偏移地址,用它们合成指令的物理地址,到内存中读取指 令码,执行。

如果说,内存中的一段信息曾被 CPU执行过的话,那么,它所在的内存单元必然被 CS:IP指向过。

修改CS IP的指令

CPU中,程序员能够用指令读写的部件只有寄存器,程序员可以通过改变寄存器中的内容实现对 CPU的控制。

CPU从何处执行指令是由CS IP中的内容决定的,程序员可以通过改变 CS IP中的内容来控制CPU执行目标指令。

我们如何改变CS IP的值呢?

8086CPU必须提供相应的指令

先回想我们如何修改 AX中的值?

mov指令

如:mov ax,123

mov指令可以改变8086CPU大部分寄存器的值,被称为传送指令。

能够通过mov指令改变CS IP的值吗?

mov指令不能用于设置CS IP的值,8086CPU没有提供这样的功能。

8086CPUCS IP提供了另外的指令来改变它们的值:转移指令

同时修改CS IP的内容:

jmp段地址:偏移地址

jmp 2AE3:3

jmp 3:0B16

功能:用指令中给岀的段地址修改 CS,偏移地址修改IP

仅修改IP的内容:

jmp某一合法寄存器

jmp ax (类似于 mov IP,ax )

jmp bx

功能:用寄存器中的值修改IP

问题分析:CPU运行的流程

内存中存放的机器码和对应汇编指令情况: (初始:CS=2000H IP=0000H)

CPU运行的流程

问题分析结果

(1)mov ax,6622

(2)jmp 1000:3

(3)mov ax,0000

(4)mov bx,ax

(5)jmp bx

6 mov ax,0123H

7 转到第3步执行

代码段

对于8086PC机,在编程时,可以根据需要,将一组内存单元定义为一个段。

可以将长度为N NK64KB )的一组代码,存在一组地址连续、起始地址为 16的倍数的内存单元中,这段内存是

用来存放代码的,从而定义了一个代码段。

代码段

这段长度为10字节的字节的指令,存在从123B0H123B9啲一组内存单元中,我们就可以认为,123B0H~123B9l这 段内存单元是用来存放代码的 ,是一个代码段,它的段地址为123BH长度为10字节。

如何使得代码段中的指令被执行呢?

将一段内存当作代码段,仅仅是我们在编程时的一种安排, CPU并不会由于这种安排,就自动地将我们定义得代码

段中的指令当作指令来执行。

CPU只认被CS:IP指向的内存单元中的内容为指令。

所以要将CS:IP指向所定义的代码段中的第一条指令的首地址。

如刚才的 CS = 123BHIP = 0000H

小结

1、 段地址在8086CPU的寄存器中存放。当8086CPL要访问内存时,由段寄存器提供内存单元的段地址。 8086CPL4 个段寄存器,其中CS用来存放指令的段地址。

2CS存放指令的段地址,IP存放指令的偏移地址。8086机中,任意时刻,CPLCS:IP指向的内容当作指令执行。

3 8086CPL的工作过程:

CS:IP指向内存单元读取指令,读取的指令进入指令缓冲器;

IP指向下一条指令;

执行指令。(转到步骤(1),重复这个过程。)

4 8086CPL提供转移指令修改CS IP的内容。

实验一

查看CPL和内存,用机器指令和汇编指令编程

DEBUGS具的使用

R命令查看、改变CPU寄存器的内容;

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

E命令改写内存中的内容;

U命令将内存中的机器指令翻译成汇编指令;

T命令执行一条机器指令;

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

引言

在第2章中,我们主要从CPU如何执行指令的角度讲解了 8086CPU的逻辑结构、形成物理地址的方法、相关的寄存 器以及一些指令。

这一章中,我们从访问内存的角度继续学习几个寄存器。

内存中字的存储

0地址处开始存放20000 4E20H :

内存中字的存储

注意:0号单元是低地址单元,1号单元是高地址单元。

问题:

1 0地址单元中存放的字节型数据是多少?

(2)0地址字单元中存放的字型数据是多少?

(3)2地址字单元中存放的字节型数据是多少?

(4)2地址单元中存放的字型数据是多少?

(5)1地址字单元中存放的字型数据是多少?

结论

任何两个地址连续的内存单元, N号单元和N+1号单元,可以将它们看成两个内存单元 ,也可以看成一个地址为 N

的字单元中的高位字节单元和低位字节单元。

DS [address]

CPU要读取一个内存单元的时候,必须先给岀这个内存单元的地址;

8086PC中,内存地址由段地址和偏移地址组成。

8086CPU中有一个DS寄存器,通常用来存放要访问的数据的段地址。

例如:我们要读取10000H单元的内容可以用如下程序段进行:

mov bx,1000H

mov ds,bx

mov al,[0]

mov al,[0]

已知的mov指令可完成的两种传送功能:

将数据直接送入寄存器;

将一个寄存器中的内容送入另一个寄存器中。

除此之外,mov指令还可以将一个内存单元中的内容送入一个寄存器。

上面三条指令将10000H (1000:0 )中的数据读到al中。

从哪个内存单元送到哪个寄存器中呢?

mov指令的格式:

mov寄存器名,内存单元地址

[]”表示一个内存单元,[]”中的0表示内存单元的偏移地址。

那么内存单元的段地址是多少呢?

执行指令时,8086CPU自动取DS中的数据为内存单元的段地址。

如何用mov指令从10000H中读取数据?

10000H表示为1000:0 (段地址偏移地址)

将段地址1000H放入ds

moval,[0]完成传送(mov指令中的[]说明操作对象是一个内存单元,[]中的0说明这个内存单元的偏移地址是 0, 它的段地址默认放在ds中)

如何把1000H送入ds

传送指令mov ax,1

相似的方式 mov ds,1000H?

8086CPU不支持将数据直接送入段寄存器的操作, ds是一个段寄存器。(硬件设计的问题)

mov ds,1000H 是非法的。

数据-> 通用寄存器-> 段寄存器

问题:

写几条指令,将al中的数据送入内存单元10000H?(思考后分析)

分析问题本质:

怎样将数据从寄存器送入内存单元?

结论:

mov bx,1OOOH

mov ds,bx

mov [0],al (—种合理的回答)

字的传送

因为8086CPU16位结构,有16根数据线,所以,可以一次性传送 16位的数据,也就是一次性传送一个字。

字的传送

问题:内存中的情况如下图,写岀下面指令执行后寄存器 axbxcx中的值。

字的传送

思考后请看听小甲鱼慢慢分析。(单步跟踪)

问题:内存中的情况如下图,写岀下面指令执行后寄存器 axbxcx中的值。

字的传送

movaddsub 指令

已学mov指令的几种形式:

mov寄存器,数据

mov寄存器,寄存器

mov寄存器,内存单元

mov内存单元,寄存器

mov段寄存器,寄存器

根据已知指令进行推测:

mov段寄存器,寄存器

mov寄存器,段寄存器

mov寄存器,段寄存器

mov内存单元,寄存器

mov内存单元,段寄存器

mov段寄存器,内存单元

addsub指令同mov—样,都有两个操作对象。

mov寄存器,段寄存器

它们可以对段寄存器进行操作吗?(请自行在 Debug中试验)

数据段

前面讲过,对于8086PC机,我们可以根据需要将一组内存单元定义为一个段 可以是代码段、数据段等

我们可以将一组长度为 N( N< 64K)、地址连续、起始地址为16的倍数的内存单元当作专门存储数据的内存空间,从 而定义了一个数据段。

比如我们用123B0H123B9H这段空间来存放数据:

段地址:123BH

长度:10字节

如何访问数据段中的数据呢?

将一段内存当作数据段,是我们在编程时的一种安排,我们可以在具体操作的时候 ,用ds存放数据段的段地址,

再根据需要,用相关指令访问数据段中的具体单元。

我们将123B0H123BAH勺内存单元定义为数据段,我们现在要累加这个数据段中的前 3个单元中的数据,代码如下:

访问数据段中的数据

问题

写几条指令,累加数据段中的前 3个字型数据。

思考后看分析:

累加数据段中的前3个字型数据

注意:一个字型数据占两个单元,所以偏移地址是 024

小结

1 字在内存中存储时,要用两个地址连续的内存单元来存放,字的低位字节存放在低地址单元中,高位字节存 放再高地址单元中。

2) 用mov指令要访问内存单元,可以在 mov指令中只给岀单元的偏移地址,此时,段地址默认在 DS寄存器中

3[address]表示一个偏移地址为 address的内存单元。

4) 在内存和寄存器之间传送字型数据时,高地址单元和高 8位寄存器、低地址单元和低8位寄存器相对应。

5movaddsub是具有两个操作对象的指令。jmp是具有一个操作对象的指令。

6 可以根据自己的推测,在 Debug中实验指令的新格式。

检测点

我们研究栈的角度:

栈是一种具有特殊的访问方式的存储空间。它的特殊性就在于,最后进入这个空间的数据,最先出去。

用一个盒子和3本书来描述栈的操作方式

出栈的方式

入栈的方式

入栈的方式

出栈的方式

出栈的方式

出栈的方式

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

入栈:将一个新的元素放到栈顶;

出栈:从栈顶取出一个元素。

栈顶的元素总是最后入栈,需要出栈时,又最先被从栈中取出。

栈的操作规则:LIFO Last In First Out ,后进先岀)

CPU提供的栈机制

现今的CPU中都有栈的设计。

8086CPU提供相关的指令来以栈的方式访问内存空间。

这意味着,我们在基于8086CPU编程的时候,可以将一段内存当作栈来使用。

8086CPU提供入栈和出栈指令: (最基本的)

PUSH(入栈)

POP (岀栈)

push ax :将寄存器ax中的数据送入栈中

pop ax :从栈顶取岀数据送入ax

8086CPU的入栈和岀栈操作都是以字为单位进行的。

下面举例说明,我们可以将10000H1000FH这段内存当作栈来使用。

寄存器(内存访问)04 -零基础入门学习汇编语言16

标签:push指令汇编语言 汇编语言

是否有疑惑?两个疑问

1 CPU如何知道一段内存空间被当作栈使用?

2 执行pushpop的时候,如何知道哪个单元是栈顶单元?

分析:任意时刻,SS:SP指向栈顶元素。

对于两个疑问的分析

CPU如何指导当前要执行的指令所在的位置?

答:寄存器CSIP中存放着当前指令的段地址和偏移地址。

8086CPU中,有两个寄存器:

段寄存器SS存放栈顶的段地址

寄存器SP存放栈顶的偏移地址

任意时刻,SS:SP指向栈顶元素。

push指令的执行过程

push ax

SP=S- 2;

ax中的内容送入SS:SP指向的内存单元处,SS:SP此时指向新栈顶。

push指令的执行过程

问题:如果我们将10000H1000FH这段空间当作栈,初始状态栈是空的,此时, SS=1000H SP=

思考后看分析。

push指令的执行过程

SP = 0010H

我们将10000H1000FH这段空间当作栈段,SS=1000H栈空间大小为16字节,栈最底部的字单元地址为1000:000E 任意时刻,SS:SP指向栈顶,当栈中只有一个元素的时候, SS = 1000HSP=000EH

栈为空,就相当于栈中唯一的元素岀栈,岀栈后, SP=SP+2, SP原来为000EH2SP=10H

所以,当栈为空的时候,SS=1000H SP=10H

换个角度看

任意时刻,SS:SP指向栈顶元素,当栈为空的时候,栈中没有元素,也就不存在栈顶元素

所以SS:SP只能指向栈的最底部单元下面的单元,该单元的偏移地址为栈最底部的字单元的偏移地址 +2

栈最底部字单元的地址为1000:000E,所以栈空时,SP=0010H

pop指令的执行过程

pop ax

SS:SP指向的内存单元处的数据送入 ax

SP = SP+2SS:SP指向当前栈顶下面的单元,以当前栈顶下面的单元为新的栈顶。

pop指令的执行过程

岀栈后,SS:SP指向新的栈顶1000EHpop操作前的栈顶元素,1000CH处的2266H依然存在,但是,它已不在栈 中。

当再次执行push等入栈指令后,SS:SP移至1000CH并在里面写入新的数据,它将被覆盖。

栈顶超界的问题

SSSP只记录了栈顶的地址,依靠 SSSP可以保证在入栈和岀栈时找到栈顶。

可是,如何能够保证在入栈、出栈时,栈顶不会超出栈空间?

都将发生栈顶超界问题,栈顶超界是危险的。

因为我们既然将一段空间安排为栈 ,那么在栈空间之外的空间里很可能存放了具有其他用途的数据、代码等,这

些数据、代码可能是我们自己的程序中的, 也可能是别的程序中的。(毕竟一个计算机系统并不是只有我们自己的程

序在运行)

但是由于我们在入栈出栈时的不小心,而将这些数据、代码意外地改写,将会引发一连串的错误。 但如果是刻意

的……那么……呵呵……)

我们当然希望CPU可以帮我们解决这个问题,比如说在 CPU中有记录栈顶上限和下限的寄存器,我们可以通过填写 这些寄存器来指定栈空间的范围 ,然后,CPU在执行push指令的时候靠检测栈顶上限寄存器,在执行 pop指令

的时候靠检测栈顶下限寄存器保证不会超界。

实际情况:8086CPU中并没有这样的寄存器。

8086CPU不保证对栈的操作不会超界。

这就是说8086CPU只知道栈顶在何处(由SS:SP指示),而不知道读者安排的栈空间有多大。

这点就好像CPU只知道当前要执行的指令在何处(由 CS:SP指示)而不知道读者要执行的指令有多少。

从这两点我们可以看出

8086CPU的工作机理,只考虑当前的情况:

当前栈顶在何处

当前要执行的指令是哪一条。

结论

我们在编程的时候要自己操心栈顶超界的问题 ,要根据可能用到的最大栈空间, 来安排栈的大小,防止入栈的数据

太多而导致的超界

执行岀栈操作的时候也要注意,以防栈空的时候继续岀栈而导致的超界。

pushpop指令是可以在寄存器和内存之间传送数据的。

栈空间当然也是内存空间的一部分,它只是一段可以以一种特殊的方式进行访问的内存空间。

pushpop指令的格式

push寄存器:将一个寄存器中的数据入栈

pop寄存器:岀栈,用一个寄存器接收岀栈的数据

例如:

push ax

pop bx

push段寄存器:将一个段寄存器中的数据入栈

pop段寄存器:岀栈,用一个段寄存器接收岀栈的数据

例如:

push ds

pop es

push内存单元:将一个内存单元处的字入栈(栈操作都是以字为单位)

pop内存单元:岀栈,用一个内存字单元接收岀栈的数据

例如:

push [0]

pop [2]

指令执行时,CPU要知道内存单元的地址,可以在 pushpop指令中给岀内存单元的偏移地址,段地址在指令执 行时,CPUds中取得。

问题

编程:将10000H1000FH这段空间当作栈,初始状态是空的,将 AXBXDS中的数据入栈。

思考后看分析。

pushpop 指令

问题

编程:

(1)10000H1000FH这段空间当作栈,初始状态是空的

(2)设置 AX=001AH BX=001BH;

(3)AX BX中的数据入栈;

(4)然后将AXBX清零

(5)从栈中恢复AX BX原来的内容。

思考后看分析。

pushpop 指令

从上面的程序我们看到,用栈来暂存以后需要恢复的寄存器中的内容时 ,岀栈的顺序要和入栈的顺序相反,因为最

后入栈的寄存器的内容在栈顶 ,所以在恢复时,要最先岀栈。

问题

编程:

(1)10000H1000FH这段空间当作栈,初始状态是空的

(2)设置 AX=002AH BX=002BH;

(3)利用栈,交换AXBX中的数据。

思考后看分析。

pushpop 指令

问题

我们如果要在10000H处写入字型数据2266H,可以用以下的代码完成:

mov ax,1000H

mov ds,ax

mov ,ax,2266H

mov [0],ax

看题目

补在10000H处写入字型数据2266H

mov ax,2266H

push ax

要求:不能使用"mov内存单元寄存器"这类指令

思考后看分析。

我们看需补全代码的最后两条指令,将 ax中的2266H压入栈中,也就是说,最终应由 push ax2266H写入10000H

处。

问题的关键就在于:如何使 push ax访问的内存单元是10000H

Push指令是入栈指令。(注意执行过程)

完整的程序:

mov ax,1000H

mov ss,ax

mov sp,2

mov ax,2266H

push ax

pushpop实质上就是一种内存传送指令,可以在寄存器和内存之间传送数据,与 mov指令不同的是,pushpop

指令访问的内存单元的地址不是在指令中给岀的,而是由 SS:SP指岀的。

同时,pushpop指令还要改变SP中的内容。

我们要十分清楚的是,pushpop指令同mov指令不同,CPU执行mov指令只需一步操作,就是传送,而执行pushpop指令却需要两步操作。

执行push时:先改变SP,后向SS:SP处传送。

执行pop时:先读取SS:SP处的数据,后改变SPo

pushpop等栈操作指令,修改的只是 SP也就是说,栈顶的变化范围最大为: 0FFFFH

提供:SS SP指示栈顶改变SP后写内存的入栈指令读内存后改变SP的岀栈指令。 这就是8086CPU提供的栈操作机制。

栈的综述

1.8086CPU提供了栈操作机制,方案如下: SS, SP中存放栈顶的段地址和偏移地址 提供入栈和岀栈指令,他们根据 SS:SP指示的地址,按照栈的方式访问内存单元。

2.push指令的执行步骤:

SP=SP-2;

SS:SP指向的字单元中送入数据。

3.pop指令的执行步骤:

SS:SP指向的字单元中读取数据

SP=SP-2

4.任意时刻,SS:SP指向栈顶元素。

5.8086CPU只记录栈顶,栈空间的大小我们要自己管理。

6.用栈来暂存以后需要恢复的寄存器的内容时 ,寄存器出栈的顺序要和 入栈的顺序相反

7.pushpop实质上是一种内存传送指令,注意它们的灵活应用。

栈是一种非常重要的机制,一定要深入理解,灵活掌握。

本文来源:https://www.2haoxitong.net/k/doc/60d15ceda7c30c22590102020740be1e640eccea.html

《小甲鱼大全课件.doc》
将本文的Word文档下载到电脑,方便收藏和打印
推荐度:
点击下载文档

文档为doc格式