草庐IT

c++ - 将静态库链接到共享库并隐藏导出的符号

coder 2023-06-03 原文

我的链接器有一个烦人的问题。我想将一些符号从共享库链接到静态库,但不导出它的符号(即,我不能简单地合并库或与 --whole-archive 链接)。我想要的是链接(如链接可执行文件,解决 undefined symbol )我的共享库到静态库并删除 undefined symbol 。

我正在寻找的东西可能只是一个链接器选项,但我无法找到它。

我会尽力描述问题(这并不容易),然后提供一个玩具最小的例子来玩。

简要说明:

我想使用 LD_PRELOAD在可执行文件中捕获一些函数调用的技巧。此可执行文件链接到第三方共享库,其中包含我要捕获的函数的函数定义。

这个第三方库还包含来自另一个库的符号,我也在我的库中使用它,但版本不同(不兼容)。

我想要做的是编译我的共享库并在编译时将它与最后一个(静态)库的定义链接,而不导出符号,以便我的共享库使用与我想要的不同的版本陷阱。

简化的问题描述

我有一个名为 libext.so 的第三方库,我没有源代码。这定义了一个函数 bar并使用函数 foo来自另一个库,但符号都在那里定义:

$> nm libext.so
0000000000000a16 T bar
00000000000009e8 T foo

正如我提到的,foo是一个外部依赖项,我想使用更新的版本。我有一个更新的库,我们称之为 libfoo.a :

$> nm libfoo.a
0000000000000000 T foo

现在的问题是我想创建一个动态库来重新定义 bar ,但我希望我的库使用 foo 的定义来自 libfoo.a我想要 libext.so 中的函数调用函数foo来自 libext.so .换句话说,我想要我的库的编译时链接到 libfoo.a .

我正在寻找的是定义一个使用 libfoo.a 的库但不导出其符号。如果我将我的图书馆链接到 libfoo.a ,我得到:

$> nm libmine.so
0000000000000a78 T bar
0000000000000b2c T foo

这意味着我都重载了foobar (我不想覆盖 foo )。如果我不将我的图书馆链接到 libfoo.a ,我得到:

$> nm libmine.so
0000000000000a78 T bar
                 U foo

所以我的图书馆将使用他们的 foo 版本,我也不想要。我想要的是:

$> nm libmine.so
0000000000000a78 T bar

在哪里 foo在编译时链接,其符号未导出。

小例子

你不需要阅读这篇文章,但你可以用它来玩耍并找到解决方案。

bar.cpp : 代表我没有代码的第三方应用:

#include <iostream>
extern "C" void foo(){ std::cerr << "old::foo" << std::endl; }
extern "C" void bar(){ std::cerr << "old::bar" << std::endl; foo(); }

foo.cpp : 代表我的库和第三方都使用的函数的更新版本:

#include <iostream>
extern "C" void foo(){ std::cerr << "new::foo" << std::endl; }

trap.cpp : 我的库中的代码,它会捕获 bar , 调用新的 foo和转发:

#include <iostream>
extern "C" {
  #include <dlfcn.h>
}
extern "C" void foo();
extern "C" void bar(){
  std::cerr << "new::bar" << std::endl;
  foo(); // Should be new::foo
  void (*fwd)() = (void(*)())dlsym(RTLD_NEXT, "bar");
  fwd(); // Should use old::foo
}

exec.cpp :调用bar的虚拟可执行文件:

extern "C" void bar();

int main(){
  bar();
}

Makefile : 仅限 Unix,抱歉

default:
    # The third party library
    g++ -c -o bar.o bar.cpp -fpic
    gcc -shared -Wl,-soname,libext.so -o libext.so bar.o
    # The updated library
    g++ -c -o foo.o foo.cpp -fPIC
    ar rcs libfoo.a foo.o
    # My trapping library
    g++ -c -o trap.o trap.cpp -fPIC
    gcc -shared -Wl,-soname,libmine.so -o libmine.so trap.o -ldl -L. -lfoo
    # The dummy executable
    g++ -o test exec.cpp -L. libext.so

在这种情况下,bar来电foo ;正常的执行是:

$> ./test
old::bar
old::foo

预加载我的库拦截 bar , 调用我的foo和转发bar ,当前执行的是:

$> LD_PRELOAD=libmine.so ./test
new::bar
new::foo
old::bar
new::foo

最后一行错了,想要的输出是:

$> LD_PRELOAD=libmine.so ./test
new::bar
new::foo
old::bar
old::foo

最佳答案

您想使用链接器版本脚本,该脚本导出您想要的符号(此处为 bar)并隐藏其他所有内容。

示例 here .

关于c++ - 将静态库链接到共享库并隐藏导出的符号,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22102470/

