overriding __ functions
Mark Kettenis
kettenis@wins.uva.nl
Thu Dec 3 05:19:00 GMT 1998
Date: Thu, 3 Dec 1998 05:10:52 -0500 (EST)
From: baccala@FreeSoft.org
I raised this question because in the announcement for glibc 2.0.103,
drepper stated:
> I got in the last time reports about some programs which used the
> symbols starting with an underscore which were available in glibc 2.0.
> People, the leading underscore means these are internal symbols and
> must not be used. There are only very few exceptions. Never use
> them. In future this will be enforced automatically since these
> symbols are not anymore exported. For existing programs with this
> problem you can either recompile them or in some cases (if there is a
> counterpart without the lading underscores) edit the binary and change
> __XXX into XXX. This is reported to be working with at least one X
> server.
Let's make one point clear. No user program should reference the
__-prefixed symbols. Any user program that reference a __-prefix
symbol is BROKEN, and should be fixed the way Ulrich suggested.
However a lot of people don't read the documentation and use the
__-interfaces when they see they're available. That's why we don't
make them available anymore. They are internal interfaces which might
be removed added or changed whenever the need arises.
I'm somewhat alarmed, since I have LD_PRELOAD libraries that
override __ functions. I hope glibc 2.1 isn't going to break this,
but drepper's posting leaves this point unclear in my mind. When
exactly is the "future"?
To answer my own question, I think a strong case can be made for allowing
at least some of these symbols to be overridden, and therefore
they must be exported.
A preloaded library wishing to override glibc functions can be operating
in one of two modes. First, it wishes to override things like fopen()
and getcwd(), and thus be layered between the user program and glibc,
like so:
+-------------------------------------+
+----------------+ USER PROGRAM +
+ PRELOAD LIBRARY >>>------------------------------+
+----------------+ GLIBC +
+-------------------------------------+
+ KERNEL +
+-------------------------------------+
The second mode would be a wish to override things like __open() and
__xstat(), and thus be layered between the glibc and the kernel:
+-------------------------------------+
+ USER PROGRAM +
+-------------------------------------+
+----------------+ GLIBC +
+ PRELOAD LIBRARY >>>------------------------------+
+----------------+ KERNEL +
+-------------------------------------+
Both forms should be supported. My programs work by overloading
the system calls, expecting to grab everything that calls open(),
be it the user program or glibc.
If anybody wants a concrete example of the usefulness of this feature,
email me and I'll send you a copy of some of my programs.
The natural interpretation of __ functions, IMHO, is that they are
the routines you override if you want to intercept system calls just
before they hit the kernel. Other __ functions, that don't correspond
to system calls, don't really enter the picture.
If any can suggest another way of doing this, short of overriding fopen()
and catopen() and dlopen() and anything else that conceivably make
a system call to __open(), please let me know.
To my original posting, Mark Kettenis replied:
>
> The System V ABI documentation suggests that if an application wants
> to override a symbol for which a global alias exists (such as
> open()/__open() in your example), it must define both symbols to point at
> the same object. So your case appears to be "undefined". However it
> makes sense that the weak alias for open() in libc would still point
> at libc's __open(), which IMHO is the only sensible thing.
>
> Mark
OK, if it's "undefined" I can live with it, but it doesn't make sense
to me.
I mean, if I wrote two definitions of open(), the first:
int open(...) __attribute__((weak, alias("__open"))
basically what we've got now, and the second:
int open(...) __attribute__((weak)) { return __open(...); }
And then I overrode __open() in an LD_PRELOAD library, the first form
(the alias) would cause open() to continue calling the old __open(),
while the second form of open() (the springboard function) would
follow along to the new __open().
Does this make any sense at all?
Doesn't this seem completely broken?
OK, this is how I understand how things are:
If both foo() and __foo() exist in glibc, __foo() is the
real function, and foo() is a weak alias.
If you override foo() in your preloaded library, all user programs
will use the foo() in your preloaded library (since there should not
be any user programs that reference __foo()), and all glibc-internal
calls will not because they use __foo(). If the foo() in your
preloaded library wishes to call foo() in libc, it should do so via
dlsym (RTLD_NEXT, "foo"). This in principle even allows multiple
preloaded libraries overriding the same function, and corresponds to
your first example where the preloaded library sits between the user
program and libc.
If you override __foo() in your preloaded library, all glibc internal
calls will call __foo() in your preloaded library. But all user
programs will still use __foo() in glibc, because the weak alias foo()
still points there. In order to make user programs use __foo() in
your preloaded library you have to provide a weak alias foo() in your
preloaded library. Again, you should use dlsym() if you want to use
glibc's foo/__foo in your preloaded library. This corresponds to your
second example, where the preloaded library sits between glibc and the
kernel. This will fail if __foo() is not exported by glibc.
Therefore this might be an argument for the case that, if foo() is
nothing but an alias for __foo(), glibc should export both foo() and
__foo(), and should continue to do so in the future.
Things get a bit problematic when only the symbol foo() exists in
glibc. In that case your preloaded library can override foo() but
should make sure it does the right thing when a glibc-internal
function calls foo(). If your preloaded library is well designed,
this shouldn't be too hard. Again, if you want to call glibc's foo()
you should use dlsym.
Mark
More information about the Libc-hacker
mailing list