1.任何程序在编译时都会产生指令和数据,进行地址编号,但是如果地址不连续,就会程序运行不起来,编译器的地址管理比较麻烦(无法动态的获知物理空间的使用情况,也就无法为数据进行编号)
2.进程直接访问物理地址,如果此时有一个野指针,那么在进行操作野指针的时候可能会改变其他空间的数据,造成不安全的事件发生(无法进行内存访问控制)
3.程序运行空间通常需要一块连续的空间,空间利用率低,通过虚拟地址空间映射到物理内存上进行数据存储,可以实现数据在物理空间上离散式存储,提高内存的利用率,并且每个进程都有一份属于自己的连续空间使用
二、进程的虚拟地址空间指令存放在.text段
int a = 12; int b = 0; int c; // 编译后成为汇编指令 // mov dword ptr[a],0ch //存放.text段 //局部变量 指令
数据存放在
static int e = 13; static int f = 0; static int g; //局部变量静态变量e存放在.data段 不为0 f、g存放在.bss段 为0/未初始化
可打印g的值为0,无法打印c的值(栈上的无效值)
#includeusing namespace std; int main(){ int c; static int g = 0; cout << c << g << endl; return 0; } //无法打印c的值 可以打印g的值为0
1.包括了用户空间、内核空间
2.全局变量均存放在data段(不为0)、bss段(为0 或者 未初始化)
3.局部变量 产生指令
局部变量中的静态变量 产生数据(data段、bss段)
三、进程和线程的区别进程是系统进行资源分配和调度的一个独立单位
线程是进程的一个实体,是CPU调度和分配基本单位
简而言之
一个程序至少要有一个进程,一个进程至少要有一个线程
四、多进程1.有各自的用户空间(隔离),共享内核空间
2.进程之间通信方式 : 匿名管道通信(内核空间内存数据可共享)
参考链接1.https://blog.csdn.net/weixin_45975835/article/details/115010310
2.《深入理解计算机系统》 第七章
3.https://blog.csdn.net/yaosiming2011/article/details/44280797
02 函数调用堆栈#includeusing namespace std; int sum(int a, int b) { int temp; temp = a + b; return temp; } int main() { int a = 10;//局部变量不产生符号 mov dword ptr[ebp-4], 0Ah int b = 20;// mov dword ptr[ebp-8], 14h int ret = sum(a,b); cout << "ret is " << ret << endl; system("pause"); return 0; }
Q1:main函数调用sum,sum执行完以后,怎么知道回到哪个函数中?
通过汇编语言中的call指令存储了下一条指令的地址。
Q2:sum函数执行完,回到main以后,怎么知道从哪一行指令继续运行的?
在sum函数调用结束以后,ret指令在CPU的PC寄存器中读取刚刚存储的地址,回到原来的函数。
03 C++的编译与链接 编译过程main.cpp sum.cpp
extern int gdata;// gdata *UND* 符号引用
int sum(int, int);// sum *UND*
int data = 20; //data .data段
int main() { //main .text段
int a = gdata;
int b = data;
int ret = sum(a, b);
return 0;
}
int gdata = 10;//gdata .data段
int sum(int a, int b) { //sum_int_int .text段
return a + b;
}
预编译:
’#‘开头的命令在预编译完成
#pragma lib #pragma link //在链接阶段处理
编译:
gcc g++ -o
汇编:
主要是符号表的输出
二进制可重定位的目标文件(*.obj) main.o sum.o
其中,.o文件的格式组成:
elf文件头 .text .data .bss .symbal .section table链接过程
链接:编译完成的所有.o文件和静态库文件
步骤一:
所有.o文件段的合并==(.text、.bss、.data等)==
符号表合并后,进行符号解析(UND所有对符号的引用,都要找到该符号的定义的地方,可能会报错,符号未定义、重定义等)
给所有的符号分配虚拟地址(在此时给符号分配虚拟地址)
步骤二:
符号的重定位(重定向)
在代码段将符号的地址填成正确的地址
查询符号段、地址指令 objdump -s sum.o objdump -t a.out readelf -h a.out
输出
a.out
读取a.out的入口地址,入口地址为main函数的地址
都是各种段组成,.out相比于.obj多了progrma headers段,有两个load,告诉系统运行到这个程序的时候,把哪些内容加载到内存中(.text、.data)
-o 可执行程序的名称
a.exe
可执行文件加载过程:



