5

I'm new at C, so sorry for my lack of knowledge (my C-book here is really massive :)

I would like to extend a shared library (libcustomer.so) with closed source, but public known api.

Is something like this possible?

  1. rename libcustomer.so to liboldcustomer.so
  2. create an extended shared library libcustomer.so (so others implicitly use the extended one)
  3. link liboldcustomer.so into my extended libcustomer.so via -loldcustomer
  4. forward any not extra-implemented methods directly to the old "liboldcustomer.so"

I don't think it would work that way (the name is compiled into the .so, isn't it?). But what's the alternative?

For #4: is there a general way to do this, or do I have to write a method named like the old one and forward the call (how?)?

Because the original libcustomer.so (=liboldcustomer.so) can change from time to time, all that stuff should work dynamically.

For security reasons, our system has no LD_PRELOAD (otherwise I would take that :( ).

Think about extended validation-checks & some better NPE-handlings.

Thanks in advance for your help!

EDIT:

I'm just implementing my extension as shown in the answer, but I have one unhandled case at the moment:

How can I "proxy" the structs from the extended library?

For example I have this:

customer.h:

struct customer;

customer.c:

struct customer {
    int children:1;
    int age;
    struct house *house_config;
};

Now, in my customer-extension.c I am writing all the public methods form customer.c, but how do I "pass-thru" the structs?

Many thanks for your time & help!

Martin L.
  • 3,006
  • 6
  • 36
  • 60
  • The answer for your first additional question is already given. The second one is closely related - C/C++ does not contain any binary metainformation, like Java/.NET, so you cannot guess how the definition of a 'customer' structure might look like. Even if you remember the types and names of the fields in this structure, there might be problems with compiler settings - e.g., field alignment. – Viktor Latypov Jan 23 '13 at 20:06

1 Answers1

5

So you have OldLib with

void func1();
int  func2();
... etc

The step 4 might look like creating another library with some static initialization.

Create NewLib with contents:

void your_func1();

void (*old_func1_ptr)() = NULL;
int  (*old_func2_ptr)() = NULL;

void func1()
{
    // in case you don't have static initializers, implement lazy loading
    if(!old_func1_ptr)
    {
       void* lib = dlopen("OldLibFileName.so", RTLD_NOW);
       old_func1_ptr = dlsym(lib, "func1");
    }

    old_func1_ptr();
}

int func2()
{
    return old_func2_ptr();
}

// gcc extension, static initializer - will be called on .so's load
// If this is not supported, then you should call this function
// manually after loading the NewLib.so in your program.
// If the user of OldLib.so is not _your_ program,
// then implement lazy-loading in func1, func2 etc. - check function pointers for being NULL
// and do the dlopen/dlsym calls there.
__attribute__((constructor))
void static_global_init()
{
   // use dlfcn.h
   void* lib = dlopen("OldLibFileName.so", RTLD_NOW);

   old_func1_ptr = dlsym(lib, "func1");
   ...
}

The static_global_init and all the func_ptr's can be autogenerated if you have some description of the old API. After the NewLib is created, you certainly can replace the OldLib.

Viktor Latypov
  • 14,289
  • 3
  • 40
  • 55
  • Hello Viktor, I have removed the old questions as they where answered on other posts. Can you (or one other) tell me how I can do the proxying of "struct"s? I have extended my quesiton above with a concrete example for that. Thank you very much. – Martin L. Jan 23 '13 at 20:57
  • At the first sight, I see no principal difference between 'pcm*' and 'int'. 'int' was easier to type so I opted to use 'int' in my sample. I think you can just 'pass-through' the pointers to structures and even structures themselves. Just use the "original" struct definition from the .h-file accompanying the .so library. – Viktor Latypov Jan 23 '13 at 21:06
  • At this moment, I also learned that just structs decorated with `typedef` shoudl be exported :) (http://www.cs.swarthmore.edu/~newhall/unixhelp/howto_C_libraries.htm). Thank your for all your help! – Martin L. Jan 23 '13 at 21:44
  • I have now developed my extending library which forwards ~35 functions. It works like a charm (with your constructor :)! Thanks again Viktor, that's one of the best answer I have received yet on SO. – Martin L. Jan 25 '13 at 13:52
  • It wasn't that long ago when I first learned the "constructor" thing. And I'm just happy to share the knowledge. Wish we all had such a wonderful site 15 years ago ))) – Viktor Latypov Jan 25 '13 at 18:17