引入
Question:
为什么函数的返回值能在函数的外部被拿到呢?局部变量不是出了作用域就要被销毁嘛?
#include<stdio.h>int Add(int a, int b)
{int ret = a + b;return ret;
}
int main()
{int a = 10, b = 20;int ret = Add(a, b);return 0;
}
我们观察函数返回时的汇编代码就能看出端倪了:
可以看到,最后在返回 Add 函数的返回值时,是讲返回值写到了寄存器 `` 中!在 main
函数的中想要拿到 Add
函数的返回值只需要将 j
寄存器中的内容拷贝到 ret
变量中就行了!
进程切换
为啥要讲怎么获取函数的返回值呢?
我想说明在 CPU
的内部有很多很多的寄存器:
- 通用寄存器:eax,ebx,ecx,edx 等等,这些寄存器就是用来临时保存函数的返回值,将内存中的数据拷贝到
CPU
中参与算术或者逻辑运算,等等。 - 程序计数器(PC),对应的寄存器是:
eip
,这个寄存器用来保存CPU
正在执行的指令的吓一跳指令的地址。通过这个寄存器,我们就知道进程的代码执行到那个位置了! - ebp,esp:这两个寄存器大家都还有印象吧,就是用来维护栈桢结构的那两个寄存器!
- status:这是个状态寄存器。
大家不用管这些,我们只要知道在 CPU
内部有很多寄存器就行了!
显然:CPU
中的寄存器保存的是进程相关的数据!你想想,一个进程的时间片消耗完毕了,在被切换的时候,CPU
中的寄存器中保存的临时数据要不要给进程带走呢?当然是要啦!不带走,这个进程下次在 CPU
上执行的时候怎么知道从哪里继续执行呢?
其中 CPU 中保存的进程的临时数据称为进程的上下文。
因此在进程切换的时候势必会有两个动作:
- 保存进程的上下文。
- 恢复进程的上下文。(保存进程上下文的目的不就是为了恢复嘛!)
那么,问题就来了,进程的上下文保存道哪里呢?
我只能说,进程的上下文是保存在
task_struct
中的,这个完全有能力做到!
我只要在task_struct
中定义一个结构体保存每个寄存器的信息就行了!struct reg_info {//假设系统是 32 位的int eax;int ebx;int eip;int esp;int ebp;//等等等等 };
定义一个结构体,在
task_struct
中保存一个reg_info*
的字段就行了!
但是,进程的上下文保存在task_struct
中的说法不完全正确!
如果你想深入了解可以搜一搜:全局段描述符,局部段描述符的概念