内存访问

内存中字的存储

两个字节 = 一个字
在0地址处开始存放20000(4E20H),如下图所示,高位对应高地址位,低位对应低地址位。
汇编语言学习笔记——————内存访问_寄存器
由此需要注意的问题是:

  • 0地址单元存放的字节型数据是20
  • 0地址单元存放的字型数据数是4E20
  • 2地址单元中存放的字节型数据是12
  • 2地址单元中存放的字型数据是0012
  • 1地址单元中存放的字型数据是124E

小结

任何两个地址连续的内存单元,N号单元和N+1号单元,可以将他们看成两个内存单元,也可以看成一个地址为N的字单元中的高位字节单元和低位字节单元。

DS和[address]

  • CPU要读取一个内存单元时,必须先给出这个内存单元的地址
  • 在8086PC中,内存地址由段地址和偏移地址组成。
  • 8086CPU中有一个DS寄存器,通常用来存放要访问的数据的段地址。
  • 执行指令的时候,8086CPU自动取DS中的数据为内存单元中的段地址。

如何把1000H送入ds

  • 传送指令 MOV ax 1
  • 8086CPU不支持将数据直接送入段寄存器的操作,ds是一个段寄存器(硬件设计的问题)
  • mov ds 1000H是非法的
  • 遵循的原理:数据->通用寄存器->段寄存器

将aI中的数据 存入内存单元10000H

问题的本质:将寄存器中的数据送入内存单元

  • mov al 1000H
    上述指令的意思是将内存单元的数送入到寄存器当中。
    正确结论:
    mov bx,1000H
    mov ds,bx
    mov [0],al
    必须通过段寄存器作为媒介才能完成将寄存器的数存入内存中。

字的传送

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

  • 比如
    mov bx,1000H
    mov ds,bx
    mov ax,[0];1000:0处的字型数据存放至ax中
    mov [0],cx;cx中的数据送到内存1000:0处

mov、add、sub指令

  • mov 寄存器,数据
  • mov 寄存器,寄存器
  • mov 寄存器,内存单元
  • mov 内存单元,寄存器
  • mov 段寄存器,寄存器
  • mov 寄存器,段寄存器(也是正确的)

数据段

对于8086CPU机,我们可以根据需要将一组内存单元定义为一个段(可以是代码段,也可以是数据段)
我们可以将一组长度为N(N <= 64K)、地址连续、起始地址为16的倍数的内存单元当作是专门存储数据的内存空间,从而定义了一个数据段。

小结

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

CPU提供的栈机制

8086CPU提供入栈和出栈指令,最基本的两个是:

  • PUSH(入栈):push ax表示将寄存器ax中的数据送入栈中
  • POP(出栈):pop ax表示从栈顶取出数据送入ax。
  • 8086CPU的入栈和出栈操作都是以字节为单位进行的。
  • 8086CPU中,入栈时,栈顶从高地址向低地址方向增长。
  • 栈空,SS:SP指向栈空间最高地址单元的下一个单元。

栈顶越界问题

在使用push和pop时,都会发生栈顶越界的问题,下图是关于栈顶越出的两个例子:

  • push操作导致栈顶越界
    汇编语言学习笔记——————内存访问_技术_02
  • pop操作导致栈顶越界
    汇编语言学习笔记——————内存访问_出栈_03

push和pop指令

push和pop指令可以是在寄存器和内存之间传送数据的。当然也有别的形式,可以是如下的形式:

  • push 寄存器:将一个寄存器中的数值入栈
  • pop 寄存器:出栈,用一个寄存器接收出栈的数据
    当然也可以是如下的形式:
  • push 段寄存器;将一个段寄存器中的数据入栈
  • pop 段寄存器:出栈,用一个段寄存器接收出栈的数据
    也可以在内存单元与内存单元之间传送数据:
  • push 内存单元:将一个内存字单元处的字入栈
  • pop 内存单元:出栈,用一个内存单元接收出栈的数据
    • 比如:
      mov ax,1000H
      mov ds,ax;内存单元的段地址放在ds中
      push [0];将1000:0处的字压入栈中
      pop [2];出栈,出栈的数据送入1000:2处
      需要注意的是:
      执行push时,CPU要进行两部操作;
  1. 第一步操作是:先改变SP
  2. 第二步操作是:向SS:SP处传送
    执行pop时,也需要两步操作:
  3. 第一步操作是:先读取SS:SP处的数据
  4. 第二步操作是:再改变SP的值

段的综述

我们可以将一段内存定义为一个段,用一个段地址指示段,用偏移地址访问段内的单元。

  • 可以用一个段存放数据,将它定义为“数据段”
    • 对于数据段,将它的段地址放在DS中,用mov,add,sub等访问内存单元的指令时,CPU就将我们定义的数据段中的内容当做数据来进行访问。
  • 可以用一个段存放代码,将它定义为“代码段”
    • 对于代码段,将它的段地址放在CS中,将段中的第一条指令的偏移地址放在IP中,这样CPU就将执行我们定义的代码中的指令。
  • 可以用一个段当做栈,将它定义为“栈段”
    • 将它的段地址放在SS中,将栈顶单元的偏移地址放在SP中,这样CPU在需要进行栈操作的时候,比如执行PUSH、pop指令时,就将我们定义的栈段当做栈空间来进行使用。

检测点3.2

补全下面的两段代码,使其可以将10000H~1000FH中的8个字,逆序复制到20000H-2000FH中。逆序复制得含义如图所示:
汇编语言学习笔记——————内存访问_技术_04
代码段1:
mov ax,1000H
mov ds,ax
mov ax,2000H
mov ss,ax
mov sp,01H
push [0]
push [2]
push [4]
push [6]
push [8]
push [A]
push [C]
push [E]
代码段2:
mov ax,2000H
mov ds,ax
mov ax,1000H
mov ss,ax
mov sp,00H
pop [E]
pop [C]
pop [A]
pop [8]
pop [6]
pop [4]
pop [2]
pop [0]