内存访问与栈

news2024/11/23 5:04:39

内存访问与栈

  • 1 内存分段
  • 2 DS和[address]
  • 3 mov、add、sub指令形式
  • 4 栈
    • 4.1 入栈与出栈
    • 4.2 SS与SP
    • 4.3 空栈
    • 4.4 栈顶超界
    • 4.5 push、pop指令
  • 5 小结

本文属于《 X86指令基础系列教程》之一,欢迎查看其它文章。

1 内存分段

在x86程序执行时,内存会被分段,每个段(segment)都有其特定的用途。以下是常见的几个段:

  • 代码段(Code Segment):代码段,也被称为文本段,是存储程序代码的地方。这通常包括二进制指令,也就是CPU执行的机器代码。
  • 数据段(Data Segment):数据段是用于存储程序中定义的数据的位置,包括变量、数组等。这些数据在编译时被确定并存储在可执行文件或DLL中。当程序运行时,这些数据被加载到内存中,并分配给对应的内存地址。
  • 堆(Heap):堆是动态分配内存的地方,也就是说,当程序运行时,它可以在需要更多内存时向操作系统请求额外的内存,并在不再需要时将其释放。
  • 栈(Stack):栈用于存储局部变量和函数调用的信息。每当函数被调用时,都会在堆栈上创建一个新的栈帧,包含函数的局部变量、参数和返回地址。当函数返回时,其对应的栈帧被从堆栈中弹出。
  • 未初始化数据段(Uninitialized Data Segment):也被称为BSS段,在程序开始执行之前,操作系统会将此段的内容初始化为零或空指针。这个段用于存储全局变量和静态变量,这些变量在程序开始运行之前不需要明确赋值。

以上这些分段的方式是操作系统和编译器为了更好地组织和管理内存而采取的一种策略。

2 DS和[address]

  • DS (Data Segment):数据段寄存器,保存了数据段地址。
  • [address]:内存单元的偏移地址。

CPU要读写一个内存单元的时候,必须先给出这个内存单元的地址,在8086PC中,内存地址由段地址偏移地址组成。8086CPU中有一个DS寄存器,通常用来存放要访问数据的段地址。比如我们要读取10000H单元的内容,可以用如下的程序段进行。

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

“[…]”表示一个内存单元, “[…]”中的0 表示内存单元的偏移地址。指令执行时,8086CPU 自动取 ds 中的数据为内存单元的段地址。
mov ds,1000H 这条指令是非法的。因此,先将1000H放入bx寄存器,再把bx寄存器放入ds,执行“mov al, [0]”时,从DSx16+0地址,也就是从10000H读取数据,放入al中。由于al为8位,因此从10000H读取的长度为1字节,放入al中。
看看以下指令执行结果,与寄存器值变化,如下所示:
在这里插入图片描述

3 mov、add、sub指令形式

到现在,我们知道, mov指令可以有以下几种形式。

mov 寄存器,数据			比如:mov ax,8
mov 寄存器,寄存器		比如: mov ax,bx
mov 寄存器,内存单元		比如:mov ax,[0]
mov 段寄存器,内存单元	比如:mov ds,[0]
mov 内存单元,寄存器		比如:mov [0],ax
mov 内存单元,段寄存器	比如:mov [0],cs
mov 段寄存器,寄存器		比如:mov ds,ax
mov 寄存器,段寄存器		比如:mov ax,ds

add和sub指令同mov一样,都有两个操作对象。它们也可以有以下几种形式。

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

4 栈

4.1 入栈与出栈

栈有两个基本的操作:入栈和出栈。入栈就是将一个新的元素放到栈顶,出栈就是从栈顶取出一个元素。栈顶的元素总是最后入栈,需要出栈时,又最先被从栈中取出。栈的这种操作规则被称为: LIFO(Last InFirst Out,后进先出)。

现今的 CPU中都有栈的设计, 8086CPU也不例外。8086CPU提供相关的指令来以栈的方式访问内存空间。这意味着,在基于8086CPU编程的时候,可以将一段内存当作栈来使用。
8086CPU提供入栈和出栈指令,最基本的两个是PUSH(入栈)和POP(出栈)。比如:

  • push ax表示将寄存器ax中的数据送入栈中;
  • pop ax表示从栈顶取出数据送入ax。

8086CPU的入栈和出栈操作都是以字为单位进行的。
查看以下,入栈出栈指令执行过程:
在这里插入图片描述
在这里插入图片描述

4.2 SS与SP

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

现在,我们可以完整地描述push和pop指令的功能了,例如push ax。
push ax 的执行,由以下两步完成。

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

下图,描述了8086CPU对push指令的执行过程。
在这里插入图片描述
从图中我们可以看出,8086CPU中,入栈时,栈顶从高地址向低地址方向增长。

4.3 空栈

