如何让共享库中的符号覆盖现有符号?

How can I have the symbols in a shared library override existing symbols?

我想用 dlopen 加载一个共享库并使其中的符号可用,而不必用 dlsym 单独获取指向它们的函数指针。 man page 表示 RTLD_DEEPBIND 标志将在全局范围之前在库中查找符号,但显然这并不意味着它会覆盖现有符号,因为这不起作用。考虑这个例子:

main.c:

#define _GNU_SOURCE
#include <stdio.h>
#include <dlfcn.h>

int is_loaded(){return 0;}

int main(){
    void *h = dlopen("./libimplementation.so", RTLD_NOW | RTLD_DEEPBIND);
    if(!h){
        printf("Could not load implementation: %s\n", dlerror());
        return 1;
    }
    puts(is_loaded() ? "Implementation loaded" : "Implementation not loaded");
    dlclose(h);
}

implementation.c:

int is_loaded(){return 1;}

生成文件:

all: main libimplementation.so

main: main.c
    gcc -Wall -std=c99 -o $@ $^ -ldl

lib%.so: %.c
    gcc -Wall -std=c99 -o $@ $^ -shared

clean:
    -rm main *.so

当我使用 make./main 构建和 运行 时,我希望 libimplementation.so 中的 test() 函数覆盖 test()来自 main 的功能,但它没有。我知道我也可以将 main() 中的所有代码移动到另一个共享库 run 中,然后 main() dlopen libimplementation.soRTLD_GLOBAL 以及然后让 librun.so 引用 libimplementation.so 中的符号而不定义它们以便加载它们:

修改后main.c:

#define _GNU_SOURCE
#include <stdio.h>
#include <dlfcn.h>

int main(){
    void *impl_h = dlopen("./libimplementation.so", RTLD_LAZY | RTLD_GLOBAL);
    if(!impl_h){
        printf("Could not load implementation: %s\n", dlerror());
        return 1;
    }
    void *run_h = dlopen("./librun.so", RTLD_LAZY);
    if(!run_h){
        printf("Could not load run: %s\n", dlerror());
        dlclose(impl_h);
        return 1;
    }
    void (*run)(void);
    *(void**)&run = dlsym(run_h, "run");
    if(!*(void**)&run){
        printf("Could not find entry point in run: %s\n", dlerror());
        dlclose(impl_h);
        dlclose(run_h);
        return 1;
    }
    run();
    dlclose(impl_h);
    dlclose(run_h);
}

run.c:

#include <stdio.h>

int is_loaded(void);

void run(void){
    puts(is_loaded() ? "Implementation loaded" : "Implementation not loaded");
}

并且 Makefile 被添加为 librun.so 作为 all 的先决条件。

有没有一种方法可以一次性从共享库中获取符号,而无需 dlsym 或将实际代码放在另一个共享库中,例如 librun.so

根本无法实现您的要求。想象一下主程序有这样的东西:

static char *myptr = array_in_lib1;

后来,当时你dlopenmyptr有一些其他的价值。程序是否只是将变量更改为指向不同的对象?或者它是否已递增以指向数组后面的某个元素 - 在这种情况下,您是否希望它进行调整以使用新打开的库中的新定义来解释 array_in_lib1 的重新定义?或者它只是一个转换为 char * 的随机整数?如果不了解程序员意图 完整的过程历史 它是如何到达的,就不可能决定如何处理它当前状态。

以上是我构建的一个特别令人震惊的示例,但是符号在运行时更改定义的想法在各种方面从根本上都是不一致的。即使是 RTLD_DEEPBIND,在它已经做的事情中,也可以说是不一致和错误的。无论您想做什么,都应该找到另一种方法。