Her*_*ann 5 c++ name-mangling ld
我正在尝试重新编译现有的 C++ 应用程序。不幸的是,我必须依赖一个专有库,我只有一个预编译的静态存档。
我使用 g++ 版本 7.3.0 和 ld 版本 2.30。
无论它是用什么 GCC 版本编译的,它都是古老的。
头文件定义了方法:
class foo {
int bar(int & i);
}
Run Code Online (Sandbox Code Playgroud)
如图nm lib.a所示,库存档包含相应的导出函数:
T bar__4fooRi
Run Code Online (Sandbox Code Playgroud)
nm app.o显示了我最近使用不同类型的名称修饰的编译器:
U _ZN4foo9barERi
Run Code Online (Sandbox Code Playgroud)
因此,链接器无法解析库提供的符号。
是否有任何选项可以选择名称修饰算法?
我可以引入地图或明确定义损坏的名称吗?
@Botje\ 的建议引导我编写这样的链接器脚本(PROVIDE 节中的空格很重要):
\n\nEXTERN(bar__4fooRi);\nPROVIDE(_ZN4foo9barERi = bar__4fooRi);\nRun Code Online (Sandbox Code Playgroud)\n\n据我了解,这将被视为bar__4fooRi外部定义的符号(确实如此)。如果_ZN4foo9barERi已搜索但未定义,bar__4fooRi则将取代它。
我像这样从 GNU 工具链调用链接器(注意脚本需要位于依赖对象之后但定义库之前的顺序 \xe2\x80\x93):
\n\ng++ -o application application.o script.ld -lfoo\nRun Code Online (Sandbox Code Playgroud)\n\n看来这可行。
\n至少在理论上是这样。
\n链接器现在考虑库的其他部分,而库的其他部分又依赖于其他不可解析的符号,包括(但不限于)__throw、__cp_pop_exception和__builtin_delete。我现在不知道这些函数是在哪里定义的。Joxean Koret 在这篇博文中显示了一些基于猜测的位置(__builtin_new可能是malloc) \xe2\x80\x93 但我不太有信心。
这些发现使我得出这样的结论:该库也依赖于不同风格的异常处理,可能还依赖于内存管理。
\n\n编辑:由于@eukaryota 指出的 ABI 更改,结果可能纯粹是学术性的,链接器脚本确实可以用于“别名”符号。这是一个完整的最小示例:
\n\nfoo.h:
\n\nclass Foo {\n public:\n int bar(int);\n};\nRun Code Online (Sandbox Code Playgroud)\n\nfoo.cpp:
\n\n#include "foo.h"\nint Foo::bar(int i) {\n return i+21;\n}\nRun Code Online (Sandbox Code Playgroud)\n\n主要.cpp:
\n\nclass Foo {\n public:\n int baa(int); // use in-place "header" to simulate different name mangling algorithm\n};\n\nint main(int, char**) {\n Foo f;\n return f.baa(21);\n}\nRun Code Online (Sandbox Code Playgroud)\n\n脚本.ld:
\n\nEXTERN(_ZN3Foo3barEi);\nPROVIDE(_ZN3Foo3baaEi = _ZN3Foo3barEi); /* declare "alias" */\nRun Code Online (Sandbox Code Playgroud)\n\n构建过程:
\n\ng++ -o libfoo.o -c foo.c\nar rvs libfoo.a libfoo.o # simulate building a library\ng++ -o app main.o -L. script.ld -lfoo\nRun Code Online (Sandbox Code Playgroud)\n\napp已编译,可以执行并返回预期结果。