The*_*ral 6 c linux gcc shared-libraries linker-flags
我正在C中构建一个由我没有源访问权限的程序动态加载的共享库.目标平台是64位Linux平台,我们正在使用gcc构建.我能够在~100行中构建问题的复制品,但仍有一点需要阅读.希望它是说明性的.
核心问题是我在共享库中定义了两个非静态函数(bar
和baz
).两者都需要是非静态的,因为我们希望调用者能够使用它们.另外,baz
电话bar
.正在使用我的库的程序也有一个名为的函数bar
,这通常不是问题,但调用程序是用-rdynamic
它编译的,因为它有一个foo
需要在我的共享库中调用的函数.结果是我的共享库最终链接到bar
运行时调用程序的版本,产生不直观的结果.
在理想的世界中,我可以在编译共享库时包含一些命令行开关,以防止这种情况发生.
我当前的解决方案是将我的非静态函数重命名为funname_local
并将它们声明为静态.然后我定义一个新函数:
funname() { return funname_local(); }
,并将funname
我共享库中的任何引用更改为funname_local
.这有效,但感觉很麻烦,我更喜欢告诉链接器更喜欢本地编译单元中定义的符号.
internal.c
#include <stdio.h>
#include "internal.h"
void
bar(void)
{
printf("I should only be callable from the main program\n");
}
Run Code Online (Sandbox Code Playgroud)
internal.h
#if !defined(__INTERNAL__)
#define __INTERNAL__
void
bar(void);
#endif /* defined(__INTERNAL__) */
Run Code Online (Sandbox Code Playgroud)
main.c中
#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;
}
Run Code Online (Sandbox Code Playgroud)
main.h
#if !defined(__MAIN__)
#define __MAIN__
extern void
foo(void);
#endif /* defined(__MAIN__) */
Run Code Online (Sandbox Code Playgroud)
shared.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;
}
Run Code Online (Sandbox Code Playgroud)
编译:
$ 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
Run Code Online (Sandbox Code Playgroud)
跑:
$ ./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
Run Code Online (Sandbox Code Playgroud)
您是否尝试过-Bsymbolic
链接器选项(或-Bsymbolic-functions
)?引自ld
男人:
-Bsymbolic
创建共享库时,将对全局符号的引用绑定到共享库中的定义(如果有).通常,链接到共享库的程序可以覆盖共享库中的定义.在创建与位置无关的可执行文件时,此选项还可以与--export-dynamic选项一起使用,以将对全局符号的引用绑定到可执行文件中的定义.此选项仅对支持共享库和位置无关可执行文件的ELF平台有意义.
它似乎解决了这个问题:
$ gcc -m64 -std=c89 -Wall -Wextra -Werror -pedantic -shared -fPIC -o shared.so shared.c
$ gcc -m64 -std=c89 -Wall -Wextra -Werror -pedantic -o main main.c internal.c -l dl -rdynamic
$ ./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
$ gcc -m64 -std=c89 -Wall -Wextra -Werror -pedantic -shared -fPIC -Wl,-Bsymbolic -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
bar:
It's important that I'm callable from a program that loads shared.so as well as from other functions in shared.so
bar:
It's important that I'm callable from a program that loads shared.so as well as from other functions in shared.so
Run Code Online (Sandbox Code Playgroud)