汇编语言3-寄存器(内存访问)

03寄存器(内存访问)

3.1 内存中字的存储

  • 字单元:(以8086CPU为例)即存放一个字型数据(16位)的内存范元,由两个地址连续的内存单元组成。高地址内存单元中存放字型数据的高位字节,低地址内存单元中存放字型数据的低位字节
    • 例如可以从0地址单元中存放20000(4E20H),则1地址单元中存放4EH,0地址单元存放20H
  • 我们将起始地址位N的字单元简称为N地址字单元,比如一个字单元由2、3两个内存单元组成。则这个字单元的起始地址为2,可以说这个是2地址字单元
    • 区分0地址单元和0字地址单元的区别,例如上述例子中,0地址单元中存放的字节型数据:20H,0地址字单元中存放的字型数据:4E20H

3.2 DS和address

  • 8086CPU中有一个DS寄存器,通常用来存放要访问数据的段地址。比如我们要读取10000H单元中的内容:

    mov bx,1000H
    mov ds,bx
    mov al,[0]
    
    • 上面三条指令实现了将10000H(1000:0)中的数据读到al中
    • mov指令也可以将一个内存单元中的内容送入一个寄存器中,通过mov 寄存器名,内存单元地址其中[…]表示内存单元,[…]中的0表示单元的偏移地址
    • 执行上述代码时,8086CPU会自动取ds中的数据作为内存单元中的段地址
    • 8086CPU中并不支持mov ds,1000H的模式,它不支持直接将数据送入段寄存器的操作,ds是一个段寄存器,所以mov ds,1000H这条指令是非法的,只能用一个寄存器进行中转。如上述代码段所示
  • 如下操作可以实现从al到10000H的数据传送:

    mov bx,1000H
    mov ds,bx
    mov [0],al
    

3.3 字的传送

  • 8086CPU可以一次性传送16位数据,也就是可以一次性传送一个字,只要在mov指令中给出16位的寄存器就可以进行16位数据的传送了

    mov bx,1000H
    mov ds,bx
    mov ax,[0]	;1000:0处的字型数据送入ax
    mov [0],cx	;cx中的16位数据送到1000:0处
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BrxEvFr9-1637590078498)(C:\Users\86133\AppData\Roaming\Typora\typora-user-images\image-20211122220742891.png)]

指 令执行后相关寄存器中的内容
mov ax,1000Hax = 1000H
mov ds,axds = 1000H
mov ax,[0]ax = 1123H
mov bx,[2]bx = 6622H
mov cx,[1]cx = 2211H
add bx,[1]bx = 8833H
add cx,[2]cx = 8833H

3.4 mov、add、sub指令

  • mov指令可以有一下几种形式:

    表现形式示例
    mov 寄存器,数据mov ax,8
    mov 寄存器,寄存器mov ax,bx
    mov 寄存器 ,内存单元mov ax,[0]
    mov 内存单元,寄存器mov [0],ax
    mov 段寄存器,寄存器mov ds,ax
    • 既然有“mov 段寄存器,寄存器”,那么合理设想有相反的通路:“mov 寄存器,段寄存器”:

      在这里插入图片描述

      如图证明猜测成立

    • 既然有“mov 内存单元,寄存器”,那么合理设想有相反的通路:“mov 内存单元,段寄存器”:

    在这里插入图片描述

    如图证明猜测成立

  • add和sub指令可以有以下几种形式:

    表现形式示例
    add 寄存器,数据add ax,8
    add 寄存器,寄存器add ax,bx
    add 寄存器,内存单元add ax,[0]
    add 内存单元,寄存器add [0],ax
    sub 寄存器,数据sub ax,9
    sub 寄存器,寄存器sub ax,bx
    sub 寄存器,内存单元sub ax,[0]
    sub 内存单元,寄存器sub [0],ax

3.5 数据段

  • 对于8086PC机,可以根据需要,将一组内存单元定义为一个段。比如用123B0H123B9H这段内存空间来存放数据,我们就可以认为,123B0H123B9H这段内存是一个数据段,它的段地址为123BH,长度为10个字节

  • 将一段内存当作数据段,是我们在编程时的一种安排,可以在具体操作的时候,用ds存放数据段的段地址,在根据需要,用相关指令访问数据段中的具体单元

3.6 栈

  • 栈是一种具有特殊的访问方式的存储空间,它的特殊性就在于,后进先出
    • 栈就相当于一个盒子,入栈就是将一个新元素放入盒子里(将新元素放入栈顶),出栈就是将盒子里最上面那个元素取出(去除栈顶的一个元素)

