程序员的自我修养 摘要 3 目标文件(.o/object file) PE/ELF/COFF

目标文件是什么

目标文件中引入’段’的机制,不同的目标文件可以拥有不同数量以及不同类型的’段’

windows NT中的PE格式与linux中的ELF格式都源自COFF格式.而当初由于UNIX系统的a.out目标文件设计过于简单,无法满足现代程序的要求,所以才会产生了COFF以及两大操作系统对其的沿用.

目标文件是什么样

目标文件至少包含编译后的机器指令代码,数据,还包括链接时须要的信息,比如符号表,调试信息,字符串等.

目标文件将这些信息按不同的属性,以’节’(section)的形式存储,有时候也叫段(segment).一般情况下,它们都表示为一个特定长度的区域.基本上不加以区别.

源代码编译后的机器指令经常放在代码段(code section),全局变量和局部静态变量经常放在数据段(Data Section).数据段的一般名字都叫’data’

下图时简单的程序被编译成目标文件后的结构

在这里插入图片描述

在这里插入图片描述

未初始化的全局变量和局部静态变量预留位置在.bss段中,它没有内容,所以它在文件中也不占据空间.

总体来说,程序源代码被编译以后主要分成两种段,程序指令和程序数据.代码段属于程序指令,而数据段和.bss属于程序数据.

程序和数据为何分开

一方面当程序装载后,数据和指令分别映射到两个虚拟内存区域.由于数据区域对于进程来说是可读写的,而指令区域对于进程来说是只读的,所以两个虚存区域的权限可以分别设置成可读写和只读.这样可以防止程序的指令被有意或无意的改写.

另一方面对于现代的CPU来说,它们有着极为强大的缓存体系(Cache).由于缓存在现代的计算机中地位非常重要,所以程序必须尽量提高缓存的命中率.指令区和数据区缓存分离,所以程序的指令和数据被分开存放对CPU的缓存命中率提高也有好处

第三个原因,也是最重要的原因,就是当系统中运行着多个该程序的副本时,它们的指令是一样的,所以内存中只需要保存一份该程序的指令部分.对于指令这种只读区域来说是这样,其他只读数据也一样.

不要小看共享指令的概念,特别是有动态链接的系统中,可以节省大量内存.

在这里插入图片描述

使用objdump -h demo.c

使用-h参数查看目标文件的各个段的基本信息

除了上面的三个段,还有只读数据段(.rodata)/注释信息段(.comment)和堆栈段(.note.GNU-stack)

最容易理解的数据,段的长度(size) 和 段所在的位置(file offset)

每个段的第二行的contents,alloc等表示段的各种属性,contents表示该段在文件中存在.可以看到.bss段没有contents,表示它实际上在ELF文件中不存在内容.

'note.GNU.stack’虽然有contents,但它的长度为0,这是个很古怪的段,可以先忽略它,认为它在ELF文件中也不存在.那么ELF文件中实际存在的就是.text代码段,.data数据段,.rodata和.comment

对应的内存空间图如下

在这里插入图片描述

有一个专门的命令size,可以用来查看ELF文件的代码段,数据段和BSS段的长度(dec表示3个段长度和的十进制,hex表示长度和的十六进制)

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值