汇编学习Day3

第三章 寄存器(内存访问)

3.1内存中字的存储

  • cpu中,用16位寄存器来存储一个字。高8位字节,低8位字节。在内存中存储时,由于内存单元字节(一个单元存放一个字节),则一个字要用两个地址连续的内存单元来存放,这个字的低位字节存放在地址单元中,高位字节存放在高地址单元中。比如我们从0地址开始存放20000,情况如图:
    在这里插入图片描述
    在图中,我们用0、1两个内存单元存放数据20000(4E20H)。0、1两个内存单元用来存储一个字,这两个单元可以看作一个起始地址为0的字单元(存放一个字的内存单元,有0、1两个字节单元组成)。0是低位字节,1是高位字节
  • 所以现在提出字单元概念:字单元,即存放在一个字型数据的内存单元,由两个地址连续的内存单元组成。高地址内存单元中

3.2 DS和[address]

  • cpu要读些一个内存单元的时候,必须先给出这个内存单元的地址,在8086cpu中,内存地址由福安地址和偏移地址组成。8086cpu中有一个DS寄存器,通常用来存放要访问数据的段地址。
  • 我们要读取1000H单元的内容,可以用下面程序进行
mov bx,1000H
mov ds,bx
mov al,[0]

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

  • mov:1.将数据直接送入寄存器;2.讲一个寄存器中的内容送入另一个寄存器。
  • 也可以mov指令将一个内存单元种的内容送入一个寄存器中。此时mov指令格式应该是:mov寄存器名,内存单元地址
  • “[…]”表示一个内存单元,“[…]”中的0表示内存单元的偏移地址
  • 只有偏移地址 是不能定位一个内存单元的,内存单元的段地址是多少?执行指令时,8086cpu自动取ds中的数据为内存单元的段地址
  • 10000H用段地址和偏移地址表示为1000:0,我们现将段地址10000H放入ds,然后用mov al,[0]完成传送。mov指令中的[]说明操作对象时一个内存单元,[]中的0说明这个内存单元的偏移地址是0.段地址默认放在ds中。指令执行时,8086cpu会自动从ds取出

3.3 字的传送

mov ax,1000H
mov ds,ax
mov ax,[0]
mov bx,[2]
mov cx,[1]
add bx,[1]
add cx,[2]

内存情况示意
在这里插入图片描述

  • 执行指令后相关寄存器的值
    在这里插入图片描述
mov ax,1000H
mov ds,ax
mov ax,11316
mov[0],ax
mov bx,[0]
sub bx,[2]
mov [2],bx
  • 内存情况示意
    在这里插入图片描述
  • 执行指令与寄存器中的内容
    加粗样式

3.4 mov,add,sub指令

mov 寄存器,数据  比如:mov ax,8
mov 寄存器,寄存器  比如: mov ax,bx
mov 寄存器,内存单元  比如:mov ax,[0]
mov 内存单元,寄存器  比如:mov [0],ax
mov 段寄存器,寄存器  比如:mov ds,ax
  • 既然有“mov 段寄存器,寄存器”,从寄存器向段寄存器传送数据,那么也应该“mov 寄存器,段寄存器”,从段寄存器向寄存器传送数据。一个设想是:8086cpu内部有寄存器到段寄存器的通路,那么也有相反通路

  • 有了推测,我们还要验证一下。
    在这里插入图片描述

  • 用A命令在一个预设的地址0B39:0100处,用汇编的形式mov ax,ds 写入指令,再用T命令执行,可以看到执行的结果,段寄存器ds 中的值送到了寄存器ax 中。通过验证我们知道,“mov寄存器,段寄存器”是正确的指令。

  • 既然有“mov内存单元,寄存器”,从寄存器向内存单元传送数据,那么也应该有“mov内存单元,段寄存器”,从段寄存器向内存单元传送数据。比如我们可以将段寄存器cs 中的内容送入内存10000H 处,指令如下。

mov ax,1000H
mov ds,ax
mov [0],cs

在Debug中进行试验
在这里插入图片描述

  • 当CS:IP指向0B39:0105的时候,Debug 显示当前的指令mov [0000],cs,因为这是一条访问内存的指令,Debug 还显示出指令要访问的内存单元中的内容。由于指令中的CS是一个16位寄存器,所以要访问(写入)的内存单元是一个字单元,它的偏移地址为0,段地址在 ds 中,Debug 在屏幕右边显示出“DS:0000=0000”,我们可以知道这个字单元中的内容为0。

  • add和sub指令同mov一样,都有两个操作对象,有以下形式

add 寄存器,数据  如:add ax,8
add 寄存器,寄存器  如:add ,ax,bx
add 寄存器,内存单元  如:add ax,[0]
add 内存单元,寄存器 如:add [0],ax
sub 寄存器,数据  如:sub ax,8
sub 寄存器,寄存器  如:sub ,ax,bx
sub 寄存器,内存单元  如:sub ax,[0]
sub 内存单元,寄存器  如:sub [0],ax
 

3.5 数据段

  • 比如,将123B0H~123B9H的内存单元定义为数据段。现在要累加这个数据段中的言3个单元中的数据,代码如下。
mov ax,123BH
mov ds,ax;123BH送入ds 中,作为数据段的段地址
mov al,0;      用al存放累加结果
add al,[0];    将数据段第一个单元(偏移地址为o)中的数值加到al中
add al, [1];   将数据段第二个单元(偏移地址为1)中的数值加到al中
add al,[2];    将数据段第三个单元(偏移地址为2)中的数值加到al中

3.6 栈

  • 栈是一种具有特殊的访问方式的存储空间。它的特殊性在于,最后进入这个空间的数据,最先出去
  • 用一个盒子3本书演示:

