-
Notifications
You must be signed in to change notification settings - Fork 2.5k
Description
NOTE: This is kind of a meta issue, regarding symbol versioning, and maybe even should be escalated to the glibc maintainers. However I became aware of it due to default symbol versioning mismatch comparing void-linux against another distribution, and like to first discuss the issue with the people who have to deal with that on a regular base in the context of maintaining this distribution.
TL;DR: The symbol versioning of some standard library functions that have been around for almost forever do not make a lot of sense. This might be either a glibc issue, or it might be a build configuration problem. Either way, it's semantically not correct and may cause problems for running stuff that's distributed in binary form (only), like games.
A customer whom I've sent a binary build of a library (confidential) I wrote (they just want to use it, not compile themself) reported an error that I immediately recognized as a symbol versioning issue. For the time being I just installed the Linux distribution they were using (Ubuntu 18.04.2 LTS) in a VM and built there. But the whole thing got me sleuthing because I took great care not to use anything "fancy" that'd make my code require a particularly "recent" version of libc.
I've built the library on void-linux, and a quick objdump -T immediately showed what was up:
.../build % objdump -T REDACTED_A.so | egrep 'GLIBC_2\.[0-9][0-9]'
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.14 memcpy
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.17 clock_gettime
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.27 expf
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.29 exp
../build % objdump -T REDACTED_B.so | egrep 'GLIBC_2\.[0-9][0-9]'
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.14 memcpy
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.29 log2
Seriously‽ With the exception of log2 these functions have been around for like forever. clock_gettime has been moved to glibc starting with version 2.17, before it was in librt.so. And log2 isn't that new either.
So let's see how the void-linux builds of libc.so, librt.so and libm.so export these:
~ % objdump -T /lib/libc.so.6 | egrep ' memcpy$| clock_gettime$'
000000000008b9e0 g iD .text 00000000000000b7 GLIBC_2.14 memcpy
00000000000a4640 g DF .text 0000000000000028 (GLIBC_2.2.5) memcpy
0000000000109530 w DF .text 000000000000006d GLIBC_2.17 clock_gettime
~ % objdump -T /lib/librt.so.1 | egrep ' clock_gettime$'
0000000000006000 g iD .text 0000000000000008 GLIBC_2.2.5 clock_gettime
~ % objdump -T /lib/libm.so.6 | egrep ' log2$| expf$'
0000000000042ba0 g iD .text 000000000000002a GLIBC_2.27 expf
0000000000015e70 g DF .text 0000000000000074 (GLIBC_2.2.5) expf
0000000000039a70 g DF .text 0000000000000302 GLIBC_2.29 log2
0000000000011e40 g DF .text 000000000000005e (GLIBC_2.2.5) log2
And all I have to say about this is: No! Just no! These functions have been around since almost the dawn of time. log2 was introduced even before "the Beaver was out of detox" (for those unfamiliar with the phrase, that's how Linus announced the release of the 2.6 series kernel). The only thing up there that's sensible is the symbol versioning reflecting the move of clock_gettime.
Now let's compare this with the versioning on the aforementioned Ubuntu installation:
~ % objdump -T /lib/x86_64-linux-gnu/libc.so.6 | egrep ' memcpy$| clock_gettime$'
000000000009f0e0 g iD .text 00000000000000ca GLIBC_2.14 memcpy
00000000000bb460 g DF .text 0000000000000028 (GLIBC_2.2.5) memcpy
0000000000130e80 w DF .text 000000000000006d GLIBC_2.17 clock_gettime
~ % objdump -T /lib/x86_64-linux-gnu/librt.so.1 | egrep ' clock_gettime$'
0000000000005220 g iD .text 0000000000000008 GLIBC_2.2.5 clock_gettime
So there's agreement for at least these symbols in libc and librt (different versions nonwithstanding). But in libm there is a discrepancy:
~ % objdump -T /lib/x86_64-linux-gnu/libm.so.6 | egrep ' log2$| expf$'
000000000004a790 g iD .text 000000000000002a GLIBC_2.27 expf
0000000000012770 g DF .text 0000000000000072 (GLIBC_2.2.5) expf
000000000000e9e0 w DF .text 000000000000005e GLIBC_2.2.5 log2
log2 and expf (which BTW have both been introduced at the same time) are versioned differently from the void-linux package. If this is due to different glibc versions or due to different build configurations I cannot tell. But it's irritating. IMHO the symbols versions should default to the version they were introduced, and symbol versions should not be bumped up, if the symbols' ABI didn't change.