引言
我们平时写代码使用的语言是高级语言,计算机看不懂,计算机硬件只认识电信号===高低电平也就是0/1二进制机器语言
程序的执行过程:高级语言--->汇编语言--->机器语言
计算机底层只有指令+数据

一、计算机核心组件
- 输入输出设备(IO):键盘、屏幕、磁盘
- 存储器:存放指令与数据(主存 = 内存)
- 运算器 + 控制器:合称 CPU,负责解析与执行指令
1.存储器
程序要运行,必须先加载到主存(内存),磁盘无法被 CPU 直接访问。
(1)主存内部结构:
- 存储体 :真正存数据的地方,由无数存储单元组成
- 每个存储单元对应一个唯一地址
- 数据按单元读写
(2)两个关键寄存器:MAR / MDR
- MAR(地址寄存器):存放要访问的内存单元地址;MAR的位数=能访问多少个存储单元,n位MAR对应2ⁿ 个单元
- MDR(数据寄存器):存放从内存读出 / 要写入内存的数据;决定一次读写多少bit的数据
(3)读取数据流程:
- CPU 把数据地址 → MAR
- MAR 根据地址去存储体找数据
- 读出的数据 → MDR
- CPU 从 MDR 拿走数据
(4)写入数据流程:
- CPU 把目标地址 → MAR
- 把要写的数据 → MDR
- 向内存发 "写信号"
- 内存把 MDR 数据写入 MAR 指向的单元

2.运算器:负责"计算"
运算器是 CPU 的 "计算器",核心组件:
- ALU(算术逻辑单元):真正做加减乘除
- ACC(累加器):存放操作数 + 保存结果
- X 寄存器:存放第二个操作数
- MQ 寄存器:乘法 / 除法专用
运算器只做一件事:从寄存器拿数 → ALU 算 → 写回寄存器。

3.控制器:大脑
控制器保证指令一条一条有序执行,核心三组件:
-
PC(程序计数器) 永远存下一条指令的地址,指令取完自动 +1。
-
IR(指令寄存器) 存放当前正在执行的指令,分为两部分:
- 操作码:做什么(加、乘、存)
- 地址码:操作数在哪
-
CU(控制单元) 翻译操作码,发出电信号,指挥存储器、运算器配合工作。

二、底层指令过程
这里用一个例子来进行讲解整个过程:
a=2,b=3,c=1
y = a*b + c
注意:一条指令的执行分为两个阶段:取指阶段、执行阶段
第一条指令:
首先CPU把地址给MAR,MAR去存储体中拿指令,把指令交给MDR,MDR再把数据交给IR;IR会区分指令是操作码还是地址码,地址码再次给到MAR,操作码给CU
MAR收到IR给的地址码,去存储体中对应地址,把数据交给MDR
之后CU开始(操作码),CU知道了你要把数据存到ACC中,之后就会把MDR的数据a交给ACC当中

第二条指令:
PC在第一条指令在执行过程中就已经指向第二条指令
CU之前的步骤和第一条指令一样就省略不写,当CU 读取操作码之后,会控制数据从MDR给到X寄存器当中,因为要进行a*b,所以第一条指令在ACC中存储的a的值会给ALU,X再把b交给ALU,在ALU中进行乘法运算,所得结果再次回到ACC中;在这里的X作用就是存储另一个操作数
之后指令过程省略
三、程序的执行本质
一个程序运行起来 = 一个 / 多个线程
一个线程运行 = 不断入栈、出栈、切换栈帧
方法调用 = 栈帧切换 :计算机世界里,没有 "函数调用",只有栈的压入与弹出。
四、栈与栈帧:函数调用的底层逻辑
1.前置知识
(1)栈
在计算机里面栈的开口方向是朝下的,栈从高地址--->低地址生长,栈底在高地址,栈顶在低地址
push → esp 向低地址移动;pop → esp 向高地址移动
(2)栈指针
- ebp:栈基指针(固定不动): 定位当前栈帧的底部,用来找参数、局部变量
- esp:栈顶指针(随时变化) :push/pop 都会移动 esp

2.栈帧切换过程
用例子来讲:main()调用add()

(1)第一步:call 指令(调用函数)
call add
做两件事:
- 把下一条指令地址(返回地址)压入栈
- 跳转到 add 函数入口
(2)第二步:创建新栈帧(add 栈帧)
push ebp
mov ebp, esp
sub esp, 空间大小
解释:
push ebp:保存上一层栈(main)的栈底mov ebp, esp:让 ebp 指向当前栈顶,确立新栈帧的底sub esp, xx:抬高栈顶,给局部变量开辟空间
栈帧正式建立
(3)第三步:执行 add 内部逻辑
使用 [ebp+8] 取参数
使用 [ebp-4] 存取局部变量 运算全部在寄存器中完成
(4)第四步:函数返回前准备
mov eax, 返回值
返回值放在 eax 中带回上一层。
(5)第五步:销毁当前栈帧
leave
等价于:
mov esp, ebp
pop ebp
作用:
- 让 esp 恢复到 ebp 位置
- 弹出旧 ebp,恢复 main 的栈底
add 栈帧彻底销毁
(6)第六步:返回到 main
ret
弹出栈顶的返回地址 → PC 跳回 main 继续执行。
3.总结
函数调用就是栈帧的保存、切换、恢复