一步步编写操作系统 13 栈

栈到底是什么玩意

cpu中有栈段SS寄存器和栈指针SP寄存器,它们是用来指定当前使用的栈的物理地址。换句话说,要想让cpu运行,必须得有栈。栈是什么?干吗用的?本节将给大家一个交待。

还记得数据结构中的栈吗?那是逻辑上的数据存取结构,是种如何用这种数据结构来存取数据的描述。在用户进程空间中,堆是堆,栈是栈,但堆栈却是人们常说的栈,和堆没关系,所以,咱们后面为避免混淆,只说栈。

栈是线性表的一种,什么是线性表?如果提出这样的问题,我想您可能不清楚什么是线性。线性就是具有线的性质,就像一条线一样,连续性强,从一个方向到另一个方向。线上没有面积的概念,不管是直线还是曲线,在线上任意位置只能容纳一个数据对象。线性表简而言之就是一个线性存储单元,结构中每个元素都有一个前驱和一个后继元素,且仅各有一个。这就是线性的体现:连续,且任意位置只有一个元素。栈也是这样,不过不同的是,数据的存取都在一端进行,这一端称为栈顶,另一端做为存储单元的基址永远不动,称为栈底。这就是上学时,老师们常常说的后进先出,先放进去的数据要在最后才能取出,后放进去的数据最先被取出。

这里我就不用举汉诺塔这样经典的例子了,毕竟上学时都听得太多了。我说个大家都认同的事实:大家肯定挤过公交车吧(坐过公交车的同学继续看,土豪随意^_^),尤其是早班车和末班车,车厢里人挤人,站都站不稳。先挤上车的乘客其实很倒霉的(有座儿不算^_^),因为他要在最后下车,在拥挤的车厢中折磨的时间最长。后挤上车的乘客在下车的时候还是蛮爽的,因为他会是第一个下车,是率先逃出恶劣环境的人。所以,挤公交车就是典型的后进先出。车厢就相当于栈,乘客就相当于栈中存取的元素,这个例子其实还算生动。

举的例子虽然很常见,但这对于已经理解栈的同学来说,我像是在说废话一样没新意。对于不理解栈的同学来说,可能是依然像说废话一样,说了也意会不到栈是什么。我非常理解这种心情,记得当初我在学网络时,老师说只要在路由器上把三层(网络层)IP协议(不是指令指针寄存器IP)禁用,四层(传输层)上的tcp或udp协议自然就不可用了。老师为了让我们明白这种依赖关系,甚至不惜举出这样的例子:如果不想让某人说话 ,最简单的办法就是给让其睡着,而不是劝他保护安静。这个例子非常浅显易懂,但用例子来理解理论知识,依然让我有点摸不着头脑,这可不是比喻恰不恰当的事,知识是严谨的,不是比喻出来的。如果您现在也有这样的体会,没关系,以后会不断接触栈的,熟了自然就理解了,这只是时间问题。

初次学习数据结构时,不容易理解其本质,我当初在学习这门课时,感觉云里雾里的,似乎明白似乎又不懂,老师让不懂的同学提问,我又不知道该怎样描述问题,不知道哪里不懂。同样的定义,同样的文字描述,每个人理解的都不一样。就像鱼和小鸟,鱼认为自己离开水就会死,水就是生命,小鸟也认为没水会渴死,水也是生命。但鱼和小鸟对水的理解能一样吗?赶紧回来,还是说咱们的正事。栈只是一种抽象概念,是一种虚拟出来的数据存取方法。其实现形式是不限的,只要满足栈的定义就可以:

  • λ首先得是线性结构,并且数据的存取在线性结构的一端进行。如果您愿意,可以用链表来实现,也可以用数组来实现,它们都是线性数据结构。
  • λ其次需要维护一个指针,用它来指向线性结构的一端,数据存取都通过此指针。

前面又比喻又回忆的,说了这么多,栈能够干什么呢?栈是一种很伟大的发明,可以解决很多难题:

  • λ表达式计算,如中缀表达式和后缀表达式的转换
  • λ函数调用,无论是嵌套调用或递归调用,用来维护返回地址。
  • λ深度优先搜索算法

