
(以下内容全部出自上述课程)
目录
- 如何访问栈帧
-
- [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)  ### 5. 小结  ## 如何切换栈帧 ### 1. 调用-切换过程 执行到call add的时候计数指针(ip,就是之前的pc)刚好指到下一个语句 ps:这句话的意思就是ip指针指到这个语句,语句执行的同时ip指向下一个语句(**指到谁谁干活**) * 所以执行call的时候,为了避免数据遗漏,就需要先把指向自己下面的值先存入栈(因为跳到另一个函数后总是要跳回来继续执行的) * 存完ip旧值之后,就可以给ip设置一个新的值让他去处理新函数(就是跳到新函数的第一个语句)  ip指针指到push ebp,这条语句就要执行了,与此同时ip指针指向下一个语句: * `push ebp`:把ebp指向位置的地址存入栈 > 大区分!!!!! > > ebp:寄存器本身,即基址指针寄存器(Base Pointer Register)的值,是一个**地址** (32位或64位数值)。 > > \[ebp\]:以 ebp 的值作为内存地址,访问该地址处的内容,即**ebp 指向的内存单元中的值**。  ip指针刚刚指了mov ebp,esp,所以现在执行这条语句:  `mov ebp,esp`:把esp的地址值赋值给ebp的地址值(**改变地址** ,所以两个指针如图指向同一个位置): 就这样,两个指针从最初指向绿色的栈帧变为现在指向黄色的栈帧,就这样完成了栈帧的切换。  这两句指令等同于一个`enter` 算是例行处理,每个函数前面都有这两句话  ### 2. 返回-切换过程 复习调用语句: * `push ebp` * `mov ebp,esp` 返回语句: * `mov esp,ebp` * `pop ebp` 完全就是倒过来  ps:这里经过一系列函数内的操作,esp按照原有规律指向栈顶(它是栈顶指针) `mov esp,ebp`:将ebp地址值赋值给esp的地址值,让ebp和esp指向同一个地方  `pop ebp`:esp指向的元素出栈(看上一个图,就是上一个栈的基址),同时esp向上移动一格(pop指令特性:先出栈再上移) 所以此时esp就完美地从指向黄色的栈帧变为指向绿色的栈帧了 同时,这个元素的值还会被复制到ebp的地址值上,所以ebp就指回了绿色栈帧的栈底(因为是 pop **ebp** )  结束之后就是下面这张图的样子:  leave指令就是这两句指令的结合体  和调用切换指令相同,都属于例行处理,所以返回的时候都会出现这两句指令,或者是leave  因为我们之前调用的时候把原本函数的ip旧值存入栈了,ret就是帮我们重新找到这个值,然后继续原函数接下来的操作。  ### 3. 小结  ### 4. 真题分析   ## 如何传递参数和返回值  ### 1. 一个栈帧内包含什么? 从上面我们知道了: * 栈帧最**底** 部一定是**上一层栈帧基址**(返回切换时所需) * 栈帧最**顶** 部一定是**返回地址**(返回继续操作原函数所需) 那么中间的位置就是用来存一些函数里的变量和值  * **局部变量** 通常存在栈帧**底**部区域(是自己的就放在最下面,别人拿不走) * **调用参数** 通常存在栈帧**顶** 部区域(是别人需要的就放在最上面,别人方便拿)  当然,也不可能全放完,肯定能够会有空闲的位置。  小总结:  ### 2. 汇编代码实战 #### 2.1 访问局部变量 和上面访问数据一个流程:-XX就往下,+XX就往上,带\[\]的都是指针所指的值 这个栈帧里和ebp相关的都是局部变量  #### 2.2 传递参数 这个栈帧里和esp相关的都是参数  #### 2.3 函数调用 调用add函数  #### 2.4 切换栈帧 和上面**调用切换** 一个流程  #### 2.5 访问参数 eax和edx访问参数  #### 2.6 传递返回值 加法运算再把结果放回eax  #### 2.7 恢复上一层栈帧 和上面**返回切换** 一个流程   #### 2.8 函数调用返回 ret就返回为原函数的ip旧值了(call的下一行指令)  #### 2.9 传递返回值 继续原函数下面的操作  ### 3. 小结  上面过程中的eax和edx中的值可能会因为某个步骤被覆盖掉,所以栈帧中可能还会将这几个寄存器的值压入栈帧(也不一定肯定有)    ## CISC和RISC CISC:组合运算 RISC:简单运算   ## 小回顾      ## CPU的功能和基本结构 ### 1. CPU的功能  ### 2. 运算器和控制器的功能  ### 3. 运算器的基本结构 具体ALU可见:[ALU](https://blog.csdn.net/2301_80071187/article/details/154411357?spm=1001.2014.3001.5502#t27) 运算需要工具(ALU)和数据(寄存器) 我们就需要将ALU和寄存器连接在一起,但是ALU和这么多寄存器连在一起就很混乱(因为不知道输入输出谁的数据) 所以有如下的几个办法: 1. 多路选择器  2. 三态门  3. 改为总线 同时,为了不破坏原来的数据,我们还在寄存器和ALU中间添加了暂存寄存器  ACC:累加寄存器,用来暂存用于加法计算的结果。 PSW:状态位寄存器,具体状态位可见:[标志位的生成](https://blog.csdn.net/2301_80071187/article/details/154411357?spm=1001.2014.3001.5502#t25)  ALU上方的寄存器可以作为移位寄存器使用。   ### 4. 控制器的基本结构 提到控制器可以想到:指令、操作:操作数、操作码,需要有指针读取指令,需要有寄存器来存指令 所以有了下面的: * 程序计数器:PC(也叫做IP),用来指指令的位置的 * 指令寄存器:用来存指令的 * 指令译码器:翻译这条指令说了什么的 * 微操作信号发生器:啥时候需要有这种操作 * 时序系统:指令之间撞了怎么办 * 存储器地址寄存器(MAR):存指令的寄存器的地址(套娃) * 存储器数据寄存器(MDR):存指令所需要的数据的  ### 5. CPU的基本结构 CPU=运算器+控制器    ### 6. 小结 