我正在用 C 语言构建一个共享库,该库由我没有源代码访问权限的程序动态加载。目标平台是 64 位 Linux 平台,我们使用 gcc 构建。我能够在大约 100 行中构建该问题的复制品,但仍然需要阅读一些内容。希望它是说明性的。
核心问题是我在共享库中定义了两个非静态函数(bar
和)。baz
两者都需要是非静态的,因为我们希望调用者能够对它们进行 dlsym。此外,baz
调用bar
. 使用我的库的程序还有一个名为 的函数bar
,这通常不会成为问题,但调用程序是用 编译的-rdynamic
,因为它有一个foo
需要在我的共享库中调用的函数。结果是我的共享库最终bar
在运行时链接到调用程序的版本,产生不直观的结果。
在理想情况下,我可以在编译共享库时包含一些命令行开关,以防止这种情况发生。
我目前的解决方案是将我的非静态函数重命名为funname_local
并将它们声明为静态。然后我定义了一个新函数:
,并将我的共享库中对 的funname() { return funname_local(); }
任何引用更改为。这可行,但感觉很麻烦,我更愿意告诉链接器更喜欢在本地编译单元中定义的符号。funname
funname_local
内部.c
#include <stdio.h>
#include "internal.h"
void
bar(void)
{
printf("I should only be callable from the main program\n");
}
内部.h
#if !defined(__INTERNAL__)
#define __INTERNAL__
void
bar(void);
#endif /* defined(__INTERNAL__) */
主程序
#include <dlfcn.h>
#include <stdio.h>
#include "internal.h"
void
foo(void)
{
printf("It's important that I am callable from both main and from any .so "
"that we dlopen, that's why we compile with -rdynamic\n");
}
int
main()
{
void *handle;
void (*fun1)(void);
void (*fun2)(void);
char *error;
if(NULL == (handle = dlopen("./shared.so", RTLD_NOW))) { /* Open library */
fprintf(stderr, "dlopen: %s\n", dlerror());
return 1;
}
dlerror(); /* Clear any existing error */
*(void **)(&fun1) = dlsym(handle, "baz"); /* Get function pointer */
if(NULL != (error = dlerror())) {
fprintf(stderr, "dlsym: %s\n", error);
dlclose(handle);
return 1;
}
*(void **)(&fun2) = dlsym(handle, "bar"); /* Get function pointer */
if(NULL != (error = dlerror())) {
fprintf(stderr, "dlsym: %s\n", error);
dlclose(handle);
return 1;
}
printf("main:\n");
foo();
bar();
fun1();
fun2();
dlclose(handle);
return 0;
}
主文件
#if !defined(__MAIN__)
#define __MAIN__
extern void
foo(void);
#endif /* defined(__MAIN__) */
共享.c
#include <stdio.h>
#include "main.h"
void
bar(void)
{
printf("bar:\n");
printf("It's important that I'm callable from a program that loads shared.so"
" as well as from other functions in shared.so\n");
}
void
baz(void)
{
printf("baz:\n");
foo();
bar();
return;
}
编译:
$ gcc -m64 -std=c89 -Wall -Wextra -Werror -pedantic -o main main.c internal.c -l dl -rdynamic
$ gcc -m64 -std=c89 -Wall -Wextra -Werror -pedantic -shared -fPIC -o shared.so shared.c
跑:
$ ./main
main:
It's important that I am callable from both main and from any .so that we dlopen, that's why we compile with -rdynamic
I should only be callable from the main program
baz:
It's important that I am callable from both main and from any .so that we dlopen, that's why we compile with -rdynamic
I should only be callable from the main program
bar:
It's important that I'm callable from a program that loads shared.so as well as from other functions in shared.so