Our project (C++, Linux, gcc, PowerPC) consists of several shared libraries. When releasing a new version of the package, only those libs should change whose source code was actually affected. With "change" I mean absolute binary identity (the checksum over the file is compared. Different checksum -> different version according to the policy). (I should mention that the whole project is always built at once, no matter if any code has changed or not per library).
Usually this can by achieved by hiding private parts of the included Header files and not changing the public ones.
However, there was a case where a mere delete
was added to the destructor of a class TableManager (in the TableManager.cpp file!) of library libTableManager.so, and yet the binary/checksum of library libB.so (which uses class TableManager ) has changed.
TableManager.h:
class TableManager
{
public:
TableManager();
~TableManager();
private:
int* myPtr;
}
TableManager.cpp:
TableManager::~TableManager()
{
doSomeCleanup();
delete myPtr; // this delete has been added
}
By inspecting libB.so with readelf --all libB.so
, looking at the .dynsym section, it turned out that the length of all functions, even the dynamically used ones from other libraries, are stored in libB! It looks like this (length is the 668 in the 3rd column):
527: 00000000 668 FUNC GLOBAL DEFAULT UND _ZN12TableManagerD1Ev
So my questions are:
Bingo. It is actually kind of a "bug" in binutils which they found and fixed in 2008. The size information is actually not useful!
What Simon Baldwin wrote in the binutils mailing list describes exactly the problem ( emphases by me):
Currently, the size of an undefined ELF symbol is copied out of the object file or DSO that supplies the symbol, on linking. This size is unreliable, for example in the case of two DSOs, one linking to the other. The lower- level DSO could make an ABI-preserving change that alters the symbol size, with no hard requirement to rebuild the higher-level DSO. And if the higher- level DSO is rebuilt, tools that monitor file checksums will register a change due to the altered size of the undefined symbol, even though nothing else about the higher-level DSO has altered. This can lead to unnecessary and undesirable rebuild and change cascades in checksum-based systems.
We have the problem with an older system (binutils 2.16). I compared it with version 2.20 on the desktop system and - voilà - the lengths of shared global symbols were 0:
157: 00000000 0 FUNC GLOBAL DEFAULT UND _ZN12TableManagerD1Ev
158: 00000000 0 FUNC GLOBAL DEFAULT UND _ZNSs6assignERKSs@GLIBCXX_3.4 (2)
159: 00000000 0 FUNC GLOBAL DEFAULT UND sleep@GLIBC_2.0 (6)
160: 00000000 0 FUNC GLOBAL DEFAULT UND _ZN4Gpio11setErrorLEDENS_
So I compared both binutils source codes, and - voilà again - there is the fix which Alan suggested in the mailing list:
Maybe we just apply the patch and recompile binutils since we need to stay with the olderish platform. Thanks for your patience.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With