共享对象(库)数据段地址无关性
在看《程序员的自我修养——链接、装载与库》,发现相见恨晚。一口气看了不少。
在7.3.5节开头是这样的:
大牛能解释一下,为何变量a是地址无关的(地址随着装载而改变),而变量p是绝对地址?
在链接的时候, 虽然不存在真实的内存, 但是链接器会产生一个虚拟内存布局. 这个布局表明了如果这个动态库按设定的基地址加载, 哪个变量就会在哪个位置. 链接器以这个基准推导出 a 在运行时候的内存地址, 把这个地址写入 p 这个变量所对应的文件位置, 文件位置加载到内存后就对应 p 变量的地址, 写入的内容就是 p 初始化成什么内容. 所以, 可以说 p 的初始化是发生在链接期间的.
[解决办法]
1.
意思是这样,
不过应该不是说成"数据段和代码段可以使用不同的链接方式",
而是使用相同的链接方式, 代码段和数据段的重定位处理方法可能不同.
使用 -fPIC 选项: 代码段用位置无关代码, 数据段用重定位表.
不使用该选项: 代码段用重定位表, 数据段用重定位表.
2. 没有指针 p 的话, 数据段中就没有保存地址, 没有需要重定位的东西.
3. 见 6 楼, C 里面的全局变量是链接时候初始化的. (C++ 引入的构造函数打破了这个规律. 如果一个全局对象有构造函数, 它的构造函数只能是运行期来调用. 对象就是运行期初始化的了)
[解决办法]
1. 恩, 数据段没有共享内存的需求, 不需要.
3. C 语言还是编译链接的时候就初始好了的, 像这种代码, 在 C++ 里可以, 在 C 里面就不行:
int fff()
{
return 10;
}
void yyy()
{
static int x = fff();
}
static int z = fff();
[解决办法]
其实不论是 C 还是 C++, 在 main 还是之前都还有其它代码运行. C 不支持运行期初始化不应该是实现上做不到, 而是不想把事情弄复杂了.
一个没有不接受任何输入的程序确实没有什么存在的意义, 当然, 这个输入不刚是指的键盘输入, 命令行参数这些. 读取硬盘, 访问硬件, 访问网络, 调用系统 API 之类的获得的数据都应该叫输入. 只要数据不是从程序中自己产生的, 都算输入. 这样定义的话, 没有输入的程序确实就没有什么意义了.