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

时间:2018-09-22 22:17:18

标签: c shared-libraries dlopen

我想使用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;}

Makefile:

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进行构建和运行时,我期望test()中的libimplementation.so函数会覆盖{{1}中的test()函数},但事实并非如此。我知道我也可以将main中的所有代码移到另一个共享库main()中,然后将run main() dlopenlibimplementation.so一起使用,并然后让RTLD_GLOBAL引用librun.so中的符号而不定义它们,以便加载它们:

修改过的main.c:

libimplementation.so

run.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);
}

,并且#include <stdio.h> int is_loaded(void); void run(void){ puts(is_loaded() ? "Implementation loaded" : "Implementation not loaded"); } 被添加Makefile作为librun.so的前提。

有没有一种方法可以立即从共享库中获取符号,而无需使用all或将实际代码放入dlsym这样的另一个共享库中?

1 个答案:

答案 0 :(得分:2)

从根本上讲,您无法做任何您想做的事情。想象一下主程序有这样的东西:

static char *myptr = array_in_lib1;

后来,在您dlopen时,myptr还有其他价值。程序是否刚刚将变量更改为指向其他对象?还是增加了它以指向数组中稍后的某个元素-在这种情况下,您是否要对其进行调整以使用新打开的库中的新定义来说明对array_in_lib1的重新定义?还是只是随机整数转换为char *?在不了解程序员如何达到当前状态的程序员意图 完整过程历史记录的情况下,决定如何进行处理是不可能的。

以上是我构建的一个极其出色的示例,但是在运行时更改符号定义的想法在各种方面根本上是不一致的。甚至RTLD_DEEPBIND都已经被认为是不稳定的和有问题的。无论您想做什么,都应该找到另一种方式。