即使使用-rdynamic编译的程序正在加载共享对象,您是否也可以编译它来使用本地符号呢? [英] Can you compile a shared object to prefer local symbols even if it's being loaded by a program compiled with -rdynamic?

查看:112
本文介绍了即使使用-rdynamic编译的程序正在加载共享对象,您是否也可以编译它来使用本地符号呢?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在用C构建一个共享库,该共享库由我没有源访问权限的程序动态加载.目标平台是64位Linux平台,我们正在使用gcc进行构建.我能够在大约100行中复制该问题,但是仍然有点可读.希望它是说明性的.

I am building a shared library in C that is dynamically loaded by a program that I do not have source access to. The target platform is a 64-bit Linux platform and we're using gcc to build. I was able to build a reproduction of the issue in ~100 lines, but it's still a bit to read. Hopefully it's illustrative.

核心问题是我在共享库中定义了两个非静态函数(barbaz).两者都必须是非静态的,因为我们希望调用者能够对它们进行dlsym.此外,baz调用bar.使用我的库的程序还具有一个名为bar的函数,通常不会出现此问题,但是调用程序是使用-rdynamic编译的,因为它具有需要调用的函数foo.我的共享库.结果是我的共享库最终在运行时链接到调用程序的bar版本,从而产生了不直观的结果.

The core issue is I have two non-static functions (bar and baz) defined in my shared library. Both need to be non-static as we expect the caller to be able to dlsym them. Additionally, baz calls bar. The program that is using my library also has a function named bar, which wouldn't normally be an issue, but the calling program is compiled with -rdynamic, as it has a function foo that needs to be called in my shared library. The result is my shared library ends up linked to the calling program's version of bar at runtime, producing unintuitive results.

理想情况下,在编译共享库时,我将能够包括一些命令行开关,以防止这种情况的发生.

In an ideal world I would be able to include some command line switch when compiling my shared library that would prevent this from happening.

我目前拥有的解决方案是将我的非静态函数重命名为funname_local并将它们声明为静态.然后,我定义一个新函数: funname() { return funname_local(); },并将共享库中对funname的所有引用更改为funname_local.可以,但是感觉很麻烦,我更愿意只告诉链接器更喜欢在本地编译单元中定义的符号.

The current solution I have is to rename my non-static functions as funname_local and declare them static. I then define a new function: funname() { return funname_local(); }, and change any references to funname in my shared library to funname_local. This works, but it feels cumbersome, and I'd much prefer to just tell the linker to prefer symbols defined in the local compilation unit.

internal.c

internal.c

#include <stdio.h>
#include "internal.h"

void
bar(void)
{
  printf("I should only be callable from the main program\n");
}

internal.h

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 -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__) */

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;
}

编译:

$ 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

推荐答案

您是否尝试过-Bsymbolic链接器选项(或-Bsymbolic-functions)?引用ld男人:

Have you tried -Bsymbolic linker option (or -Bsymbolic-functions)? Quoting from ld man:

-象征

创建共享库时,请将对全局符号的引用绑定到共享库中的定义(如果有).通常,链接到共享库的程序可能会覆盖共享库中的定义.当创建位置独立的可执行文件时,此选项还可以与--export-dynamic选项一起使用,以将对全局符号的引用绑定到可执行文件中的定义.此选项仅在支持共享库和位置独立可执行文件的ELF平台上有意义.

When creating a shared library, bind references to global symbols to the definition within the shared library, if any. Normally, it is possible for a program linked against a shared library to override the definition within the shared library. This option can also be used with the --export-dynamic option, when creating a position independent executable, to bind references to global symbols to the definition within the executable. This option is only meaningful on ELF platforms which support shared libraries and position independent executables.

似乎可以解决问题:

$ 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

这篇关于即使使用-rdynamic编译的程序正在加载共享对象,您是否也可以编译它来使用本地符号呢?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