栈为空,就相当于栈中唯一的元素出栈,出栈后,SP=SP+2, SP原来为000EH,加2后SP=10H,所以,当栈为空的时候, SS=1000H,SP=10H。
在这里插入图片描述
接下来,我们描述pop指令的功能,例如pop ax。
pop ax的执行过程和push ax刚好相反,由以下两步完成。

  • (1)将SS:SP指向的内存单元处的数据送入ax中;
  • (2) SP=SP+2, SS:SP指向当前栈顶下面的单元,以当前栈顶下面的单元为新的栈顶。

4.4 栈顶超界

下图,描述了在执行push指令后,栈顶超出栈空间的情况。
将10010H-1001FH当作栈空间,该栈空间容量为16字节(8字),初始状态为空, SS=1000H,SP=0020H, SS:SP指向10020H;在执行8次push ax后,向栈中压入8个字,栈满, SS:SP指向10010H;再次执行push ax: sp-sp-2, SS:SP 指向 1000EH,栈顶超出了栈空间, ax 中的数据送入1000EH单元处,将栈空间外的数据覆盖。
在这里插入图片描述
出栈时,也是类似的情况。可以看到,当栈满的时候再使用push指令入栈,或栈空的时候再使用pop指令出栈,都将发生栈顶超界问题。
我们在编程的时候,要自己操心栈顶超界的问题,要根据可能用到的最大栈空间,来安排栈的大小,防止入栈的数据太多而导致的超界;执行出栈操作的时候也要注意,以防栈空的时候继续出栈而导致的超界。

4.5 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]			;出栈,出栈的数据送入1000:2

5 小结

mov、add、sub和push、pop指令形式。

栈:

  • (1)8086CPU提供了栈操作机制,方案如下。
    SS、SP 中存放栈顶的段地址和偏移地址;提供入栈和出栈指令,它们根据SS:SP指示的地址,按照栈的方式访问内存单元。
  • (2)push指令的执行步骤: ①SP=SP-2;②向SS:SP 指向的字单元中送入数据。
  • (3)pop指令的执行步骤:①从SS:SP指向的字单元中读取数据;②SP=SP+2。
  • (4)任意时刻, SS:SP 指向栈顶元素。
  • (5)8086CPU只记录栈顶,栈空间的大小我们要自己管理。
  • (6)用栈来暂存以后需要恢复的寄存器的内容时,寄存器出栈的顺序要和入栈的顺序相反。
  • (7)push、pop实质上是一种内存传送指令,注意它们的灵活应用。

内存分段有数据段、代码段、堆、栈、未初始化数据段:

  • 我们可以用一个段存放数据,将它定义为“数据段”;
  • 我们可以用一个段存放代码,将它定义为“代码段”;
  • 我们可以用一个段当作栈,将它定义为“栈段”。

我们可以这样安排,但若要让CPU按照我们的安排来访问这些段,就要:

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

可见,不管我们如何安排, CPU将内存中的某段内容当作代码,是因CS:IP指向了那里; CPU将某段内存当作栈,是因为SS:SP指向了那里。我们一定要清楚,什么是我们的安排,以及如何让CPU按我们的安排行事。要非常清楚CPU的工作机理,才能在控制CPU按照我们的安排运行的时候做到游刃有余。


参考文档:

  • 《汇编语言 第3版》 王爽 清华大学出版社

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1098333.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

微信小程序的框架

目录 一、视图层 1. WXML 数据绑定 列表渲染 条件渲染 模板 2. WXSS 尺寸单位 样式导入 内联样式 选择器 3. WXS事件 二、逻辑层 1. 页面生命周期 2.跳转 1. 一级跳一级 2. 一级跳二级 3. 二级跳二级 4. 二级跳一级 总结 带给我们的收获 一、视图层 1. …

竞赛 深度学习YOLOv5车辆颜色识别检测 - python opencv

文章目录 1 前言2 实现效果3 CNN卷积神经网络4 Yolov56 数据集处理及模型训练5 最后 1 前言 🔥 优质竞赛项目系列,今天要分享的是 🚩 **基于深度学习YOLOv5车辆颜色识别检测 ** 该项目较为新颖,适合作为竞赛课题方向&#xff0…

微信小程序使用阿里巴巴iconfont,报错Failed to load font http://at.alicdn.com/t/..........

介绍 上篇文章,介绍了,在微信小程序里导入并使用阿里巴巴iconfont图标;但是在页面里使用后,可以看到后台日志有打印错误信息,具体报错如下: 分析 报这个错,是因为项目里使用了 iconfont字体…

OpenCV15-图像边缘检测:Sobel、Scharr、Laplace、Canny

OpenCV15-图像边缘检测:Sobel、Scharr、Laplace、Canny 1.边缘检测原理2.Sobel算子3.Scharr算子4.生成边缘检测滤波器5.Laplacian算子6.Canny算法 1.边缘检测原理 图像的边缘指的是图像中像素灰度值突然发生变化的区域,如果将图像中的每一行像素和每一列…

功能集成,不占空间,同为科技TOWE嵌入式桌面PDU超级插座

随着现代社会人们生活水平的不断提高,消费者对生活质量有着越来越高的期望。生活中,各式各样的电气设备为我们的生活带来了便利,在安装使用这些用电器时,需要考虑电源插排插座的选择。传统的插排插座设计多暴露于空间之中&#xf…

