指令和地址分开原因:(P59)
1、独立权限,防止程序指令非预期改写
程序装载后,数据和指令分别被映射到两个虚存区域。由于数据区域对于进程来说是可读写的,而指令区域对于进程来说是只读的,所以这两个虚存区域的权限可以被分别设置为可读写和只读。这样可以防止程序的指令被有意或者无意地改写。
2、提高 CPU 缓存命中率
指令区和数据区的分离有利于提高程序的局部性。
3、节省内存占用
等系统中运行着多个该程序的副本时,他们的指令都是一样的,所以内存中只需要保存一份该程序的指令部分。而每个副本进程的数据区域是不一样的,他们是进程私有的。
.bss 段和 .data 段 (P59、P65、P66、P111)
- .bss 段只是为“未初始化的全局变量和局部静态变量预留位置,它并没有内容,所以它在文件中不占据空间”
- .data 段保存的是“已经初始化了的全局静态变量和局部静态变量”
注:有些编译器会将全局的未初始化变量存放在目标文件的.bss 段,有些则不存放,只是预留一个未定义的全局变量符号,等到最终链接成可执行文件的时候再在.bss 段分配空间。原则上讲,我们可以简单地把它当做全局未初始化变量存放在.bss段。值得一提的是编译单元内部可见的静态变量的确是存放在.bss 段的
原因:
1、“未初始化的全局变量”在目标文件中并未放到 .bss 段中,而是标记为一个 COMMON 类型的变量,这是因为“未初始化的全局变量”是一个弱符号,其最终占用的大小未知,所以编译器此时无法为该弱符号在 BSS 段分配空间
,也即不能放在 .bss 段中,而链接器在链接过程中就能确定弱符号的大小了,所以“未初始化的全局变量”可以放在最终输出文件的 .bss 段中
现在我们再回头总结性地思考关于未初始化的全局变量的问题:在目标文件中,编译器
为什么不直接把未初始化的全局变量也当作未初始化的局部静态变量一样处理,为它在 BSS
段分配空间,而是将其标记为一个 COMMON 类型的变量?
通过了解链接器处理多个弱符号的过程,我们可以想到,当编译器将一个编译单元编译
成目标文件的时候,如果该编译单元包含了弱符号(末初始化的全局变量就是典型的弱符
号),那么该弱符号最终所占空间的大小在此时是未知的,因为有可能其他编译单元中该符
号所占的空间比本编译单元该符号所占的空问要大。所以编译器此时无法为该弱符号在 BSS
段分配空间,因为所须要空间的大小末知。但是链接器在链接过程中可以确定弱符号的大小,
因为当链接器读取所有输入目标文件以后,任何一个弱符号的最终大小都可以确定了,所以
它可以在最终输