是否有一个编译器标志允许共享库调用来自打开它的共享库的函数?

问题描述 投票:0回答:1

下面是一个最小的可重现示例,其目标是从

b_util()
调用
a()
。我的问题是是否可以在不显式地将 b_util() 函数指针传递给
a.c
的情况下执行此操作。
我正在寻找像

-rdynamic

这样的标志,如

this Stack Overflow post
中所述,它允许共享库从主可执行文件调用函数。使用此标志编译 a.c
b.c
会打印相同的运行时错误,但也许有一种方法可以利用该标志?
您可以使用 

gcc c.c -o c.out && gcc b.c -o b.so -shared -fPIC && gcc a.c -o a.so -shared && ./c.out

编译并运行以下代码,但问题是它会打印

dlopen: ./a.so: undefined symbol: b_util
:
// a.c

void b_util(void);

void a(void) {
    b_util();
}

// b.c

#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>

void assert_dl(void *p, char *fn_name) {
    if (!p) {
        fprintf(stderr, "%s: %s\n", fn_name, dlerror());
        exit(EXIT_FAILURE);
    }
}

void b(void) {
    void *dll = dlopen("./a.so", RTLD_NOW);
    assert_dl(dll, "dlopen");

    void (*a)(void) = dlsym(dll, "a");
    assert_dl(a, "dlsym");

    a();
}

void b_util(void) {
    printf("b_util\n");
}
// c.c

#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>

void assert_dl(void *p, char *fn_name) {
    if (!p) {
        fprintf(stderr, "%s: %s\n", fn_name, dlerror());
        exit(EXIT_FAILURE);
    }
}

int main(void) {
    void *dll = dlopen("./b.so", RTLD_NOW);
    assert_dl(dll, "dlopen");

    void (*b)(void) = dlsym(dll, "b");
    assert_dl(b, "dlsym");

    b();
}
	
c shared-libraries dlopen dlsym
1个回答
0
投票
评论中的一些程序员家伙

让我意识到了RTLD_GLOBAL标志,我确实只需要将

dlopen("./b.so", RTLD_NOW)
更改为
dlopen("./b.so", RTLD_NOW | RTLD_GLOBAL)
过了一会儿我发现不需要

b.so

来打开

a.so
c.c
只需先用
b.so
打开
RTLD_GLOBAL
即可使
b_util
可见,就好像它已直接链接到程序中一样。之后,
dlopen("./a.so", RTLD_NOW)
成功了:
// a.c

void b_util(void);

void a(void) {
    b_util();
}

// b.c

#include <stdio.h>

void b_util(void) {
    printf("b_util\n");
}
// c.c

#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>

void assert_dl(void *p, char *fn_name) {
    if (!p) {
        fprintf(stderr, "%s: %s\n", fn_name, dlerror());
        exit(EXIT_FAILURE);
    }
}

int main(void) {
    // Comment dlopen("./b.so") out to cause `undefined symbol: b_util`
    void *dll_b = dlopen("./b.so", RTLD_NOW | RTLD_GLOBAL);
    assert_dl(dll_b, "dlopen");

    void *dll_a = dlopen("./a.so", RTLD_NOW);
    assert_dl(dll_a, "dlopen");

    void (*a)(void) = dlsym(dll_a, "a");
    assert_dl(a, "dlsym");

    a();
}
	
© www.soinside.com 2019 - 2024. All rights reserved.