到现在为止,我们说的只是数据结构中的栈,这是逻辑上的,最终我想表达的是内存中的栈,这是物理上的。把数据结构中的栈的概念用物理硬件来实现,这就是我们要说的栈。它同数据段、代码段一样,是个内存中的区域。也就是栈段寄存器SS和栈指针SP所指向的内存区域。我们常听说的栈溢出,指的就是这个内存区域无法容纳数据了。

硬件是如何实现这个栈的呢?还是那句话,首先得满足栈的概念,具备栈的特性,即使是硬件也不能例外,必须满足上面提到的这两个条件:一个是线性结构,一个是在栈顶对数据存取。因为它毕竟造的是栈,不具备这些就不叫栈了。

线性结构这个简单,内存就是,直接用物理内存存取最方便了,咱们要做的,就是给栈指定一片内存区域就成了,区域的起始地址做为栈基址,存入栈基址寄存器SS中,另一端是动态变化的,用栈指针寄存器SP来指定。栈在使用过程中是向下扩展的,所以栈顶地址肯定是小于栈底地址。

栈既然是一片内存区域,访问内存就要用“段基址:段内偏移地址”的形式,所以栈中的内存地址也是用“段基址SS的值*16+栈指针SP(段内偏移地址)形成的20位地址”访问到的。由于是硬件实现的栈,故硬件提供了相应的方法来存取栈,即push和pop指令。push指令负责把数据压入栈,pop指令功能相反,将其从栈中取出。不过我刚才说的不全面,栈的出口和入口都是栈顶,push把数据压向哪里,它得知道栈顶在哪里才行。pop指令也一样,它得知道哪里是栈顶才能从栈中取出正确的数据。这正是栈指针寄存器SP的作用,此寄存器中的值是段内偏移地址,是栈顶相对于栈底的偏移量。

栈顶(SP指针)是栈的出口和入口,它指向的内存中存储的始终是最新的数据。push和pop就是操作这个指针所指向的内存。由于栈是从高地址向低地址发展,所以栈顶、栈指针指向的地址会越来越低。push压入数据的过程是:先将SP减去字长,目的是避免将栈顶的数据破坏,所得的差再存入SP,栈顶在此被更新,这样栈顶就指向了栈中下一个存储单元的位置。再将数据压入SP(新的栈顶)指向的新的内存地址。pop指令相反,既然是在栈中弹出数据,栈指针寄存器SP的值应该是增大一个数据单位。由于要弹出的数据就在当前栈顶,所以在弹出数据后,才将SP加上字长,所得的和再存入SP,从而更新了栈顶。这样SP就指向了上一个存储单元的位置。

上面提到的字长,是指cpu的字长,即一次可处理的数据的长度。在实模式下的字长是16。

物理内存中的栈如图:

 

注意啦,如图所示,虽然栈是向下发展,但栈也是内存,访问内存依然是从低地址往高地址,假如当前栈顶是0x1233E,栈顶数据占2字节的话,其范围是0x1233E~0x1233F。个人觉得,这个硬件中的栈让人感到神秘,主要有两方面原因:

一方面是栈指针不是自己维护,这不像咱们在高级语言中自己创建的栈那样,指针的一举一动都是自己在操作。不直接受控的东西往往让人心存忧虑和有点小恐慌。其实即使是这里的硬件栈,咱们也可以自己维护指针,如push ax可以这样代替:

mov bp,sp
sub bp, 2
mov [bp],ax

bp默认的段寄存器就是SS,用bp的时候直接操作的便是栈。bp就相当于栈指针啦,自己维护毕竟太麻烦,有直接省事的干吗不用呢^_^。

另一方面,栈就是一片内存区域,只不过“经常”操作这片内存的指令不是mov,而是push、pop,这两条指令无非是自动维护存取数据的位置(SP寄存器的值)而已,大家用mov来操作这片内存,不是也得要给出存取地址吗。这样看来,它和普通的数据段没什么不同,不要觉得它比金字塔还神秘啦。