有关c++ - 将静态库链接到共享库并隐藏导出的符号的更多相关文章

  1. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  2. ruby - 通过 ruby​​ 进程共享变量 - 2

    我正在编写一个gem,我必须在其中fork两个启动两个webrick服务器的进程。我想通过基类的类方法启动这个服务器,因为应该只有这两个服务器在运行,而不是多个。在运行时,我想调用这两个服务器上的一些方法来更改变量。我的问题是,我无法通过基类的类方法访问fork的实例变量。此外,我不能在我的基类中使用线程,因为在幕后我正在使用另一个不是线程安全的库。所以我必须将每个服务器派生到它自己的进程。我用类变量试过了,比如@@server。但是当我试图通过基类访问这个变量时,它是nil。我读到在Ruby中不可能在分支之间共享类变量,对吗?那么,还有其他解决办法吗?我考虑过使用单例,但我不确定这是

  3. ruby - 使用 `+=` 和 `send` 方法 - 2

    如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:

  4. ruby-on-rails - 创建 ruby​​ 数据库时惰性符号绑定(bind)失败 - 2

    我正在尝试在Rails上安装ruby​​,到目前为止一切都已安装,但是当我尝试使用rakedb:create创建数据库时,我收到一个奇怪的错误:dyld:lazysymbolbindingfailed:Symbolnotfound:_mysql_get_client_infoReferencedfrom:/Library/Ruby/Gems/1.8/gems/mysql2-0.3.11/lib/mysql2/mysql2.bundleExpectedin:flatnamespacedyld:Symbolnotfound:_mysql_get_client_infoReferencedf

  5. ruby - 如何计算 Liquid 中的变量 +1 - 2

    我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我

  6. ruby - 鸭子输入字符串、符号和数组的优雅方式? - 2

    这是针对我无法破坏的现有公共(public)API,但我确实希望对其进行扩展。目前,该方法采用字符串或符号或任何其他在作为第一个参数传递给send时有意义的内容我想添加发送字符串、符号等列表的功能。我可以只使用is_a吗?数组,但还有其他发送列表的方法,这不是很像ruby​​。我将调用列表中的map,所以第一个倾向是使用respond_to?:map。但是字符串也会响应:map,所以这行不通。 最佳答案 如何将它们全部视为数组?String的行为与仅包含String的Array相同:deffoo(obj,arg)[*arg].eac

  7. ruby - 如果它是标点符号,我怎么能从字符串中删除最后一个字符,在 ruby​​ 中? - 2

    啊,正则表达式有点困惑。我正在尝试删除字符串末尾所有可能的标点符号:ifstr[str.length-1]=='?'||str[str.length-1]=='.'||str[str.length-1]=='!'orstr[str.length-1]==','||str[str.length-1]==';'str.chomp!end我相信有更好的方法来做到这一点。有什么指点吗? 最佳答案 str.sub!(/[?.!,;]?$/,'')[?.!,;]-字符类。匹配这5个字符中的任何一个(注意,。在字符类中并不特殊)?-前一个字符或组

  8. ruby - 如何在 Ruby 字符串中插入项目符号字符? - 2

    我正在尝试创建一个带有项目符号字符的Ruby1.9.3字符串。str="•"+"helloworld"但是,当我输入它时,我收到有关非ASCII字符的语法错误。我该怎么做? 最佳答案 你可以把Unicode字符放在那里。str="\u2022"+"helloworld" 关于ruby-如何在Ruby字符串中插入项目符号字符?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/1195

  9. Ruby隐藏与覆盖 - 2

    我刚刚了解到,在Java中,覆盖和隐藏之间是有区别的(静态方法是隐藏的,而不是覆盖),这意味着Java使用早期绑定(bind)和后期绑定(bind)。是否有与方法隐藏类似的东西,或者它只是具有方法重写? 最佳答案 Java具有三种不同的“方法”:实例方法,静态方法和构造函数。Ruby只有一个:实例方法。在Java中,静态方法的行为必须不同于实例方法,因为类不是对象。它们没有类,因此也没有父类(superclass),因此没有要覆盖的内容。在Ruby中,类与其他任何对象一样都是对象,它们具有一个类,该类可以具有父类(superclas

  10. arrays - Ruby 数组 += vs 推送 - 2

    我有一个数组数组,想将元素附加到子数组。+=做我想做的,但我想了解为什么push不做。我期望的行为(并与+=一起工作):b=Array.new(3,[])b[0]+=["apple"]b[1]+=["orange"]b[2]+=["frog"]b=>[["苹果"],["橙子"],["Frog"]]通过推送,我将推送的元素附加到每个子数组(为什么?):a=Array.new(3,[])a[0].push("apple")a[1].push("orange")a[2].push("frog")a=>[[“苹果”、“橙子”、“Frog”]、[“苹果”、“橙子”、“Frog”]、[“苹果”、“

随机推荐