十三、深入理解程序的结构
1. 程序由不同的段构成(代码段,数据段)
- 程序的静态特征就是指令和数据
- 程序的动态特征就是执行指令处理数据
2. 源程代码到可执行程序文件的对应关系
静态分析工具多半都是通过文件头来获得信息。
局部变量存储在栈上。
3. 代码段(.text)
- 源代码中的可执行语句编译后进入代码段
- 代码段在有内存管理单元的系统中具有只读属性
- 代码段的大小在编译结束后就已经固定(不能动态改变)
- 代码段中可以包含常量数据(如︰常量字符串)
4. 数据段(.data, .bss, .rodata)
- 数据段用于存放源代码中具有全局生命期的变量
- .bss
- 存储未初始化(初始化为0)的变量
- .data
- 存储具有非0初始值的变量
- .rodata
- 存储const关键字修饰的变量
- .bss
5. 问题
同是全局变量和静态局部变量,为什么初始化的和未初始化的保存在不同段中?
6. 深入理解.data和.bss
- 程序加载后
- .bss段中的所有内存单元被初始化为 0
- 将程序文件中.data段相关的初始值写入对应内存单元
.bss段中的变量不用在程序文件中保存初始值,从而减小可执行程序文件的体积,并且提高程序的加载效率。
7. 编程实验:关键段的分析
编译器默认四字节对齐
查看.data的初始值 objdump -s -j .data test.out
查看.rodata的初始值 objdump -s -j .rodata test.out
8. 程序中的栈(Stack)
- 程序中栈的本质是一片连续的内存空间
- SP 寄存器作为栈顶“指针”实现入栈操作和出栈操作
9. 栈的深入理解
- 中断发生时,栈用于保存寄存器的值
- 函数调用时,栈用于保存函数的活动记录(栈帧信息)
- 并发编程时,每一个线程拥有自己独立的栈
10. 程序中的堆( Heap )
- 堆是一片“闲置”的内存空间,用于提供动态内存分配
- 堆空间的分配需要函数支持(malloc)
- 堆空间在使用结束后需要归还(free)
11. 内存映射段(Memory Mapping Segment)
- 内核将硬盘文件的内容直接映射到内存映射段(mmap)
- 动态链接库在可执行程序加载时映射到内存映射段
- 程序执行时能够创建匿名映射区存放程序数据
12. 内存映射文件原理简介
- 将硬盘上的文件数据逻辑映射到内存中(零耗时)
- 通过缺页中断进行文件数据的实际载入(一次数据拷贝)
- 映射后的内存的读写就是对文件数据的读写
13. 实例分析:内存映射文件的原理
14. 小结
- 0 - 0x00048000 操作系统使用
- 堆的起始地址是随机的,为了安全。
- 内存映射段的起始地址是随机的,为了安全。
- 栈的起始地址是随机的,为了安全。
- 起始地址是随机的,防止恶意程序进行破坏,导致系统崩溃。
- 栈、内存映射段生长方向是由高地址向低地址生长。
- 堆生长方向是由低地址向高地址生长。
- 内核空间占用1gb