第三章

一、题目回顾

针对8086,在debug中执行以下命令:-e 0:200 10 20。在debug中,使用a命令,写出汇编指令,计算内存单元地址00200H00201H两个字节数据的总和,并将结果保存在00202H中。

方法一:             方法二:           方法三:

mov ax,0            mov ax,0           mov bx,20

mov ds,ax              mov ds,ax            mov ds,bx

mov al,[200]          mov al,[200]         mov al,[0]

add al,[201]           mov [200],al         add al,[1]

mov [202],al          mov al,[201]         mov [2],al

                  add [201],al

 

关于栈的说法,正确的是

  1. 入栈和出栈只能从栈顶操作。
  2. 栈空间中,固定的一端称为栈顶。
  3. 栈空间中,栈顶会随着数据的入栈和出栈而动态变化
  4. 通过入栈和出栈指令,访问的是栈顶,而movadd等指令可以通过偏移地址访问栈中其他单元。

 

00200H-002FFH这段内存当作栈来使用,初始栈为空

方法一:               方法二:

mov ax,0             mov bx,20H

mov ss,ax              mov ss,bx

mov sp,300H           mov sp,100H

 

 

关于栈的说法,正确的是:

  1. 8086dos汇编中约定栈空间的入栈和出栈均以字为单位,而其他有些汇编指令则支持以字,字节,双字等作为入栈和出栈操作的单位。
  2. SS全称Stack Segement Register,栈段寄存器,用来存放栈段的地址
  3. SP全称Stack Pointer Register,栈指针寄存器,用来存放栈顶的偏移指针
  4. SS:SP构成了栈顶的逻辑地址,通过SS*16+SP可以计算出栈顶的物理地址。

 

---------------------------------------------------------------------------------------------------------------------------------

二、寄存器

 

 

DS[address]

mov ax,1000H

mov ds,ax ;ds<-1000H

 

mov al,[0] ;al<-(ds:0)

 

mov bl[1] ;bl<-(ds:1)

ds中的值默认为段地址

 

 

 

mov指令形式

mov    寄存器常数 mov   ax, 1000H

mov    寄存器寄存器 mov   bx, ax

mov    寄存器内存单元 mov   ax, [1]

mov    寄存器段寄存器 mov   ax, ds

mov    内存单元常数 mov    [1], byte ptr 3

mov    内存单元寄存器 mov    [1], ax

mov    内存单元段寄存器 mov    [1], ds

mov    段寄存器寄存器 mov    ds, ax

mov    段寄存器内存单元 mov    ds, [1]

 

注意:

  1. 两个操作数长度要一致
  2. 常数(立即数)不能作为目的操作数
  3. 常数作为源操作数时,如果最高位是十六进制的a-f,前面要加零。

 

 

add 指令形式

add    寄存器常数 add   ax, 1000H

add    寄存器寄存器 add   bx, ax

add    寄存器内存单元 add   ax, [1]

add    内存单元常数 add    [1], byte ptr 3

add    内存单元寄存器 add    [1], ax

 

 

sub指令形式

sub    寄存器常数 sub   ax, 1000H

sub    寄存器寄存器 sub   bx, ax

sub    寄存器内存单元 sub   ax, [1]

sub    内存单元常数 sub    [1], byte ptr 3

sub    内存单元寄存器 sub    [1], ax

 

 

小结

  1. 字在内存中存储时,要用两个连续地址的内存单元来存放,字的低位字节存放在低地址单元中,高位字节存放在高地址中。
  2. mov指令访问内存单元,可以在mov指令中只给出单元的偏移地址,此时段地址默认在DS寄存器中。
  3. [ADDRESS]表示一个偏移地址位address的内存单元
  4. 在内存和寄存器之间传送字型数据时,低地址单元和低八位,高地址单元和高八位相对应。
  5. movaddsub是具有两个操作对象的指令。jmp是具有一个操作对象的指令。
  6. 数据和程序没有区别。被CS:IP指向的信息是程序;被传送、运算等指令操作的是数据。我们可以自己定义出代码段,数据段,栈段。

---------------------------------------------------------------------------------------------------------------------------------

 

 

三、栈

 

栈的特性: 后进先出

两个概念: 栈底、栈顶

两个操作: 入栈、出栈

一个约定: 8086中栈以字为存取单位

栈顶:  最后入栈的字数据所对应的地址单元

栈底:  固定的一端,栈区最高地址单元的前一个单元

 

入栈:  把数据存入栈

出栈:  从栈取出数据

 

push 指令执行步骤:

  1. SP=SP-2;
  2. SS:SP指向的字单元中送入数据

 

pop指令执行步骤:

  1. SS:SP指向的字段元中读取数据
  2. SP=SP+2

栈为空时,栈顶指向栈底+2

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

 

 

汇编指令 功能

 push   寄存器   将寄存器值入栈

 pop   寄存器   用寄存器保存出栈数据

 push   内存单元   将内存单元内容入栈

 pop   内存单元   用内存单元保存出栈数据

 push   段寄存器   将段寄存器值入栈

 pop    段寄存器   用段寄存器保存出栈数据

 

指令形式 功能

 push   ax      ←   ax

 pop   ax   ax    ←  

 push   [0]       ←  ds:0对应的内存单元字数据

 pop   [0]  ds:0对应的内存单元 ← 

 push   ds      ←   ds

 pop    ds   ds   ←    

 

 

 

8086CPU而言,pushpop的操作:

 入栈和出栈均以字为单元

 操作对象不能是常数

 pop 段寄存器中,段寄存器不能是CSSS

 

 

 

 

以下两种情形会发生「栈顶超界」问题:

 当栈满的时候,再使用push指令入栈;

 当栈空的时候,再使用pop指令出栈;

      8086CPU不会自动考虑栈顶超界,需要程序员在编程设计时自己考虑。栈区长度不同,栈顶超界的具体情形也不同。

 

 

小结

1. 「段」是一个逻辑上的概念。编程时,可根据需要指定一段内存区用作数据段、代码段或是栈段。

2.  用作数据段时,要把段地址→DS.用作栈段时,要把段地址→SS,栈顶偏移地址 → SP。用作代码段时,段地址→CS,要取的指令偏移地址→IP。但CSIP的值不能使用mov改变.

3. 一段内存可以同时用作代码段、数据段、栈段。由编程时灵活确定。

4. 8086CPU中,每个段的最大长度不能超过64KB

(因为寄存器是16位的,能表示的地址范围只能是0000H~FFFFH,即0~216-1

posted @ 2018-11-01 16:55  Nebulas  阅读(240)  评论(0)    收藏  举报