深入了解C++:底层编译原理

进程的虚拟空间划分

任何编程语言,都会产生两样东西,指令和数据。

.exe程序运行的时候会从磁盘被加载到内存中,但是不能直接加载到物理内存中。Linux会给当前进程分配一块空间,比如x86 32位linux环境下会给进程分配2^32(4G)大小的空间,这个空间被叫做【进程的虚拟地址空间】,进程的虚拟地址空间其实并不存在,从底层来看它不过是内核创建的一系列数据结构而已。

以x86 32位linux为例,讲解进程的虚拟地址空间:这部分空间默认首地址是0x00000000,尾地址是0xFFFFFFFF,以0xCCCCCCCC为界被划分为两块,0x00000000~0xCCCCCCCC是【用户空间】,0xCCCCCCCC~0xFFFFFFFF是【内核空间】。

用户空间被进一步划分,0x00000000~0x08048000是不允许访问的空间。往后就是.【text段】,用于存储程序的机器代码(即已编译的指令),其中还有一部分是,rodata段(readonly data),用于存放只读数据(比如char *p=“hello”,所以不能修改)。

再往下就是.data段(专门存放初始化并且初始化不为0的数据),和.bss段(存放未初始化和初始化为0的数据),.bss段会自动把放入的数据做0初始化。最终生成的可执行文件就已经包含了./data段和./bss段里的数据了。

再往下就是.head段,俗称堆内存。

再往下就是共享库空间,用于加载.dll,.so等文件。

再往下就是stack段,俗称栈空间。栈是从高地址往低地址增长,堆是从低地址往高地址增长。栈空间在运行到相应的指令的时候才会被使用。

最后存放命令行参数和环境变量。

内核空间被划分为ZONE_DMA(16M左右),ZONE_NORMAL(800M左右,存放了各种控制块,比如tcb),ZONE_HIGHMEM(地址映射用)

深入了解C++:底层编译原理_第1张图片

注意:每一个进程用户空间是私有的,内核空间是共享的!所以进程之间通信需要通过内核空间。

#include

//可执行文件展开的时候
//这些数据都被直接放入相应的./data或./bss段
int gdata1 = 0; //.data
int gdata2 = 0;//.bss
int gdata3;//.bss

static int gdata4 = 1; //.ata
static int gdata5 = 0;//.bss
static int gdata6;//.bss

int main(){

        //编译的时候产生的是指令,
        //可执行问价展开的时候放在.text中,
        //指令运行的时候才会再栈上开辟空间
        int a =12;
        int b =0;
        int c;

        //同.data或.bss
        static int c =13;
        static int f =0;
        static int g;
        return 0;
}

函数调用堆栈空间的过程

下面用一段很简单的代码说明栈堆调用过程。

#include 
using namespace std;

int sum(int a,int b)
{
	int temp = 0;
	temp = a + b;
	return temp;
}

int main()
{
	int a = 10;
	int b = 20;
	int ret = sum(a,b);
	cout << ret <

我们知道函数运行的时候需要在栈上开辟一块栈桢,.text里的汇编指令运行的时候,会往栈帧里写入相关数据。 比如int a = 10对应的指令运行的时候,会对main函数的栈帧进行压栈,从ebp(栈底)压入了a=10这个数据。

运行上述代码会依次发生以下事情:

1、ebp指针指向main栈帧的栈底,esp指针指向main栈帧的栈顶。esp和ebp指向的是当前调用的栈帧,能表示一块空间。

2、a、b、ret会依次从ebp压入main函数的栈帧中。

3、sum函数的实参会从右往左依次从esp(栈顶压入)。注意,栈帧的大小是会动态变化的,esp会保持位移一直指向栈帧的顶部。

4、把下一指令,也就是sum函数的指令的地址跟从实参地址一起从esp方向压入栈帧中。

深入了解C++:底层编译原理_第2张图片

5、把main函数调用的地址跟从sum函数调用的地址一起从esp方向压入栈帧中。

深入了解C++:底层编译原理_第3张图片

6、给sum函数开辟栈帧空间,ebp赋值成esp后,esp指向sum栈帧的顶部。sum函数栈帧可能会被初始化成0xCCCCCCCC。

深入了解C++:底层编译原理_第4张图片

7、给sum函数的栈帧空间从ebp压入temp。

8、计算a+b的值并赋值给temp空间。

9、回退栈帧,让ebp获取pop出的栈值,所以能重新指向main函数的栈底。

深入了解C++:底层编译原理_第5张图片

你可能感兴趣的:(linux,运维,c++,缓存,开发语言)