汇编语言——寄存器(内存访问 ss栈段寄存器)

摘要:
推送和弹出指令还可以在内存和寄存器中传输数据。8086 CPU的堆栈入和堆栈出操作以字执行。在8086 CPU中,有两个寄存器:段寄存器SS存储段地址寄存器SP随时存储堆栈顶部的偏移地址,SS:SP指向堆栈顶部的元素。我们可以将内存段定义为段,使用段地址指示该段,并使用偏移地址访问该段中的单元。

一、栈的基本概念

栈有两个基本的操作:入栈和出栈。
入栈:将一个新的元素放到栈顶;
出栈:从栈顶取出一个元素。
栈顶的元素总是最后入栈,需要出栈时,又最先被从栈中取出。
栈的操作规则:后进先出

8086CPU提供的栈机制

8086CPU提供入栈和出栈指令: (最基本的)
PUSH(入栈)
POP (出栈)
push ax:将寄存器ax中的数据送入栈中;
pop ax :从栈顶取出数据送入ax。

push和pop指令也可以在内存和寄存器传输数据(以栈的形式)
8086CPU的入栈和出栈操作都是以为单位进行的。

示例:

假设将10000H~1000FH这段内存当作栈来使用(其实CPU并不知道这段是代码段,数据段还是栈段,都是人为设定的)
下面一段指令的执行过程:
 mov ax,0123H	 # AX=0123H
 push ax		 # 将AX的值推入栈中
 mov bx,2266H	 # BX=2266H
 push bx		 # 将BX的值推入栈中
 mov cx,1122H	 # CX=1122H
 push cx		 # 将CX的值推入栈中
 pop ax			 # 将栈顶的2个内存单元取出放到AX寄存器中,AX=1122H			
 pop bx			 # 将栈顶的2个内存单元取出放到BX寄存器中,BX=2266H
 pop cx			 # 将栈顶的2个内存单元取出放到CX寄存器中,CX=0123H

那么问题来了,在执行push和pop的时候,如何知道哪个单元是栈顶单元?

8086CPU中,有两个寄存器:

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

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

二、push和pop指令

push 指令的执行过程

在执行push ax指令时,主要做了一下2件事
(1)先将SP=SP–2
(2)将ax中的内容送入SS:SP指向的内存单元处,SS:SP此时指向新栈顶

汇编语言——寄存器(内存访问 ss栈段寄存器)第1张

pop 指令的执行过程

在执行pop ax指令时,主要做了一下2件事
(1)先将SS:SP指向的内存单元处的数据送入ax中;
(2)SP = SP+2,SS:SP指向当前栈顶下面的单元,以当前栈顶下面的单元为新的栈顶。

汇编语言——寄存器(内存访问 ss栈段寄存器)第2张

当栈为空的时候,SS:SP指向最高地址空间的下一位

汇编语言——寄存器(内存访问 ss栈段寄存器)第3张

任意时刻,SS:SP 指向栈顶元素,当栈为空的时候,栈中没有元素,也就不存在栈顶元素,所以SS:SP 只能指向栈的最底部单元下面的单元,该单元的偏移地址为栈最底部的字单元的偏移地址+2,栈最底部字单元的地址为1000:000E,所以栈空时,SP=0010H。

栈顶超界的问题(简单了解就好,我们又不做黑客)

原因:SS和SP只记录了栈顶的地址,依靠SS和SP可以保证在入栈和出栈时找到栈顶

上面我说了,CPU并不知道这段是代码段,数据段还是栈段,都是人为设定的所以加入这个栈空了,我们继续pop,它就会把其它段的数据pop出。所以非常危险

解决办法:一个很NC的办法,就是我们在编程的时候要自己操心栈顶超界的问题 ,要根据可能用到的最大栈空间,来安排栈的大小,防止入栈的数据太多而导致的超界;执行出栈操作的时候也要注意,以防栈空的时候继续出栈而导致的超界。

push和pop指令具体可以操作

# 可以为通用寄存器赋值
push ax
pop bx

# 可以为段寄存器赋值
push ds
pop es

# 可以为内存单元赋值
push [0]
pop [2]

示例:

1、将10000H~1000FH 这段空间当作栈,初始状态是空的,将 AX、BX、DS中的数据入栈。

汇编语言——寄存器(内存访问 ss栈段寄存器)第4张

2、编程

(1)将10000H~1000FH 这段空间当作栈,初始状态是空的;
(2)设置AX=001AH,BX=001BH;
(3)将AX、BX中的数据入栈;
(4)然后将AX、BX清零;
(5)从栈中恢复AX、BX原来的内容。

汇编语言——寄存器(内存访问 ss栈段寄存器)第5张

3、编程:

(1)将10000H~1000FH 这段空间当作栈,初始状态是空的;
(2)设置AX=002AH,BX=002BH;
(3)利用栈 ,交换 AX 和 BX 中的数据。

 汇编语言——寄存器(内存访问 ss栈段寄存器)第6张汇编语言——寄存器(内存访问 ss栈段寄存器)第7张

