adg*_*adg 13 c++ linker shared-libraries elf abi
的平普尔成语,以便允许改变动态链接库的代码而不破坏ABI兼容性和重新编译所有依赖于库中的代码通常使用的.
我看到的大多数解释都提到添加一个新的私有成员变量会改变类中公共成员和私有成员的偏移量.这对我来说很有意义.我不明白的是,实际上这实际上打破了依赖库.
我已经做了很多的阅读ELF文件,以及如何动态链接实际工作,但我仍然没有看到如何在共享库改变类规模将破事.
例如,这是我编写的测试应用程序(a.out),它使用Interface::some_method来自测试共享库(libInterface.so)的code():
aguthrie@ana:~/pimpl$ objdump -d -j .text a.out
08048874 <main>:
...
8048891: e8 b2 fe ff ff call 8048748 <_ZN9Interface11some_methodEv@plt>
Run Code Online (Sandbox Code Playgroud)
some_method使用程序链接表(PLT)的调用:
aguthrie@ana:~/pimpl$ objdump -d -j .plt a.out
08048748 <_ZN9Interface11some_methodEv@plt>:
8048748: ff 25 1c a0 04 08 jmp *0x804a01c
804874e: 68 38 00 00 00 push $0x38
8048753: e9 70 ff ff ff jmp 80486c8 <_init+0x30>
Run Code Online (Sandbox Code Playgroud)
随后进入全局偏移表(GOT),其中包含地址0x804a01c:
aguthrie@ana:~/pimpl$ readelf -x 24 a.out
Hex dump of section '.got.plt':
0x08049ff4 089f0408 00000000 00000000 de860408 ................
0x0804a004 ee860408 fe860408 0e870408 1e870408 ................
0x0804a014 2e870408 3e870408 4e870408 5e870408 ....>...N...^...
0x0804a024 6e870408 7e870408 8e870408 9e870408 n...~...........
0x0804a034 ae870408 ....
Run Code Online (Sandbox Code Playgroud)
然后这就是动态链接器工作的魔力,并查看LD_LIBRARY_PATH中共享库中包含的所有符号,Interface::some_method在libInterface.so中找到并将其代码加载到GOT中,以便在后续调用时some_method,GOT中的代码实际上是共享库中的代码段.
或类似的规定.
但鉴于上述情况,我仍然不明白共享lib的类大小或其方法偏移是如何发挥作用的.据我所知,上述步骤与班级规模无关.看起来只有库中方法的符号名称包含在a.out中.当链接器将代码加载到GOT中时,应该在运行时解析类大小的任何更改,不是吗?
我在这里错过了什么?
bdo*_*lan 16
主要的问题是,当你分配一个类(在栈上,或通过的新实例new),调用代码需要知道对象的大小.如果稍后更改对象的大小(通过添加私有成员),则会增加所需的大小; 但是你的来电者仍在使用旧尺寸.所以你最终没有分配足够的空间来容纳对象,然后对象的构造函数继续破坏堆栈(或堆),因为它假设它有足够的空间.
此外,如果您有任何内联成员函数,则可以将其代码(包括成员变量的偏移量)内联到调用代码中.如果您将私有成员添加到除结尾之外的任何位置,这些偏移将不正确,也会导致内存损坏(注意:即使您添加到最后,大小不匹配仍然是一个问题).