Overriding C library functions, calling original

后端 未结 4 1244
野性不改
野性不改 2020-12-03 11:00

I am a bit puzzled on how and why this code works as it does. I have not actually encountered this in any project I\'ve worked on, and I have not even thought of doing it my

相关标签:
4条回答
  • 2020-12-03 11:43

    The linker will search the files you provide on the command line first for symbols, before it searches in libraries. This means that as soon as it sees that getline has been defined, it will no longer look for another getline symbol. This is how linkers works on all platforms.

    This of course has implications for your fifth point, in that there is no possibility to call the "original" getline, as your function is the original from the point of view of the linker.

    For the fifth point, you may want to look at e.g. this old answer.

    0 讨论(0)
  • 2020-12-03 11:43

    What you see is expected behaviour if you linking with shared libraries. Linker will just assign it to your function, as it was first. It will also be correctly called from any other external libraries functions, - because linker will make your function exportable when it will scan linking libraries.

    But - if you, say, have no external libraries that links to your function (so it isn't marked exportable, and isn't inserted to symbol table), and then dlopen() some library that want to use it during runtime - it will not find required function. Furthermore, if you first dlopen(RTLD_NOW|RTLD_GLOBAL) original library, every subsequent dlopen()'d library will use this library code, not yours. Your code (or any libraries that you've linked with during compilation phase, not runtime) will still stick with your function, no matter what.

    0 讨论(0)
  • 2020-12-03 11:47

    There's no standard way to have two functions of the same name in your program, but with some UNIX-like implementations (notably GNU libc) you might be able to get away with this:

    #define _GNU_SOURCE
    #include <dlfcn.h>
    #include <stdio.h>
    
    ssize_t getline(char **lineptr, size_t *n, FILE *stream)
    {
       ssize_t (*realfunc)(char**, size_t *, FILE*) =
           (ssize_t(*)(char**, size_t *, FILE*))(dlsym (RTLD_NEXT, "getline"));
       return realfunc(lineptr, n, stream);
    }
    

    You will need to link with -ldl for this.

    0 讨论(0)
  • 2020-12-03 11:47

    What is happening here is that you are relying on the behaviour of the linker. The linker finds your implementation of getline before it sees the version in the standard library, so it links to your routine. So in effect you are overriding the function via the mechanism of link order. Of course other linkers may behave differently, and I believe the gcc linker may even complain about duplicate symbols if you specify appropriate command line switches.

    In order to be able to call both your custom routine and the library routine you would typically resort to macros, e.g.

    #ifdef OVERRIDE_GETLINE
    #define GETLINE(l, n, s) my_getline(l, n, s)
    #else
    #define GETLINE(l, n, s) getline(l, n, s)
    #endif
    
    #ifdef OVERRIDE_GETLINE
    ssize_t my_getline(char **lineptr, size_t *n, FILE *stream)
    {
       // ...
       return getline(lineptr, n, stream);
    }
    #endif
    

    Note that this requires your code to call getline as GETLINE, which is rather ugly.

    0 讨论(0)
提交回复
热议问题