4、补全下面的代码,完成同样的功能:在10000H处写入字型数据2266H。

__________
__________
__________
mov ax,2266H
push ax

mov ax,1000H
mov ss,ax
mov sp,2    # 题目要求的是要将10000H位置写入字形数据,10000H的偏移量是0,在执行push操作的时候回将sp-2,所以我们要把它指向10002H的位置
mov ax,2266H
push ax

栈段

上面说过我们可以定义一段内存单元为代码段,数据段或栈段。

我们可以将一个段空间当做一个栈段,一个栈段最大64K,因为16位CPU的偏移地址最大为2^16B,如果超出FFFF它会重新变成0(FFFF+1=0000,1被抛弃了)。

CPU是如何判断哪块是什么段的?

我们可以将一段内存定义为一个段,用一个段地址指示段,用偏移地址访问段内的单元。这完全是我们自己的安排。
我们可以用一个段存放数据,将它定义为“数据段”;
我们可以用一个段存放代码,将它定义为“代码段”;
我们可以用一个段当作栈,将它定义为“栈段”;
我们可以这样安排,但若要让CPU按照我们的安排来访问这些段,就要:
对于数据段将它的段地址放在 DS中,用mov、add、sub等访问内存单元的指令时,CPU就将我们定义的数据段中的内容当作数据段来访问;

对于代码段将它的段地址放在 CS中,将段中第一条指令的偏移地址放在IP中,这样CPU就将执行我们定义的代码段中的指令;

对于栈段,将它的段地址放在SS中,将栈顶单元的偏移地置放在 SP 中,这样CPU在需要进行栈操作的时候,比如执行 push、pop 指令等,就将我们定义的栈段当作栈空间来用。

可见,不管我们如何安排 ,CPU 将内存中的某段内存当作代码 ,是因为CS:IP指向了那里;CPU将某段内存当作栈 ,是因为 SS:IP 指向了那里。

汇编语言——寄存器(内存访问 ss栈段寄存器)第8张

汇编语言——寄存器(内存访问 ss栈段寄存器)第9张

免责声明:文章转载自《汇编语言——寄存器(内存访问 ss栈段寄存器)》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇js, 树状菜单隐藏显示Dapper2.0.78手册翻译下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

汇编语言(王爽) 第3章寄存器(内存访问)

3.1 内存中的字 内存中的字是16位的,以2个内存单元存储 地址大的存高位(字的左边8位),地址小的存低位(字的右边8位) 字单元:存放1个字形数据的内存单元,由2个内存单元组成,共16位 3.2 DS 一个寄存器的名字,用来放数据段的段地址 mov 指令可以把数据转到寄存器,一个寄存器的内容转到另一个寄存器,内存单元(字单元)转到寄存器 但是一般会mo...

SMBUS的介绍与访问

博文是为了总结自己在bios学习上面的点点滴滴,并且加深印象,由于本人水平有限,难免存在不足之处,望指正,同时感谢CSDN提供的平台。本文主要介绍的是SMBUS。            1  SMBUS的简介                  特点:  SMBUS,System Management BUS,即系统管理总线,1995年,由Intel公司提出...

汇编语言程序设计读书笔记(2)- 相关工具64位系统篇

汇编语言程序设计一书,在32位系统下应该不会有什么问题,然而在64位系统下,则会有些不一样的地方。有些程序范例还会汇编错误或者执行错误。 博主所用系统为CentOS v6.4 x64。本文主要解决32位的汇编程序如何在64位环境下汇编、连接,而不论述64位汇编语言如何设计。 1. 64位系统下编译32位的C程序 以程序test5.c为例,程序代码很简单,如...

[笔记].浅析在Nios II中的两种寄存器映射方法的异同

此处以我所写的MAX7219为范例,从HDL接口描述到C语言软件编程,分析两种表面不一样、但实质是一样的寄存器映射方法,找出其中联系与区别。 方法1 使用Altera提供的API 1. 使用HDL描述Avalon-MM接口 代码1 Amy_S_max7219_avalon_interface.v /*-----版权声明----- * 艾米电子工作室...

[虚拟化/云][全栈demo] 为qemu增加一个PCI的watchdog外设(五)

目的: 1. 了解PCI的基本知识,为完成watchdog的设备做准备。 准备知识: 简单的说,PCI 设备分3个空间。 配置空间,IO空间,内存地址空间。 PCI设备厂家决定了外设是使用IO空间还是IO内存空间。 我们通过读取配置空间的bar寄存器的最低位bit0来决定是该设备使用的是IO空间还是内存地址空间。 计算机一启动,bois或者linux会根据...

【Linux 驱动】第九章 与硬件通信

在学习有关I/O总线的内容时,最好先看看相关的知识:从PC总线到ARM的内部总线 一,I/O 端口和 I/O 内存 每种外设都是通过读写寄存器来进行控制。 大部分外设都有几个寄存器,不管是在内存地址空间还是在I/O地址空间,这些寄存器的访问地址都是连续的。在硬件层,内存区和 I/O 区域没有概念上的区别: 它们都是通过向在地址总线和控制总线发出电平信号来进...