文章目录
进程概述
1.引言
首先引入问题,进程是怎么产生的,为什么需要进程?
- 我们先回到古老的裸机编程时代,即没有操作系统的时代,我们写的代码(汇编)直接跑在硬件之上。
- 裸机编程自由度很大,即内存可以供我们随意使用
- 自由使用内存带来一个问题:CPU可能会混淆数据与指令,如果产生混淆会产生无法预料的结果
- 自由使用内存带来的另外一个问题:我们的程序可以修改自身,比如修改内存中某一位置的数据,那么可能就将自身代码改变了。
- 事实上,Linux内核引导程序部分频繁涉及了修改自身代码。
引入了以上问题以后,我们开始学习进程,进程可以帮助我们解决上述问题。学习过程中注意体会进程是如何帮我们解决上述问题的。
2.进程的概念
- 进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,也可以理解成其是对内存的抽象。
- 我们从其定义可以看出,其存在的目的是为了管理资源。想想我们引言中提出的问题,上述问题是不是和资源管理有关联?
- 那么我们再思考一个问题,所谓分配资源是分配的哪里的资源?再看看引言中的问题,上述问题是因为内存访问引起的,所以进程涉及的资源分配和管理大多都是针对内存的。
- 那么有了进程的概念以后,内存是怎么管理的呢?带着这个问题继续看。
2.1进程的内存抽象
先看一个比较熟悉的结构:
- 所谓进程为内存提供了一层抽象,其实就是上述结构,将内存严格划分成各个段。
- 想想划分成各个段以后,怎么解决我们引言中提到的CPU混淆数据和指令的问题?
- 根据之前的基础应该能将一些知识串起来:CPU执行的时候在代码段取指令,划分了数据段和代码段CPU就不会混淆数据和指令了,然后再分别对各个段做限制,比如限定代码段是只读的,那么程序就不能修改自身代码了。
各个段的含义:
- 代码段text:存放代码(指令)
- 数据段data:存放全局变量,静态变量
- 堆heap:new,malloc时从堆中申请空间
- 栈stack:存放局部变量,子函数返回地址
课外充电站
Linux0.11(1991年)版本内核只能管理16M内存,其中0-1M是内核使用的,然后还要划分缓冲区,虚拟盘,其余才是用户使用
在Linux内核源码中,前几个程序(bootsect.s, setup.s, head.s)是用汇编写的,频繁涉及改动自身代码(移动自身代码的位置)
考题补充:
int a;
void main(){
int x;
x=f(1,2);
printf("%d",x);
}
int f(int b, int c){
static int d;
d+=b*c;
return d;
}
提问:
- int a 存在哪个段? — 数据段data
- int x,b,c 存在哪个段? — 栈stack
- static int d; 存在哪个段? — 数据段data
- 这些代码存在哪个段? — 代码段text
2.2分段保护
2.2.1例一
引言中提到,裸机编程中 我们可以用代码修改我们的代码,那么我们在Win10上试试能不能修改自身代码呢?
复制下面代码到devc++中(任何包含C编译器的开发环境均可)
#include<stdio.h>
void f() {
int i=3;
}
int main() {
//函数名f不仅仅是函数名,还是函数的入口地址
*(int*)f=9;
printf("after modify");
return 0;
}
先讲解下程序的含义:f可不仅仅是函数名,它是函数的入口地址,那么*(地址)=xxx就将某个地址的内容修改了。
运行结果: