扩展动态链接共享库?

5

我刚开始学习 C,对知识的缺乏感到抱歉(我的 C 书很多)。

我想用已知的公共 API 扩展一个共享库 (libcustomer.so),但该库是封闭源代码。

这种情况可能吗?

  1. 将 libcustomer.so 重命名为 liboldcustomer.so
  2. 创建一个扩展的共享库 libcustomer.so(因此其他人会隐式地使用扩展版)
  3. 通过 -loldcustomer 将 liboldcustomer.so 链接到我的扩展 libcustomer.so 中
  4. 将任何未额外实现的方法直接转发到旧的 "liboldcustomer.so"

我认为这样不行(名称编译到 .so 中了,不是吗?)。但是有什么替代方案吗?

对于#4:是否有一般方法来解决此问题,还是我必须编写一个类似旧方法的命名并转发调用(如何实现?)?

由于原始的 libcustomer.so (=liboldcustomer.so) 可能会随时更改,因此所有这些都应动态工作。

由于安全原因,我们的系统没有 LD_PRELOAD(否则我会采用它 :( )。

考虑扩展验证检查和一些更好的 NPE 处理。

感谢您提前的帮助!

编辑:

我正在按照答案所示实现我的扩展,但目前有一个未处理的情况:

如何“代理”来自扩展库的结构体?

例如,我有这个:

customer.h:

struct customer;

customer.c:

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

现在,在我的customer-extension.c文件中,我正在编写来自customer.c的所有公共方法,但是如何“传递”结构体呢?

非常感谢您的时间和帮助!


你的第一个附加问题已经有答案了。第二个问题与之密切相关 - C/C++不包含任何二进制元信息,如Java/.NET,因此你无法猜测“客户”结构的定义可能是什么样子。即使你记得这个结构中字段的类型和名称,也可能会出现编译器设置的问题 - 例如,字段对齐。 - Viktor Latypov
1个回答

5

所以你有一个名为OldLib的库,其中包含

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

第四步看起来像是创建另一个带有一些静态初始化的库。
创建NewLib并添加以下内容:
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");
   ...
}

如果您有旧API的描述,可以自动生成static_global_init和所有func_ptr。创建NewLib后,您可以将OldLib替换。


你好 Viktor,我已经删除了旧的问题,因为它们在其他帖子中得到了回答。你(或其他人)能告诉我如何代理“struct”吗?我已经在上面扩展了我的问题,并提供了一个具体的例子。非常感谢。 - Martin L.
乍一看,我看不出'pcm *'和'int'之间有什么本质区别。 'int'更容易输入,因此我选择在示例中使用'int'。我认为您可以将指向结构体甚至结构体本身的指针“直接传递”。只需使用伴随.so库的.h文件中的“原始”结构定义即可。 - Viktor Latypov
此时,我也学到了只有用typedef修饰的结构体才能被导出 :) (http://www.cs.swarthmore.edu/~newhall/unixhelp/howto_C_libraries.htm)。感谢您的所有帮助! - Martin L.
我现在开发了一个扩展库,可以转发约35个函数。它非常好用(需要使用您的构造函数 :)!)再次感谢维克多,这是我在SO上收到的最佳答案之一。 - Martin L.
并不是很久以前,我第一次学习了“构造函数”的概念。我很高兴能够分享这个知识。希望我们在15年前就有这样一个精彩的网站))) - Viktor Latypov

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接