0. 目录
文章目录
1. 结论
直接给结论:
- stack栈
- heap堆
- bss
- data
- text
1.1 作用
- stack栈
存放局部非静态变量,用来保存现场(堆栈作用)
从高地址向低地址生长。 - heap堆
存放malloc和new开的内存 - bss
Block Started by Symbol,存放全局未初始化变量,静态变量。
bss不占实际的磁盘空间,运行时分配内存。编译的可执行文件中不包含这部分。 - data
data segment,存放已初始化的全局变量,已初始化的静态变量 - text
code segment/text segmen,存放系统代码,只读区域
1.2 位置
五大内存分区的位置如下图:
text和data段,为编译可执行文件时确定,
2. 疑问
其实之前看了不少文章,但是感觉大家的分类都不一致。
简单来说,观点比较一致的如下:
- 5大分区
- 堆+栈是一定有的
其他的部分感觉名称各式各样:
全局区、静态区、文字常量区、 自由存储区、常量存储区…
看着看着,真的问题越来越多:
- 是不是不同C语言和C++语言(或者其实是跟着编译器走的?),是不一致的,所以大家有各自的分法?
- 是不是win和linux不一样,所以大家总是能给出各种花式答案?
- 字符串常量(只读数据段) 是属于代码段 .text 还是数据段 .data ?(未解决)
- 编译出来的可执行文件?包含了哪几部分?
- …
2.1 名词解释
- 全局区
就是数据段 - 静态区
就是数据段 - 文字常量区
就是rodata段,不知道划分为数据段还是代码段。看名字是数据段,但是性质又和代码段一样(不可改) - 常量存储区
同rodata段 - 自由存储区
网上找的是说,new开的,free关的部分,有点疑惑,这个不应该是堆吗?或者C++规定不同。
2.2 混淆概念
其实怎么分区,按照链接文件来看最清晰了。
其他的分区无非是定义的混淆和重定义。
在ld文件中,明确的就是
.data段
.bss段
.text段
有些文章就把.data段分成了常量区+数据区
有些文章把数据区作为data+bss的统称
有些文章把常量字符串放入了代码段
3. 堆栈
看完了内存分区,主要再总结一下堆栈作用,其实主要还是栈。
3.1 混淆概念
之前看过一些话:
- 一个线程只有一个栈
- 每次函数调用有一个栈
- 每个进程有两个栈,内核栈+用户栈
所以,到底是几个栈?
3.2 概念
- 栈
栈是一种先进后出(FILO)的数据结构 - 系统栈/调用栈
(Call stack),是整个栈空间,由栈帧组成。 - 栈帧
(stack frame), 每一个函数独占自己的栈帧空间。当前正在运行的函数的栈帧总是在栈顶。Win32系统提供两个特殊的寄存器用于标识位于系统栈顶端的栈帧。
- ESP:栈指针寄存器(extended stack pointer),其内存放着一个指针,该指针永远指向系统栈最上面一个栈帧的栈顶。
- EBP:基址指针寄存器(extended base pointer),其内存放着一个指针,该指针永远指向系统栈最上面一个栈帧的底部。
3.3 函数调用过程
函数调用主要是依靠栈来实现现场的保护,函数的重入等等。
3.3.1 调用过程
- 参数入栈: 将参数按照调用约定(C 是从右向左)依次压入系统栈中;
- 返回地址入栈: 将当前代码区调用指令的下一条指令地址压入栈中,供函数返回时继续执行;
- 代码跳转: 处理器将代码区跳转到被调用函数的入口处;
- 栈帧调整:
- 将调用者的ebp压栈处理,保存指向栈底的ebp的地址(方便函数返回之后的现场恢复),此时esp指向新的栈顶位置; push ebp
- 将当前栈帧切换到新栈帧(将eps值装入ebp,更新栈帧底部), 这时ebp指向栈顶,而此时栈顶就是old ebp mov ebp, esp
- 给新栈帧分配空间 sub esp, XXX
3.3.2 返回过程
- 保存被调用函数的返回值到 eax 寄存器中 mov eax, xxx
- 恢复 esp 同时回收局部变量空间 mov ebp, esp
- 将上一个栈帧底部位置恢复到 ebp pop ebp
- 弹出当前栈顶元素,从栈中取到返回地址,并跳转到该位置 ret
4. 验证实验
待补充,汇编分析
参考链接
函数调用
系统栈的工作原理
Linux内存分区---------介绍比较详细,就是把rodata划入了代码区,不知道对不对