pimpl idiom通常用於允許更改動態鏈接庫中的代碼而不破壞ABI兼容性,並且必須重新編譯依賴於庫的所有代碼。添加私有成員變量如何破壞C++ ABI兼容性?
大部分explanations我看到提到添加一個新的私有成員變量會改變班級中公共和私人成員的偏移量。這對我來說很有意義。我不明白的是,實際上這是如何打破依賴庫的。
我已經做了很多關於ELF文件的閱讀以及動態鏈接是如何實際工作的,但是我仍然沒有看到如何改變共享庫中的類大小會破壞事情。
E.g.下面是測試應用(a.out的)我寫從測試共享庫(libInterface.so)使用代碼(Interface::some_method
):
[email protected]:~/pimpl$ objdump -d -j .text a.out
08048874 <main>:
...
8048891: e8 b2 fe ff ff call 8048748 <[email protected]>
到some_method
呼叫使用程序鏈接表(PLT):
[email protected]:~/pimpl$ objdump -d -j .plt a.out
08048748 <[email protected]>:
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>
隨後前進到全局偏移表(GOT),其中地址0x804a01c包含:
[email protected]:~/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 ....
然後這是,動態連接器WO通過LD_LIBRARY_PATH中的共享庫中包含的所有符號查找它,並在libInterface.so中找到Interface::some_method
並將其代碼加載到GOT中,因此在隨後調用some_method
時,GOT中的代碼實際上是來自共享的代碼段圖書館。
或沿着這些線。
但是鑑於上述情況,我仍然不明白共享庫的類大小或其方法偏移量如何在這裏發揮作用。據我所知,上述步驟對班級人數不可知。它看起來像庫中方法的名稱名稱包含在a.out中。當鏈接器將代碼加載到GOT中時,任何類大小變化都應該在運行時解決,否?
我在這裏錯過了什麼?
啊哈!得到它了。事實上,在調用Interface的ctor之前,在反彙編中稍微看一下,我可以看到它爲該對象分配了空間(在本例中爲4字節)。 – adg