我正在C中build立一个共享库,它是由我没有源访问权限的程序dynamic加载的。 目标平台是一个64位的Linux平台,我们正在使用gcc来构build。 我能够在100行的范围内复制这个问题,但还是有一点需要阅读。 希望这是说明。
核心问题是我有两个在我的共享库中定义的非静态函数( bar和baz )。 两者都需要是非静态的,因为我们希望调用者能够调用它们。 另外, baz来电bar 。 使用我的库的程序也有一个名为bar的函数,这通常不是问题,但调用程序是用-rdynamic编译的,因为它有一个函数foo ,需要在我的共享库中调用。 结果是我的共享库在运行时结束了与调用程序版本的bar链接,产生了不直观的结果。
在理想的世界中,编译我的共享库时可以包含一些命令行开关,以防止这种情况发生。
目前的解决scheme是将我的非静态函数重命名为funname_local并声明它们是静态的。 然后我定义一个新的函数: funname() { return funname_local(); } funname() { return funname_local(); } ,并将我共享库中对funname_local引用更改为funname_local 。 这有效,但感觉麻烦,我更愿意告诉链接器更喜欢在本地编译单元中定义的符号。
Linux何时/如何将共享库加载到地址空间?
malloc函数在标准的C和C ++库中插入
如何处理共享库中的依赖项,unix
internal.c
#include <stdio.h> #include "internal.h" void bar(void) { printf("I should only be callable from the main programn"); }
internal.h
#if !defined(__INTERNAL__) #define __INTERNAL__ void bar(void); #endif /* defined(__INTERNAL__) */
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 -rdynamicn"); } 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: %sn",dlerror()); return 1; } dlerror(); /* Clear any existing error */ *(void **)(&fun1) = dlsym(handle,"baz"); /* Get function pointer */ if(NULL != (error = dlerror())) { fprintf(stderr,"dlsym: %sn",error); dlclose(handle); return 1; } *(void **)(&fun2) = dlsym(handle,"bar"); /* Get function pointer */ if(NULL != (error = dlerror())) { fprintf(stderr,error); dlclose(handle); return 1; } printf("main:n"); foo(); bar(); fun1(); fun2(); dlclose(handle); return 0; }
main.h
#if !defined(__MAIN__) #define __MAIN__ extern void foo(void); #endif /* defined(__MAIN__) */
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.son"); } 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
将共享库打包到精灵中
replacestring后出现符号查找错误
为什么共享库的ELF标头指定Linux作为OSABI?
g ++ Cygwin / Linux或版本差异
你有没有试过-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 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 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
这个问题的一个常见的解决方案是实际上不依赖于全局符号不被覆盖。 而是执行以下操作:
隐藏__attribute__((visibility("hidden")))或类似的mylib_bar
让bar成为一个弱符号,像这样引用mylib_bar :
#pragma weak bar = mylib_bar
让你的库调用mylib_bar到处而不是bar
现在一切都按预期工作:
当库调用mylib_bar ,由于隐藏可见性,它总是引用库中的定义。
如果有人定义了他自己的bar ,这将覆盖bar而不是mylib_bar ,使你的图书馆不变。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。