ソースにアクセスできないプログラムによって動的にロードされる共有ライブラリを C で構築しています。ターゲット プラットフォームは 64 ビットの Linux プラットフォームであり、ビルドには gcc を使用しています。問題の再現を 100 行以内で作成できましたが、まだ少し読む必要があります。うまくいけば、それは説明的です。
中心的な問題は、共有ライブラリで2 つの非静的関数 (bar
および) が定義されていることです。baz
呼び出し元がそれらを dlsym できることが期待されるため、両方とも非静的である必要があります。さらに、 を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");
}
内部.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 -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;
}
main.h
#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