Why are different symbols in libc declared with different bindings,

1510 0x0003d200 0xf7d55200   WEAK   FUNC   55 system
 454 0x00067b40 0xf7d7fb40   WEAK   FUNC  474 puts
 147 0x000303d0 0xf7d483d0 GLOBAL   FUNC   33 exit

From readelf -s /lib/i386-linux-gnu/libc-2.27.so,

1510: 0003d200    55 FUNC    WEAK   DEFAULT   13 system@@GLIBC_2.0
 454: 00067b40   474 FUNC    WEAK   DEFAULT   13 puts@@GLIBC_2.0
 147: 000303d0    33 FUNC    GLOBAL DEFAULT   13 exit@@GLIBC_2.0

From this question, it seems like the authors' libc has a LOCAL exit?

What the rhyme or reason behind the different libc binding levels?


Weak symbols in glibc permit overriding even under static linking.

The global exit is a strong symbol. Additional definitions will not resolve, and will raise linking errors.

Thus you might be able to supply your own puts, and barring a second definition of puts that is strong, the puts with the largest memory occupation (size) will be chosen.

Why the largest size? Well, GCC needs some discriminator, and most of the glibc is structured such that the public symbols are nearly universally aliased to private symbols, which means the size is rather small (a jump). This means that if you provide your own implementation of puts, unless you structure it to alias exactly the same way, odds are you implementation is larger. For puts the alias directs to __IO_puts.

This is the mechanism by which the standard library both provides implementations of standard library calls and permits you to override them.

  • I agree, but I think the question remains. Why? Why is that I can override puts but not exit? Why is only puts, and not exit, a WEAK alias of an internal symbol? – Evan Carroll Oct 31 '18 at 20:08
  • exit has non override-able behavior because it is a routine that handles the shutdown of processes with the operating system. Any "external" implementation is likely to break the contracts between the operating system and the process model it expects. Remember, the program doesn't really return the exit code to the parent process, it signals it to the kernel, which then provides it to the parent process. There are other shutdown hooks available if you want on-exit behavior, namely atexit(...) – Edwin Buck Nov 1 '18 at 15:03

The answer to the question of what is happening from a technical viewpoint is that it's an implementation detail for the reasons Edwin mentioned about (symbol aliasing). But moreover, why it's there is that it's happenstance, and that it would be suitable for a patch.

15:14 < azanella> EvanCarroll, it is an implementation detail, exit is not used internally so there is no need to define an internal symbol with a alias to it [...] system and puts are both implemented by different symbols with alias to them [...] but it is a good question though, I believe for exit case it glibc is not really static linking focused and no one has raised any issue on trying to override it in static linking

From #glibc on irc.freenode.net on Oct 31, 2018

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.