一定要注意,push和pop操作是要成对出现的,这样才能维护栈平衡。否则,光push,不pop,有进没出,这栈很快就溢出啦。切记,一个push要对应一个pop,每键入一个pop指令,一定要清楚它对应的是哪个push。

栈就先说这么多,不摸索实际东西的话还是不能真正掌握和理解,本书强调实践,纸上谈兵可来不了真知识。

好啦,官人常来玩哦

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

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

相关文章

【2019牛客暑期多校训练营(第二场)- E】MAZE(线段树优化dp,dp转矩阵乘法,线段树维护矩阵乘法)

题干: 链接:https://ac.nowcoder.com/acm/contest/882/E?&headNavacm 来源:牛客网 Given a maze with N rows and M columns, where bijb_{ij}bij​ represents the cell on the i-row, j-th column. If bi,j"1"b_{i, j} …

Apollo进阶课程⑰丨Apollo感知之旅——传感器选择和安装

目录 1.激光雷达 2.相机 3.Radar毫米波 4.安装传感器 原文链接:进阶课程⑰丨Apollo感知之旅——传感器选择和安装 上周阿波君为大家详细介绍了「进阶课程⑯ Apollo感知之旅——感知概况」。 传感器是一种检测装置,能感受到被测量的信息,…

2.2)深度学习笔记:优化算法

目录 1)Mini-batch gradient descent(重点) 2)Understanding mini-batch gradient descent 3)Exponentially weighted averages 4)Understanding exponetially weighted averages 5)Bias c…

Apollo进阶课程⑱丨Apollo感知之旅——传感器标定

目录 传感器标定 标定的目的 传感器标定算法 标定案例解析 3D标定间制作 Cmaera-to-Camera外参标定 Lidar-to-Camera外参标定 Lidar-to-Lidar外参标定 Lidar内参标定 Lidar-to-GPS外参标定 自然场景的Lidar-to-Camera外参标定 自然场景的Bifocal Camera外参标定 C…

一步步编写操作系统 15 CPU与外设通信——IO接口,下

既然都说到IO接口了,不知道各位有没有疑问,cpu是怎样访问到IO接口呢?肯定得有个链路吧?什么?有隐约听到有同学开玩笑说:cpu用无线访问其它设备。哈哈,不知道各位听说过没有,无线的终…

Telnet端口连接Linux服务器失败

在ubuntu写了个服务器端口号是666 ,ip地址是192.168.96.129 在windows用telnet无法连接上 首先检查windows telnet服务是否打开 Windows 10操作系统上使用telnet命令(图文)_时间-CSDN博客_windows使用telnet命令 测试网络是否通:…

重磅 | 完备的 AI 学习路线,最详细的资源整理!

本文转自微信公众号:Datawhale(强烈推荐) 原创: AIUnion Datawhale 今天 【导读】 本文由知名开源平台,AI技术平台以及领域专家:Datawhale,ApacheCN,AI有道和黄海广博士联合整理贡献…

Windows/Linux 下使用telnet发送消息

Windows下使用telnet 1.首先打开cmd命令行连接上服务器端口 连不上可以参考这篇 Telnet端口连接Linux服务器失败_m0_46480482的博客-CSDN博客 telnnt <ip地址> <端口号> 2. 连接成功后&#xff0c;会发现是一片黑的 按住 ctrl ] 可以招出提示 输入 &#x…

Apollo进阶课程⑲丨Apollo感知之旅——感知算法

目录 点云感知 启发式方法&#xff1a;NCut 深度学习方法&#xff1a;CNNSeg 视觉感知 CNN检测 CNN分割 后处理 红绿灯感知 基于深度学习的红绿灯感知模块 Radar感知 超声波感知 原文链接&#xff1a;进阶课程⑲丨Apollo感知之旅——感知算法 感知是自动驾驶的第一环…

动手学PaddlePaddle(0):新版本PaddlePaddle安装

目录 0.引言 1.环境 2.Windows下安装 安装Python 安装PaddlePaddle 0.引言 今天介绍如何安装新版本的PaddlePaddle&#xff0c;现在最新版的PaddlePaddle是指Fluid版&#xff0c;Fluid可以让用户像Pytorch和TensorFlow Eager Execution一样执行程序&#xff0c;也就是说P…