入栈的方式
在这里插入图片描述

  • 现在问题是,一次只允许取一本书,该怎么将3本书从盒子取出来
  • 必须从盒子最上面开始取。

出栈的方式
在这里插入图片描述

3.7cpu提供的栈机制

  • 8086cpu提供入栈和出栈指令,最基本的两个是push(入栈)和pop(出栈)。8086cpu的入栈和出栈操作都是以字为单位进行

8086cpu的栈操作
在这里插入图片描述


mov ax,0123H
push ax
mov bx,2266H
push bx
mov cx,1122H
push cx
pop bx
pop cx
  • 字型数据用两个单元存放,高地址单元存放高8位,低地址单元存放低8位

其一,我们将10000H-100FH这段内存当作栈来使用,cpu执行push和pop指令时,将对这段空间按照栈的后进先出的规则进行访问。但是,一个重要的问题是,cpu如何知道10000H-100FH这段空间被当作栈来使用?
其二,push ax等入栈指令 执行时,要将寄存器中的内容放入当前栈顶单元的上方,成为新的的栈顶元素;pop ax 等指令执行时,亚聪栈顶单元取出数据,送入寄存器中。显然,push pop 在执行的时候,必须知道哪个单元是栈顶单元

  • 现在,我们可以完整的描述push和pop指令的功能,例如push ax

push ax的执行,由以下两步完成

  1. SP=SP-2。SS:SP指向当前栈顶前面的单元,以当前栈顶前面的单元为新的栈顶;
  2. 将ax中的内容送入SS:SP指向的内存单元处,SS:SP此时指向新栈顶
    在这里插入图片描述

3.8 栈顶超界的问题

  • 我们现在知道,8086cpu用SS和SP只是记录了栈顶的地址,依靠SS和SP只是记录了栈顶的地址,依靠SS和SP可以保证在入栈和出栈时找到栈顶。如何能够保证在入栈、出栈时,栈顶不会超出栈空间

执行push后栈顶超出栈空间
在这里插入图片描述


执行pop后栈顶超出栈空间
在这里插入图片描述


在执行8次pop ax后,从栈中弹出8个字,栈空,SS:SP指向10020H;
再次执行pop ax: sp=sp+2,SS:SP指向10022H,栈顶超出了栈空间。此后,如果再执行push指令,10020H、10021H中的数据将被覆盖。

3.9 push、pop指令

前面我们一直使用push ax和pop ax,显然push 和pop指令是可以在寄存器和内存(栈空间淡然也是内存空间的一部分,它只是一段可以以一种特殊的方式进行)之间传送数据的

push和pop指令的格式可以是如下
push 寄存区;
pop 寄存器;

当然也可以是如下形式:

push 段寄存器;将一个段寄存器中的数据入栈
pop 段寄存器;出栈,用一个段寄存器
push 和 pop也可以在内存单元和内存单元之间传送数据,我们可以
push内存单元;将一个内存字单元处字入栈(注意:找操作都是以字为单元)
pop内存单元;出栈,用一个内存字单元接受出栈的数据
必须:
mov ax,1000H
mov ds,ax;内存单元的段地址要放在ds中
push [0];1000:0处的字压入栈中
pop[2];出栈,用一个,内存字单元接受出栈的数据
比如:
mov ax,1000H
mov ds,ax;内存单元的段地址要放在ds中
push [0];1000:0处的字压入栈中
pop [2];出栈,出栈的数据送入1000:2

指令执行时,cpu要知道内存单元的地址,可以在push、pop指令中只给出内存单元的便宜地址,段地址在指令执行时,cpu从ds中取得

问题:1.将10000H-1000FH这段空间当作栈,初始状态栈是空的;
2.设置AX=001AH,BX=001BH
3.利用栈,交换AX和BX中的数据

mov ax,1000H
mov ss,ax
mov sp,0010H;初始化栈顶,栈的情况如图1所示

mov ax,001AH
mov bx,001BH

push ax
push bx; ax、bx入栈,栈的情况如图2

pop ax; 当前栈顶的数据是bx中原来的数据:001BH;
       ;所以先pop ax,ax=001BH;
     
pop bx  ;  执行pop ax后,栈顶的数据为ax原来的数据;所以再pop bx,bx=001AH

图1
在这里插入图片描述


图二在这里插入图片描述

3.10 栈段

  • 将一段内存当作栈段,仅仅是我们再编程时的一种安排,cpu并不会由于这种暗炮,就在执行push、pop等站操作指令时自动地将我们定义的栈段当作栈空间来访问。如何使得如push、pop等栈操作指令访问我们定义的栈段呢?就是要讲SS:SP指向我们定义的栈段。

如果讲10000H-1FFFFH这段空间当作栈段,初始状态栈是空的,此时,SS=1000H,SP=?

如果将10000H~1FFFFH这段空间当作栈段,SS=1000H,栈空间为64KB,栈最底部的字单元地址为1000:FFFE。任意时刻,SS:SP指向栈顶单元,当栈中只有一个元素的时候,SS=1000H,SP=FFFEH。栈为空,就相当于栈中唯一的元素出栈,出栈后,SP=SP+2。
SP原来为FFFEH,加2后SP=o,所以,当栈为空的时候,SS=1000H,SP=O。换一个角度看,任意时刻,SS:SP指向栈顶元素,当栈为空的时候,栈中没有元素,也就不存在栈顶元素,所以 SS:SP只能指向栈的最底部单元下面的单元,该单元的地址为栈最底部的字单元的地址+2。栈最底部字单元的地址为1000:FFFE,所以栈空时,SP=0000H

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Edison.W

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值