直播美颜技术的技术背后:美颜SDK的原理与实践

对于美颜美颜SDK来说大家都不会陌生,通过它,我们能够实现实时美颜效果,改善视频质量,吸引更多观众。 一、美颜SDK是什么? 美颜SDK为开发者提供了一整套美颜和图像处理功能,用于实时处理直播视频流。这个工…

Android USB分析

先下一个定论,常规来讲,所有作slave的android设备都是配件,作为主机的android设备还是叫Host。此外还有usb tethering支持的radnis功能以及ncm功能,这两个是网络相关的usb应用,使用usb模拟网卡。其中radnis属于上网能力…

如何减轻软件测试的时间压力?6大注意事项

软件测试处于软件研发流程的下游。如果上游的项目进度延迟,往往会遇到通过压缩测试时间来按时交付的情况。 因此软件测试人员经常遇到时间压力,可能会为了赶时间草率测试,导致测试人员无法充分地测试所有功能和场景,影响测试的覆盖…

如何制作有专业水准的的电子杂志:专家教你秘籍

​随着数字化时代的到来,电子杂志作为一种新型的传媒形式,越来越受到人们的关注和喜爱。但是,如何制作一份具有专业水准的电子杂志呢? 今天,给大家分享一款在线就能制作的电子杂志------FLBOOK,让你轻松打造…

【mac】常用命令01

1、如何像windows一样看磁盘? 不断的在上层文件夹显示,找到最上层,拖拽到左侧,方便之后找 2、Macintosh HD显示隐藏文件夹方法 终端窗口: defaults write com.apple.finder AppleShowAllFiles true killall Finder 或者…

Java发起Soap请求

目录 1.前言2.请求报文格式2.1不带表头的请求格式2.2带表头的请求格式 3 请求代码实例3.1解析Soap返回的XML,提取需要的元素 参考 文章所属专区 超链接 1.前言 SOAP请求(Simple Object Access Protocol,简单对象访问协议)是HTTP…

CEC2013(MATLAB):猎豹优化算法(The Cheetah Optimizer,CO)求解CEC2013

一、猎豹优化算法CO 猎豹优化算法(The Cheetah Optimizer,CO)由MohammadAminAkbari等人于2022年提出,该算法性能高效,思路新颖。 参考文献: Akbari, M.A., Zare, M., Azizipanah-abarghooee, R. et al. Th…

word误删除的文件怎么恢复?恢复办法分享

在日常工作和学习中,我们常常会使用到Word来撰写文章、毕业论文、方案等。然而,我们可能会遇到Word误删文件的情况,令我们陷入恐慌,特别是这个文件很重要时。幸运的是,有办法找回。下面一起来看下word误删除的文件怎么…

RFID固定资产管理的应用

在如今的商界竞争中,要确保企业的固定资产管理得当至关重要。庆幸的是,现代科技为这一挑战带来了一项高效的解决方案,那就是RFID技术。 **RFID技术就是借助无线射频通信,通过RFID标签和读写器之间的互动,来识别和跟踪资…

【力扣520】检测大写字母

👑专栏内容:力扣刷题⛪个人主页:子夜的星的主页💕座右铭:前路未远,步履不停 目录 一、题目描述二、题目分析 一、题目描述 题目链接:检测大写字母 我们定义,在以下情况时&#xff…

ARM Cortex-A9:裸机开发,点亮LED3

1.看原理图 外设板原理图 核心板原理图 2.在芯片手册中找到控制硬件的有效的特殊功能寄存器 选择0x1输出 GPX1DAT[0]->GPX1_0 0->1/0 3.编程 start.s Makefile复制到桌面 使用超级终端,连接串口 随便写一个 选择串口 配置串口 板子上电马上按enter…

MATLAB | 对随机信号进行统计分析,绘制频次直方图、频率分布图,与理论概率密度进行比较

一、问题描述 对于一个随机信号,我们可以通过统计手段,得到其的频次分布图(直方图),并由此计算出它的频率分布图。当观察次数区域无穷大时,频率分布图近似于概率密度函数。 下面我们以稳定分布的随机变量为…

MySQL多表查询面试题一

其中分析题意,学生表student是与成绩表score关联,课程表course与教师表teacher关联,由此可以先确定关联关系,学生表为s,课程表为c,教师表为t,成绩表为o。s.s_ido.s_id,c.t_idt.t_id …

SpringBoot核心功能与基础配置

SpringBoot简介 原先的Spring程序缺点,包括依赖设置繁琐,每项jar的引用都需要自己撰写。并且配置繁琐,配置文件中也需要自己写加载bean等。由此针对原始的Spring程序,Pivotal团队提供的全新框架——SpringBoot,其设计…

PyQt 定义控件SwitchButton 指南

PyQt 定义控件SwitchButton 指南 PyQt 定义控件SwitchButton 指南实例程序效果如下所示: PyQt 定义控件SwitchButton 指南 SwitchButton 是一个自定义开关按钮控件,通常用于在用户界面中启用或禁用某些功能或选项。它是一种用户友好的控件,允…