深入理解程序的结构-创新互联
深入理解程序的结构
1静态可执行程序中的段
程序由不同的段构成(代码段、数据段),程序的静态特征就是指令和数据,动态特征就是执行指令处理数据。
源程序代码到可执行程序的对应关系:
代码段
- 源代码的可执行语句编译后进入代码段,编译完成后大小固定
- 代码段在内存管理单元的系统中具有只读属性(是一种保护,防止被改写)
- 代码段中可以包括常量数据(如字符串常量)
数据段(.data .bss .rodata)
.bss段(Block Started by Symbol segment)
存储未初始化的全局数据,不占用可执行文件的大小。
.data段:存储具有非0初始值的变量
.rodata段:存储const修饰的和其他只读数据
问题:.bss和.data段同样存储的是全局数据,为什么初始化的和不初始化的保存在不同的段中?
.bss段中的变量不用在再程序文件中保存初始值,从而减小可执程序的大小,提高程序加载的效率。(对于.bss段中的变量,在可执行文件中只需要保存其变量名和变量类型,在加载时统一将其初始化为0;而对于存储于.data段中的数据,需要保存其变量名,类型、和值,在加载其需要将变量值拷贝得到变量对应的空间)
编程实验:可以编写简单测试程序,通过objdump -h命令查看各个段的信息,使用nm命令查看可执行文件中的符号和地址,使用objdump -s -j .data ./a.ou查看某个段中的具体信息,并将上述信息对应起来。6.2动态加载后生成的段
栈(stack)
栈时在程序被加载到内存之后才生成的,其本质时片连续的存储空间
SP寄存器作为栈顶“指针”实现入栈操作和出栈操作
栈通常作为以下用途
中断发生时,栈用于保存寄存器的值(现场保护)
函数调用时,栈用于保存函数的活动记录(栈帧信息)
并发编程时,每个线程拥有自己独立的栈堆(Heap)
堆和栈一样,时程序被加载到内存后才生成的。是一片“空闲的空间”,用于提供动态内存分配。
需要函数的支持(malloc、free)
内存映射段(memory mapping segment)
内核将硬盘中的文件内容直接映射到内存映射段(mmap)
动态链接库在可执行程序加载时映射到内存映射段
程序执行时能够创建匿名映射区存放程序数据
内存映射文件的原理:
将硬盘上的文件数据逻辑映射到内存中(零耗时),通过缺页中断进行文件数据的实际载入(一次数据拷贝),映射后对内存的读写就是对文件的读写(极大的提高了文件的读写效率)。
使用传统的方式通过read函数来读取文件,首先内核程序接到应用程的请求,然后内核程序去读取硬盘中的文件内核空间,然后再讲内核空间中的数据拷贝到应用空间(使用了两次数据拷贝)。
最终各个段在内存中的布局:
这里我们看到栈、堆的起始地址都是随机的,这样做的目的是为了安全,当其实地址随机后,恶意代码修改程序的暗度变大(难以直接通过固定地址获取到程度的返回地址)。
另外有需要云服务器可以了解下创新互联cdcxhl.cn,海内外云服务器15元起步,三天无理由+7*72小时售后在线,公司持有idc许可证,提供“云服务器、裸金属服务器、高防服务器、香港服务器、美国服务器、虚拟主机、免备案服务器”等云主机租用服务以及企业上云的综合解决方案,具有“安全稳定、简单易用、服务可用性高、性价比高”等特点与优势,专为企业上云打造定制,能够满足用户丰富、多元化的应用场景需求。
当前文章:深入理解程序的结构-创新互联
网页网址:http://myzitong.com/article/doedsi.html