共享对象(库)数据段地址无干性

共享对象(库)数据段地址无关性
在看《程序员的自我修养——链接、装载与库》,发现相见恨晚。一口气看了不少。
在7.3.5节开头是这样的:

共享对象(库)数据段地址无干性

大牛能解释一下,为何变量a是地址无关的(地址随着装载而改变),而变量p是绝对地址?

------解决方案--------------------
这句话应该是说在编译后,p的值会被赋上a在当前编译后在数据段的地址,这个值就是一个绝对地址,但当a被重定位之后,a的地址发生了变化,如果要正常使用,p被赋的初值也应该随着这个重定位进行设置成a重定位之后的值。
------解决方案--------------------
数据段也可以使用地址无关的方式访问, 只是数据段本来就会被写入, 写入就会触发 Copy On Wrtie 进行内存拷贝. 既然本身数据段就会被拷贝了, 那么通过重定位修改下它就不存在多占用内存的问题. 而使用地址无关的方式反而会影响访问效率, 权衡之后觉得不使用更好.

代码段和数据段只要有任何一个有需要重定位的, 就会产生重定位表项, 并不能根据有重定位表项就判断出代码段也采用了重定位.


------解决方案--------------------
引用:
Quote: 引用:

a 在数据段中, 地址是相对于 dll 基址动态变化. 而 p 所指向的地址是一个内存中的数据, 是和 dll 基址无关的.
p是指针,指向的是a的地址。在链接或装载时,a根本不在内存,而最多是在共享对象(库)的虚拟空间里,那么p怎么可能指向一个内存地址?编译链接时p应该怎么初始化?p的初始化发生在什么时候?

你说的,p指向的地址是内存地址,这个是进程在运行时,a的地址肯定是确定的内存地址,p的赋值最终也会是a所在的内存地址。我疑惑的是这段话里到底要表达什么意思?我有点儿云里来,雾里去。。。

你也可帮我看一下3楼我的回复那里有全文的截图。

谢谢!共勉进步,共享对象(库)数据段地址无干性


在链接的时候, 虽然不存在真实的内存, 但是链接器会产生一个虚拟内存布局. 这个布局表明了如果这个动态库按设定的基地址加载, 哪个变量就会在哪个位置. 链接器以这个基准推导出 a 在运行时候的内存地址, 把这个地址写入 p 这个变量所对应的文件位置, 文件位置加载到内存后就对应 p 变量的地址, 写入的内容就是 p 初始化成什么内容. 所以, 可以说 p 的初始化是发生在链接期间的.
 
------解决方案--------------------
1.
意思是这样,
不过应该不是说成"数据段和代码段可以使用不同的链接方式", 
而是使用相同的链接方式, 代码段和数据段的重定位处理方法可能不同.

使用 -fPIC 选项: 代码段用位置无关代码, 数据段用重定位表.
   不使用该选项: 代码段用重定位表, 数据段用重定位表.

2. 没有指针 p 的话, 数据段中就没有保存地址, 没有需要重定位的东西.

3. 见 6 楼, C 里面的全局变量是链接时候初始化的. (C++ 引入的构造函数打破了这个规律. 如果一个全局对象有构造函数, 它的构造函数只能是运行期来调用. 对象就是运行期初始化的了)
------解决方案--------------------
1. 恩, 数据段没有共享内存的需求, 不需要.
3. C 语言还是编译链接的时候就初始好了的, 像这种代码, 在 C++ 里可以, 在 C 里面就不行: