考研408--组成原理--day9--栈帧的访问与切换&CPU

(以下内容全部出自上述课程)

目录

  • 如何访问栈帧
    • [1. 函数调用栈在内存中的位置](#1. 函数调用栈在内存中的位置)
    • [2. EBP、ESP寄存器](#2. EBP、ESP寄存器)
    • [3. push、pop指令](#3. push、pop指令)
    • [4. mov指令](#4. mov指令)
    • [5. 小结](#5. 小结)
  • 如何切换栈帧
    • [1. 调用-切换过程](#1. 调用-切换过程)
    • [2. 返回-切换过程](#2. 返回-切换过程)
    • [3. 小结](#3. 小结)
    • [4. 真题分析](#4. 真题分析)
  • 如何传递参数和返回值
    • [1. 一个栈帧内包含什么?](#1. 一个栈帧内包含什么?)
    • [2. 汇编代码实战](#2. 汇编代码实战)
      • [2.1 访问局部变量](#2.1 访问局部变量)
      • [2.2 传递参数](#2.2 传递参数)
      • [2.3 函数调用](#2.3 函数调用)
      • [2.4 切换栈帧](#2.4 切换栈帧)
      • [2.5 访问参数](#2.5 访问参数)
      • [2.6 传递返回值](#2.6 传递返回值)
      • [2.7 恢复上一层栈帧](#2.7 恢复上一层栈帧)
      • [2.8 函数调用返回](#2.8 函数调用返回)
      • [2.9 传递返回值](#2.9 传递返回值)
    • [3. 小结](#3. 小结)
  • CISC和RISC
  • 小回顾
  • CPU的功能和基本结构
    • [1. CPU的功能](#1. CPU的功能)
    • [2. 运算器和控制器的功能](#2. 运算器和控制器的功能)
    • [3. 运算器的基本结构](#3. 运算器的基本结构)
    • [4. 控制器的基本结构](#4. 控制器的基本结构)
    • [5. CPU的基本结构](#5. CPU的基本结构)
    • [6. 小结](#6. 小结)

如何访问栈帧

前情提要:Call和ret指令

之前Call和ret指令提到栈底在上栈顶在下:

1. 函数调用栈在内存中的位置

函数调用栈通常处于用户栈,地址从上往下依次递减,所以高地址在上面,也就是栈底在上面,低地址在下面,也就是栈顶在下面。

java 复制代码
高地址
+------------------+  ← 栈底(main函数的栈帧,最先入栈)
| main() 栈帧      |
+------------------+
| funcA() 栈帧     |
+------------------+
| funcB() 栈帧     |
+------------------+  ← 栈顶(最新调用的函数,最后入栈)
低地址

2. EBP、ESP寄存器

简单记:EBP-->栈底指针;ESP-->栈顶指针

ps:在后续的一系列操作中,这个指针可能指的不是同一个栈帧

默认4字节为栈的基本单元。

访问-->ebp、esp指针√

3. push、pop指令

push :

  • 可以是立即数、寄存器或者主存地址
  • 先让esp指针向下动一格,再将数据压入栈
  • 所以存数据的位置是当前esp指的下一个格子的位置(空的地方)

pop:

  • 可以是寄存器或者主存地址
  • 先让数据出栈,再让esp指针向上动一格
  • 所以esp最后指向被出栈数据的上一个格子(存数据的地方)

4. mov指令

mov指令就是push和pop指令的结合体

之前我们说过Intel格式中,move A,B 就是把B的值复制给A的意思,可见Intel格式

esp+8\]:因为上面说过高地址在上,默认4字节为栈的基本单位,所以+8就是esp向上动两格的位置的**值**。 * 最开始ebp指向黄色最上面的格子,esp指向从上往下数的第二个黄色格子 * `sub esp,12` 将esp向下移动12/4=3格(灰色esp指向的位置) * `mov [esp+8],eax` 将eax寄存器里面的值211赋值给esp向上移动两个格子的位置的值(图中esp指向的位置) * `mov [esp+4],985` 将985赋值给esp向上移动一个格子的位置的值(211下面的这个格子) * `mov eax,[ebp+8]` 将ebp向上移动两个格子的位置的值复制给eax寄存器(也就是图中eax的666) ![请添加图片描述](https://i-blog.csdnimg.cn/direct/75d09fc13f9349228d2d0d2361f86fb1.jpeg) ### 5. 小结 ![请添加图片描述](https://i-blog.csdnimg.cn/direct/651c5b4be8e640969fd704c8aab815b4.jpeg) ## 如何切换栈帧 ### 1. 调用-切换过程 执行到call add的时候计数指针(ip,就是之前的pc)刚好指到下一个语句 ps:这句话的意思就是ip指针指到这个语句,语句执行的同时ip指向下一个语句(**指到谁谁干活**) * 所以执行call的时候,为了避免数据遗漏,就需要先把指向自己下面的值先存入栈(因为跳到另一个函数后总是要跳回来继续执行的) * 存完ip旧值之后,就可以给ip设置一个新的值让他去处理新函数(就是跳到新函数的第一个语句) ![请添加图片描述](https://i-blog.csdnimg.cn/direct/84a7aaf7bb0d4d7cb857a4c3df85611b.jpeg) ip指针指到push ebp,这条语句就要执行了,与此同时ip指针指向下一个语句: * `push ebp`:把ebp指向位置的地址存入栈 > 大区分!!!!! > > ebp:寄存器本身,即基址指针寄存器(Base Pointer Register)的值,是一个**地址** (32位或64位数值)。 > > \[ebp\]:以 ebp 的值作为内存地址,访问该地址处的内容,即**ebp 指向的内存单元中的值**。 ![请添加图片描述](https://i-blog.csdnimg.cn/direct/57d7bb95ae4b4c36898cfa71df635c3b.jpeg) ip指针刚刚指了mov ebp,esp,所以现在执行这条语句: ![请添加图片描述](https://i-blog.csdnimg.cn/direct/02ea54588c5d426cb1f2d379fa4dc8ad.jpeg) `mov ebp,esp`:把esp的地址值赋值给ebp的地址值(**改变地址** ,所以两个指针如图指向同一个位置): 就这样,两个指针从最初指向绿色的栈帧变为现在指向黄色的栈帧,就这样完成了栈帧的切换。 ![请添加图片描述](https://i-blog.csdnimg.cn/direct/20d926f60c86484789c669398a2d561c.jpeg) 这两句指令等同于一个`enter` 算是例行处理,每个函数前面都有这两句话 ![请添加图片描述](https://i-blog.csdnimg.cn/direct/02e3383d2e3d43de921eebb1f6885c48.jpeg) ### 2. 返回-切换过程 复习调用语句: * `push ebp` * `mov ebp,esp` 返回语句: * `mov esp,ebp` * `pop ebp` 完全就是倒过来 ![请添加图片描述](https://i-blog.csdnimg.cn/direct/3269244ef1394a34bd125be18bb0e5a4.jpeg) ps:这里经过一系列函数内的操作,esp按照原有规律指向栈顶(它是栈顶指针) `mov esp,ebp`:将ebp地址值赋值给esp的地址值,让ebp和esp指向同一个地方 ![请添加图片描述](https://i-blog.csdnimg.cn/direct/829a03e224444228b8651a904d0468fc.jpeg) `pop ebp`:esp指向的元素出栈(看上一个图,就是上一个栈的基址),同时esp向上移动一格(pop指令特性:先出栈再上移) 所以此时esp就完美地从指向黄色的栈帧变为指向绿色的栈帧了 同时,这个元素的值还会被复制到ebp的地址值上,所以ebp就指回了绿色栈帧的栈底(因为是 pop **ebp** ) ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/92f55a12cd1a405cae16810e1b49196e.png) 结束之后就是下面这张图的样子: ![请添加图片描述](https://i-blog.csdnimg.cn/direct/c92e3d71e5d54800a05cad9b294f8844.jpeg) leave指令就是这两句指令的结合体 ![请添加图片描述](https://i-blog.csdnimg.cn/direct/2cc3f5f8941c45c591379de397cfeaae.jpeg) 和调用切换指令相同,都属于例行处理,所以返回的时候都会出现这两句指令,或者是leave ![请添加图片描述](https://i-blog.csdnimg.cn/direct/6bb24787563048969bfcf38352a39ac6.jpeg) 因为我们之前调用的时候把原本函数的ip旧值存入栈了,ret就是帮我们重新找到这个值,然后继续原函数接下来的操作。 ![请添加图片描述](https://i-blog.csdnimg.cn/direct/2b4a1ceb197d49e38cd4edbbd8a78d9c.jpeg) ### 3. 小结 ![请添加图片描述](https://i-blog.csdnimg.cn/direct/afd95c9870bd4eaa8ad6987a72fb9d7a.jpeg) ### 4. 真题分析 ![请添加图片描述](https://i-blog.csdnimg.cn/direct/7acc590426464a89be02c02ae8caec23.jpeg) ![请添加图片描述](https://i-blog.csdnimg.cn/direct/74251a1be5e7460eae4a20aa02780acf.jpeg) ## 如何传递参数和返回值 ![请添加图片描述](https://i-blog.csdnimg.cn/direct/f0e1b65f02c24dfe806e95b1a09c28f6.jpeg) ### 1. 一个栈帧内包含什么? 从上面我们知道了: * 栈帧最**底** 部一定是**上一层栈帧基址**(返回切换时所需) * 栈帧最**顶** 部一定是**返回地址**(返回继续操作原函数所需) 那么中间的位置就是用来存一些函数里的变量和值 ![请添加图片描述](https://i-blog.csdnimg.cn/direct/b4b67afda3e948008262744bd9f2790b.jpeg) * **局部变量** 通常存在栈帧**底**部区域(是自己的就放在最下面,别人拿不走) * **调用参数** 通常存在栈帧**顶** 部区域(是别人需要的就放在最上面,别人方便拿) ![请添加图片描述](https://i-blog.csdnimg.cn/direct/772c3159e6a145f3830384ad5da15793.jpeg) 当然,也不可能全放完,肯定能够会有空闲的位置。 ![请添加图片描述](https://i-blog.csdnimg.cn/direct/2d2ecd261a914d8da94a028d9ef3aa7c.jpeg) 小总结: ![请添加图片描述](https://i-blog.csdnimg.cn/direct/fa2cd7df9a0c4b90b6bc62089ca2bbd2.jpeg) ### 2. 汇编代码实战 #### 2.1 访问局部变量 和上面访问数据一个流程:-XX就往下,+XX就往上,带\[\]的都是指针所指的值 这个栈帧里和ebp相关的都是局部变量 ![请添加图片描述](https://i-blog.csdnimg.cn/direct/fb085004fb8246329865c5dd9a283840.jpeg) #### 2.2 传递参数 这个栈帧里和esp相关的都是参数 ![请添加图片描述](https://i-blog.csdnimg.cn/direct/011e92a3cbe347c1865df1a90c7c4938.jpeg) #### 2.3 函数调用 调用add函数 ![请添加图片描述](https://i-blog.csdnimg.cn/direct/a74daea4fb7e479c9d32f11d5688e311.jpeg) #### 2.4 切换栈帧 和上面**调用切换** 一个流程 ![请添加图片描述](https://i-blog.csdnimg.cn/direct/167af13813eb464f9c8f90e1271ca85d.jpeg) #### 2.5 访问参数 eax和edx访问参数 ![请添加图片描述](https://i-blog.csdnimg.cn/direct/9673507649dd48389bd1e9ed343b6e30.jpeg) #### 2.6 传递返回值 加法运算再把结果放回eax ![请添加图片描述](https://i-blog.csdnimg.cn/direct/77962c1baa6147c58f095e3cb2d15e17.jpeg) #### 2.7 恢复上一层栈帧 和上面**返回切换** 一个流程 ![请添加图片描述](https://i-blog.csdnimg.cn/direct/866f844b1da441a4a67c06327f32b6e4.jpeg) ![请添加图片描述](https://i-blog.csdnimg.cn/direct/8926828a057240919880723033f515ee.jpeg) #### 2.8 函数调用返回 ret就返回为原函数的ip旧值了(call的下一行指令) ![请添加图片描述](https://i-blog.csdnimg.cn/direct/3565918ce91f4814a24eb7b0b8de3239.jpeg) #### 2.9 传递返回值 继续原函数下面的操作 ![请添加图片描述](https://i-blog.csdnimg.cn/direct/b6a24f8259a2488e8b24548c509b6bc6.jpeg) ### 3. 小结 ![请添加图片描述](https://i-blog.csdnimg.cn/direct/67d9bd8690a646af9f1c7a63e198e7c1.jpeg) 上面过程中的eax和edx中的值可能会因为某个步骤被覆盖掉,所以栈帧中可能还会将这几个寄存器的值压入栈帧(也不一定肯定有) ![请添加图片描述](https://i-blog.csdnimg.cn/direct/4c4d3ccf93894271a9f287d1fe75edf1.jpeg) ![请添加图片描述](https://i-blog.csdnimg.cn/direct/1799f807c608424cb1153a9cb7f811cf.jpeg) ![请添加图片描述](https://i-blog.csdnimg.cn/direct/6059356881c449beb9f9f5f55ec64a0f.jpeg) ## CISC和RISC CISC:组合运算 RISC:简单运算 ![请添加图片描述](https://i-blog.csdnimg.cn/direct/54bf56de23734d47918b86da90051322.jpeg) ![请添加图片描述](https://i-blog.csdnimg.cn/direct/0180daac2ed04932930340d8e6c6cbb6.jpeg) ## 小回顾 ![请添加图片描述](https://i-blog.csdnimg.cn/direct/bc586183cdba4c2b8869da095dcf619c.jpeg) ![请添加图片描述](https://i-blog.csdnimg.cn/direct/cbbcb39eea1443efa1198bc553456177.jpeg) ![请添加图片描述](https://i-blog.csdnimg.cn/direct/71b3951d571c49728faebc7a553355ef.jpeg) ![请添加图片描述](https://i-blog.csdnimg.cn/direct/9c73e18f3fa144648f5fcdda2c02aecb.jpeg) ![请添加图片描述](https://i-blog.csdnimg.cn/direct/3d5368458b5f4b8398d470f4a742e198.jpeg) ## CPU的功能和基本结构 ### 1. CPU的功能 ![请添加图片描述](https://i-blog.csdnimg.cn/direct/442a48c5f08f4d8ea65e6c6bbbf9b573.jpeg) ### 2. 运算器和控制器的功能 ![请添加图片描述](https://i-blog.csdnimg.cn/direct/80dfbcfd1571446686df8816e0a4cee0.jpeg) ### 3. 运算器的基本结构 具体ALU可见:[ALU](https://blog.csdn.net/2301_80071187/article/details/154411357?spm=1001.2014.3001.5502#t27) 运算需要工具(ALU)和数据(寄存器) 我们就需要将ALU和寄存器连接在一起,但是ALU和这么多寄存器连在一起就很混乱(因为不知道输入输出谁的数据) 所以有如下的几个办法: 1. 多路选择器 ![请添加图片描述](https://i-blog.csdnimg.cn/direct/c2be713a25934771ba60e8f8bf8673bb.jpeg) 2. 三态门 ![请添加图片描述](https://i-blog.csdnimg.cn/direct/aef7c5e1bc1f40f18139f000d72dcf99.jpeg) 3. 改为总线 同时,为了不破坏原来的数据,我们还在寄存器和ALU中间添加了暂存寄存器 ![请添加图片描述](https://i-blog.csdnimg.cn/direct/cc8ce9fd609b4506b68a86495fa6a30a.jpeg) ACC:累加寄存器,用来暂存用于加法计算的结果。 PSW:状态位寄存器,具体状态位可见:[标志位的生成](https://blog.csdn.net/2301_80071187/article/details/154411357?spm=1001.2014.3001.5502#t25) ![请添加图片描述](https://i-blog.csdnimg.cn/direct/539b7917fe0f4c76a63c3851d7919e81.jpeg) ALU上方的寄存器可以作为移位寄存器使用。 ![请添加图片描述](https://i-blog.csdnimg.cn/direct/623dcedffe8541859278fc23d6d808b2.jpeg) ![请添加图片描述](https://i-blog.csdnimg.cn/direct/f214e455775345eda898069a719ede9f.jpeg) ### 4. 控制器的基本结构 提到控制器可以想到:指令、操作:操作数、操作码,需要有指针读取指令,需要有寄存器来存指令 所以有了下面的: * 程序计数器:PC(也叫做IP),用来指指令的位置的 * 指令寄存器:用来存指令的 * 指令译码器:翻译这条指令说了什么的 * 微操作信号发生器:啥时候需要有这种操作 * 时序系统:指令之间撞了怎么办 * 存储器地址寄存器(MAR):存指令的寄存器的地址(套娃) * 存储器数据寄存器(MDR):存指令所需要的数据的 ![请添加图片描述](https://i-blog.csdnimg.cn/direct/00ddc9f628554e24850f10eab47355e0.jpeg) ### 5. CPU的基本结构 CPU=运算器+控制器 ![请添加图片描述](https://i-blog.csdnimg.cn/direct/4edcca3ed08949d484c0313c7632fa3a.jpeg) ![请添加图片描述](https://i-blog.csdnimg.cn/direct/84c3f4747d5a4d1abf80534c0979ed59.jpeg) ![请添加图片描述](https://i-blog.csdnimg.cn/direct/93917ef5c0a34242b6e0bc9b633b4094.jpeg) ### 6. 小结 ![请添加图片描述](https://i-blog.csdnimg.cn/direct/b30c81beb80044b5b814e1aea72ddc30.jpeg)

相关推荐
蒙奇D索大1 天前
【数据结构】考研408 | 平方探测法精讲:跳跃探查的艺术与聚集迷思
数据结构·笔记·考研·改行学it
imbackneverdie2 天前
AI工具如何重塑综述写作新体验
数据库·人工智能·考研·自然语言处理·aigc·论文·ai写作
蒙奇D索大2 天前
【数据结构】考研408 | 开放定址法精讲:连续探测的艺术与代价
数据结构·笔记·考研·改行学it
荒原之梦网2 天前
27考研,英语,数学,政治推荐哪些线上课?
考研·考研数学·荒原之梦考研数学
蒙奇D索大3 天前
【数据结构】考研408 | 冲突解决精讲: 拉链法——链式存储的艺术与优化
数据结构·笔记·考研·改行学it
元亓亓亓3 天前
考研408--操作系统--day9--I/O设备(上)
考研·操作系统·i/o·408
阿恩.7703 天前
国际水电与电力能源期刊精选
经验分享·笔记·考研·动态规划·能源·制造
Doan13133 天前
离2026考研仅剩3天,你还能做些什么?
考研
心本无晴.3 天前
拣学--基于vue3和django框架实现的辅助考研系统
vue.js·python·mysql·考研·django·dify