一步步编写操作系统 18 操作显卡,显存,显示器 下

接上回&#xff0c;大家看下显卡各种模式的内存分布。 各外部设备都是通过软件指令的形式与上层接口通信的&#xff0c;显卡&#xff08;显示适配器&#xff09;也不例外&#xff0c;所以它也有自己的bios。位置是0xC0000到0xC7FFF。显卡支持三种模式&#xff0c;文本模式、黑白…

VMware 安装VMware Tools

想要在linux和windows之间复制粘贴&#xff0c;把之前一直没有下的vmwaretools的下载过程记录一下。 1.左上角菜单 ->虚拟机 ->安装 vmware tools (我已经点过了所以是取消安装) 2.桌面多了一个VMware tools &#xff0c;点进去看一下位置&#xff0c;复制一下tar.gz的文…

Apollo进阶课程⑳丨Apollo感知之旅——机器学习与感知的未来

目录 1机器学习 可解释性是否需要 其它算法 2感知的未来 Sensor迭代 深度学习仿真数据AI芯片 智能交通设施 3思考 原文链接&#xff1a;进阶课程⑳丨Apollo感知之旅——机器学习与感知的未来 自动驾驶感知中的机器学习最大问题在于系统对模块的要求与普通的机器学习不同…

一步步编写操作系统 19 改进MBR,直接操作显卡

到目前为止&#xff0c;说了一部分有关显存的内容&#xff0c;这对于一般的输出来说已经足够了&#xff0c;下面咱们可以尝试写显存啦。我们将之前MBR改造一下&#xff0c;保留滚屏的操作&#xff0c;只修改有关输出的部分。即把通过bios的输出改为通过显存&#xff0c;你会发现…

Apollo进阶课程㉑丨Apollo规划技术详解——Basic Motion Planning and Overview

原文链接&#xff1a;进阶课程㉑丨Apollo规划技术详解——Basic Motion Planning and Overview 运动规划&#xff08;Motion Planning&#xff09;就是在给定的位置A与位置B之间为机器人找到一条符合约束条件的路径。这个约束可以是无碰撞、路径最短、机械功最小等。具体的案例…

ROS机器人导航仿真(kinetic版本)

准备工作&#xff1a; ubuntu 16.04系统;ROS kinetic版本;ROS包turtlebot,导航包rbx1,模拟器arbotix&#xff0c;可视化rviz 1、安装ubuntu 16.04系统与安装ROS kinetic版本自行百度安装。一下链接可作为参考。 http://blog.csdn.net/weicao1990/article/details/52575314 2…

1.深度学习练习:Python Basics with Numpy(选修)

本文节选自吴恩达老师《深度学习专项课程》编程作业&#xff0c;在此表示感谢。 课程链接&#xff1a;https://www.deeplearning.ai/deep-learning-specialization 目录 1 - Building basic functions with numpy 1.1 - np.exp(), sigmoid function 1.2 - Sigmoid gradient …

一步步编写操作系统 20 x86虚拟bochs一般用法 上

bochs一般用法 bochs是一个开源x86 虚拟机软件。在它的实现中定义了各种数据结构来模拟硬件&#xff0c;用软件模拟硬件缺点是速度比较慢&#xff0c;毕竟全是软件来模拟&#xff0c;您想&#xff0c;虚拟机还要在软件中模拟各种中断&#xff0c;能不慢吗。不过它的功能非常强…

2.3)深度学习笔记:超参数调试、Batch正则化和程序框架

目录 1&#xff09;Tuning Process 2&#xff09;Using an appropriate scale to pick hyperparameters 3&#xff09;Hyperparameters tuning in practice: Pandas vs. Caviar 4&#xff09;Normalizing activations in a network&#xff08;重点&#xff09; 5&#xf…

2.深度学习练习:Logistic Regression with a Neural Network mindset

本文节选自吴恩达老师《深度学习专项课程》编程作业&#xff0c;在此表示感谢。 课程链接&#xff1a;https://www.deeplearning.ai/deep-learning-specialization/ You will learn to: Build the general architecture of a learning algorithm, including: Initializing para…