This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Force specified function to be linked to a specified lib whencompiling/linking


On Thu, Jul 20, 2017 at 02:26:22PM -0400, Carlos O'Donell wrote:
> On 07/20/2017 12:28 PM, Yubin Ruan wrote:
> > Hi,
> > 
> > I am wondering whether it is possible to force the linker to use some
> > specified function to link to when compiling/linking.
> > 
> > I am using the LD_PRELOAD environment variable to hook some specified
> > functions but I am not so familiar with linker so there are some
> > troubles. I am hooking the standard `open' system call to add some
> > functionalities, so that when users use the `open' system call, I can
> > collect some data. Basically I am doing something like this:
> > 
> >     int open(int fd, int flags, ...) {   /* (1) */
> >         ...
> >         /* add some functionalities here */
> >         ...
> > 
> >         return open(...);   /* (2) return the original open function call */
> >     }
> > 
> > Obviously, this cannot work, as it would call into a infinite loop...
> > So I am wondering whether I can force the linker to link some function
> > to some specified dynamic library so that it would not cause infinite
> > loop. In the example above, it would be perfect for the `open()'
> > system call at (2) to be linked to the standard library, rather than
> > the one that I hook.
> > 
> > As for now, because I set the LD_PRELOAD as:
> > 
> >     export LD_PRELOAD=/path/to/my_open.so
> > 
> > whenever a program that have a `open()' function inside is loaded, the
> > dynamic linker would link that `open()' to my ``my_open.so''. And that
> > is the same for my ``open'': when the linker try to link the `open()'
> > at (2), it would also try to link that to my `open()' at (1),
> > resulting in a infinite loop.
> > 
> > Any idea?
> 
> (1) Use ld's --wrap=symbol.
> 
> See the man page for details.

ld's --wrap=symbol is almost perfect, but it is also almost useless, because
it requires users of the .so file to be aware of the "wrapped" function and
pass in a --wrap=symbol when compiling. For example, imagine that we want to
"wrap" the standard malloc function like this:

    void *
    __wrap_malloc(size_t size)
    {
        printf("in __wrap_malloc");
        return __real_malloc(size);
    }

and creat a .so from it:

    $ gcc -shared -fPIC my-wrap-malloc.c -o my-wrap-malloc -Wl,--wrap-malloc

and then user can create a program, say:
    
    int main()
    {
        int *ptr = malloc(100);
        if (ptr)
            puts("malloc success");
        return 0;
    }

but, to use the "my-wrap-malloc.so" we created before, users also have to
pass in the --wrap=malloc when compiling:
    
    $ gcc main.c -o main -Wl,--wrap=malloc

and that is not transparent. It require that users are aware of the customized
malloc function (because they have to pass in --wrap=malloc). It is as if to
tell users "hey, we created a customized malloc that is really fast, to use it,
just pass in a "--wrap=malloc" flag when compiling. But, if we have to notify
users, why don't we just create something like "fmalloc":

    void * fmalloc(size_t size)
    {
        /* do something here */

        return malloc(size);
    }

and tell users to use the new `fmalloc', which is more clear.

What I want to do here is to have the internal standard malloc linked to the
right place, not the one we created:

    void *
    malloc(size_t size)
    {
        /* do something here */

        return __real_malloc(size);
    }

as you see, I want the `__real_malloc' to be linked to the standard malloc
implementation. And in this situation, user don't know any internal changes.
They just use it as usual.
 
> (2) Use libdl's dlopen().
> 
> Use dlopen to get the real open() from libc.so.6, and then
> call that through the handle returned from dlsym().

This works for some libc functions such as "malloc", but it doesn't work for
`open()'. open() is a system call, and dlopen(), which is a libc function, use
open internally, so you still have infinite loop here.

--
Yubin


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]