三块核心内容
进程的虚拟地址空间内存的划分和布局
以32位linux操作系统为例,通常为每个进程分配4GB的虚拟地址空间。其中,低3GB(0x00000000 ~ 0xBFFFFFFF)为进程的用户空间,高1GB(0xC0000000 ~ 0xFFFFFFFF)为进程的内核空间,进程的用户空间是进程私有的,内核空间为进程之间共享的。
在进程的用户空间中,从低到高被划分为进程的:.txt段、.data段、.bss段、.heap(堆)、*os(加载共享库)、stack(栈)、命令行参数和环境变量
.text
用于存放可执行指令(包括函数代码、局部变量对应的汇编指令)。
.data
用于存放已经初始化的全局变量或静态变量
.bss
用于存放未初始化或初始化为0的全局变量或静态变量
heap
用于存放用户开辟的空间
内存映射区
用于存放动态链接库、共享内存等。
stack
进程的栈空间,用于进程的函数调用等操作
函数的调用堆栈详细过程
在进程调用函数时:
- 首先先将参数从右向左,依次压入栈中;
- call指令,将下一条指令的地址压入栈中;
- 将ebp基址寄存器的值压入栈中
- 将esp的值赋给ebp
- esp 减去一个固定大小(例如 sub esp, N),为该函数的局部变量分配空间
这样就为被调用的函数开辟好了栈帧空间
在被调用函数返回时:
- 首先先将ebp的值赋给esp
- pop ebp(出栈,并将出栈的值赋给ebp,因为此时栈顶指针指向的正是在调用函数时,被压入栈的ebp中的值)
- ret(该汇编指令会首先执行出栈操作,然后将出栈的值赋给PC寄存器)
CPP代码的编译链接过程
预编译
作用:处理以 # 开头的指令
处理内容:
- 展开头文件(
#include) - 宏替换(
#define) - 删除注释
- 条件编译(
#ifdef、#endif)
编译
将预处理后的代码翻译成汇编语言
汇编
将汇编代码转换成机器指令(目标代码)
链接
作用:合并多个目标文件和库,生成最终可执行文件
处理内容:
- 符号解析(函数、全局变量的地址确定)
- 重定位(把相对地址改成绝对地址)
- 合并段(
.text、.data等) - 链接运行时库(如 libstdc++)