8

ソースにアクセスできないプログラムによって動的にロードされる共有ライブラリを C で構築しています。ターゲット プラットフォームは 64 ビットの Linux プラットフォームであり、ビルドには gcc を使用しています。問題の再現を 100 行以内で作成できましたが、まだ少し読む必要があります。うまくいけば、それは説明的です。

中心的な問題は、共有ライブラリで2 つの非静的関数 (barおよび) が定義されていることです。baz呼び出し元がそれらを dlsym できることが期待されるため、両方とも非静的である必要があります。さらに、 をbaz呼び出しますbar。私のライブラリを使用しているプログラムには、bar通常は問題にならないという名前の関数もありますが、共有ライブラリで呼び出す必要-rdynamicがある関数があるため、呼び出しプログラムは でコンパイルされます。fooその結果、共有ライブラリが実行時に呼び出しプログラムのバージョンにリンクされてしまいbar、直感的でない結果が生成されます。

理想的な世界では、共有ライブラリをコンパイルするときに、これを防ぐコマンド ライン スイッチを含めることができます。

私が持っている現在の解決策は、非静的関数の名前を変更し、funname_localそれらを静的に宣言することです。次に、新しい関数 を定義 し、共有ライブラリ内の へのfunname() { return funname_local(); }参照を に変更します。これは機能しますが、面倒に感じます。リンカに、ローカル コンパイル ユニットで定義されたシンボルを優先するように指示するだけで十分です。funnamefunname_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
4

2 に答える 2

9

-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
于 2016-09-13T20:00:25.720 に答える