4

Well I couldn't find very nice short phrase for my question title, but here is what I mean:

I have a library that interposes some syscalls like open(2). I use this method for interposing. I add it to DYLD_INSERT_LIBRARIES in order to achieve my goal.

The library that contains the interposing code is a.dylib.

I need to link a library b.dylib to a.dylib because it contains some functions that a.dylib needs.

The issue is a.dylib interposes functions in b.dylib too which I don't want.

I am not an expert with linking. Is there any way to prevent this behaviour and what's the reason behind this happening?

UPDATE:

This is how b.dylib is built:

clang -dynamiclib -fPIC -Wextra -Wall -pedantic -Wl,-single_module <object files> -o b.dylib -install_name <path>

This is how a.dylib is built:

clang -dynamiclib -fPIC -Wextra -Wall -pedantic -Wl,-single_module <object files> -o a.dylib -install_name <path> b.dylib

Only a.dylib is added to the end of DYLD_INSERT_LIBRARIES.

Community
  • 1
  • 1
Mihir Luthra
  • 6,059
  • 3
  • 14
  • 39
  • How are you linking `a.dylib` and `b.dylib` together? Show the compile commands; the example you show has only one `dylib` linking to an executable. – l'L'l Feb 07 '20 at 17:59
  • @l'L'l, updated. I should have added that from before. If any more info needed, please ask. Thanks. – Mihir Luthra Feb 07 '20 at 18:12
  • Could you also show `` and `-install_name `, it's unclear what you have there. It seems more an issue of how you are using `-install_name`, rather you are injecting `a.dylib` into `b.dylib`. – l'L'l Feb 07 '20 at 21:00
  • @l'L'l, path is just installaion location of the library which is different for both. Like I install `a.dylib` to a location `/path/to/alib` and similarly `b.dylib` to some other location. Object files are just `.o` files which are different for both. I am not getting it. Are those concerned with the question? Can you help me understand? – Mihir Luthra Feb 07 '20 at 21:04
  • Also, I am pretty sure library paths are correctly set and linked. Otherwise how would have the call in b.dylib got intercepted? Am I missing something? – Mihir Luthra Feb 07 '20 at 21:05
  • I think you want the opposite (eg. `-o b.dylib -install_name a.dylib`) – l'L'l Feb 07 '20 at 21:06
  • I think that would mean linking `a.dylib` to `b.dylib`. But I want to link b.dylb to a.dylib because a.dylib needs b.dylib and not vice-versa. – Mihir Luthra Feb 07 '20 at 21:09
  • It’s still unclear what you’re actually doing. What are you interposing ( a or b ) and do they link to something else? – l'L'l Feb 08 '20 at 03:56
  • a.dylib interposes `open` and a.dylib depends on, say, `processFile` in b.dylib and you want `processFile` to call the `open` defined in the C library and not have its `open` interposed. Have I got that right? If so, should every execution of `processFile` not have its open interposed? Can b.dylib be loaded without a.dylib? – Jeff Holt Feb 12 '20 at 21:30
  • @JeffHolt , right. – Mihir Luthra Feb 13 '20 at 06:51

1 Answers1

1

You say a.dylib depends on b.dylib but b.dylib does not depend on a.dylib and that you want no calls in b.dylib to ever be interposed. You gave open as an example of an interposed function.

The example I gave was that a.dylib needs to call processFile that is defined in b.dylib and it opens files. You don't want the open call in b.dylib to be interposed ever (whether a.dylib is loaded or not).

The only way I know to pull this off is for processFile to dynamically load the C library instead of letting ld do it automatically.

There are two problems with this approach. The first is that each function that needs to call open will need one additional if statement to execute the code to resolve the symbol.

The other is that you need to know ahead of time the filename of the C library to load. And if there's a problem resolving the symbol, then you have to deal with a situation that most programs don't have to deal with; at least at a later time.

The code will look something like this:

void processFile (char * filename) {
    FILE *fp;
    // c_open can have file scope if thread safety isn't needed
    static int (*c_open)() = NULL;

    if (c_open == NULL) {
        // factor this if more than one function needs open
        void *dlh = dlopen(C_LIBRARY_FILENAME, RTLD_LAZY);
        if (dlh == NULL) {
           perror("cannot load C library");
           exit(1);
        }
        c_open = dlsym(dlh, "open");
        if (c_open == NULL) {
           perror("cannot resolve open in the C library");
           exit(1);
        }
    }
    c_open(filename, O_RDONLY);
    ...
}

UPDATE

If you do not specify the full pathname to the C library, dlopen could open an unexpected file.

Jeff Holt
  • 2,940
  • 3
  • 22
  • 29
  • Probably not the answer I actually expected. Never thought it this way. But this _does_ solve the problem. Thanks for the answer and I really like the idea. – Mihir Luthra Feb 13 '20 at 14:10
  • 1
    It looked like you wanted something special that `ld` would do when it loads `b.dylib`; like a feature declared when `b.dylib` was written that informs `ld` "to not resolve a symbol to any library other than the one used at the time `b.dylib` was written". I don't believe any such feature exists. – Jeff Holt Feb 13 '20 at 14:16
  • Yep, that's what I was looking for. But if such a feature doesn't exist, your answer would probably be the best fit-in. – Mihir Luthra Feb 13 '20 at 14:40