3.7 CPU提供的栈机制

  • 8086CPU中也有栈的设计,8086CPU提供相关的指令来以栈的方式访问内存空间,这意味着,在基于8086CPU编程的时候,可以将一段内存当作栈来使用

  • 8086CPU提供入栈和出栈指令,最基本的便是:PUSH(入栈)、POP(出栈),入栈和出栈操作都是以字节为单位进行的,如图是一段指令执行的过程:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-scqSxBlN-1637926496478)(C:\Users\86133\AppData\Roaming\Typora\typora-user-images\image-20211126104916959.png)]

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

      • CS、IP中存放着当前指令的段地址和偏移地址
    • CPU如何知道栈顶的位置?

      • 8086CPU中,有两个寄存器,段寄存器SS和寄存器SP,栈顶的段地址存放在SS中,偏移地址存放在SP中,任意时刻,SS:SP指向栈顶元素,push指令和pop指令执行时,CPU从SS和SP中得到栈顶的地址

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

        • (1)SP=SP-2,SS:SP指向当前栈顶前面的单元,以当前栈顶元素的单元为新的栈顶;
        • (2)将ax中的内容送入SS:SP指向的内存单元处,SS:SP此时指向新栈顶

        [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZQHpMi42-1637926496479)(C:\Users\86133\AppData\Roaming\Typora\typora-user-images\image-20211126105919387.png)]

        • 由此我们可以看出,8086CPU中,入栈时,栈顶从高地址向低地址方向增长
  • 如果将10000H~1000FH这段空间当作栈,初始状态栈是空的,此时SS=1000H,SP=10010H

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xrlMRswH-1637926496481)(C:\Users\86133\AppData\Roaming\Typora\typora-user-images\image-20211126111840694.png)]

    栈空的时候,SS:SP指向占空间最高地址单元的下一个单元

    • 对于pop操作,pop ax的执行过程与push ax刚好相反,由以下两部完成
      • 将SS:SP指向的内存单元处的数据送入ax中
      • SP = SP+2,SS:SP指向当前栈顶下面的单元,以当前栈顶下面的单元为新的栈顶

3.8 栈顶超界问题

虽然push和pop指令实现了入栈和出栈,但是,还有一个问题需要讨论:依靠SS和SP可以保证在入栈和出栈时找到栈顶。但是,如何保证在入栈、出栈时,栈顶不会超出栈空间?

  • 将10010H~1001FH当作占空间,该栈空间容量为16字节(8字节),初始状态为空,SS=1000H、SP=0020H,往栈中不断压入数据直至栈满:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Imry3i7c-1637926496483)(file:///C:\Users\86133\Documents\Tencent Files\2972374129\Image\C2C\Image1\JDCTS23QD28UK{[WFXX59ZA.png)]

    • 如上图,执行8次push此操作之后,再次执行ax:SP=SP-2,SS:SP指向1000EH,栈顶超出了栈空间,ax中的数据送入1000E处,将栈空间外的数据覆盖

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QlSFjZHJ-1637926496484)(C:\Users\86133\AppData\Roaming\Typora\typora-user-images\image-20211126134107100.png)]

    • 在执行8次pop ax后,从栈中弹出8个字,栈空,SS:SP指向10020H,再次执行pop ax:sp=sp+2,SS:SP指向10022H,栈顶超出了栈空间,此后,如果再执行push指令,100020H、10021H中的数据将被覆盖
  • 由上可以看出,无论是当栈满的时候再使用push指令入栈,或栈空的时候再使用pop指令出栈,都将发生栈顶超界问题

  • 栈顶超界时十分危险的,因为我们既然将一段空间安排为栈,那么再栈空间之外的空间里很可能存放了具有其他用途的数据、代码等,这些数据、代码可能是我们自己程序中的,也可能是别的程序中的。但是由于我们在入栈出栈的时候的不小心,而将这些数据、代码以外的改写,将会引发一连串的错误

  • 事实上8086CPU中并不存在记录栈顶上限和栈底的寄存器,所以8086CPU并不能帮我们通过记录栈顶和站地来替我们解决这个问题

  • 8086CPU只知道栈顶在何处,而不知道我们安排的栈空间有多大,就像CPU只知道当前要执行的指令在何处,而不知道要执行的指令有多少。由此我们可以看出8086CPU的工作机理,它只考虑当前的情况:当前的栈顶在何处,当前要执行的指令是哪一条

3.9 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处
    
  • 例题1:

    编程:

    (1)将1000H~1000FH这段空间当作栈,初始状态栈是空的

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

    (3)将AX、BX中的数据入栈

    (4)然后将AX、BX清零

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

    mov ax,1000H
    mov ss,ax
    mov sp,0010H
    
    mov ax,001AH
    mov bx,001BH
    
    push ax
    push bx
    
    sub ax,ax
    sub bx,bx
    
    pop bx
    pop ax
    
  • 例题2:

    编程:

    (1)将10000H~1000FH这段空间当作栈,初始状态栈是空的

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

    (3)利用栈,交换AX和BX中的数据

    mov ax,1000H
    mov ss,ax
    mov sp,0010H
    
    mov ax,001AH
    mov bx,001BH
    
    push ax
    push bx
    pop ax
    pop bx
    

3.10 栈段

  • 在编程时,可以根据需要,将一组内存单元定义为一个段。比如:我们将10010H~1001FH这段长度为16字节的内存空间当作栈来用,以栈的方式进行发个文。这段空间就可以称为一个栈段,段地址为1001H,大小为16字节
  • 我们可以将一段内存定义为一个段:
    • 可以用一个段存放数据,将它定义为“数据段”
      • 对于数据段:段地址存放在DS中,用mov、add、sub等访问内存单元的指令时,CPU就将数据段中的内容当作数据来访问
    • 可以用一个段存放代码,将它定义为“代码段”
      • 对于代码段:段地址存放在CS中,将段中第一条指令的偏移地址放在IP中,这样CPU就将执行我们定义的代码段中的指令
    • 可以用一个段当作栈,将它定义为“栈段”
      • 对于栈段:段地址存放在SS中,栈顶单元的偏移地址放在SP中,通过push、pop等指令,就将我们定义的栈段当作栈空间使用
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值