GNU 链接器:适应名称修改算法的更改
GNU linker: Adapt to change of name mangling algorithm
我正在尝试重新编译现有的 C++ 应用程序。
不幸的是,我必须依赖一个专有库,我只有一个预编译的静态存档。
我使用的是 g++ 7.3.0 版和 ld 2.30 版。
无论用什么 GCC 版本编译,它都是古老的。
头文件定义方法:
class foo {
int bar(int & i);
}
如nm lib.a
所示,库存档包含相应的导出函数:
T bar__4fooRi
nm app.o
显示我最近的编译器使用了不同类型的名称修改:
U _ZN4foo9barERi
因此链接器无法解析库提供的符号。
是否有选择名称修改算法的选项?
我可以引入映射或明确定义错位名称吗?
@Botje 的建议让我编写了一个这样的链接描述文件(PROVIDE 节中的空格很重要):
EXTERN(bar__4fooRi);
PROVIDE(_ZN4foo9barERi = bar__4fooRi);
据我了解,这会将 bar__4fooRi
视为外部定义的符号(它是)。如果搜索 _ZN4foo9barERi
但未定义,bar__4fooRi
将取而代之。
我这样从 GNU 工具链调用链接器(注意顺序——脚本需要在依赖对象之后但在定义库之前):
g++ -o application application.o script.ld -lfoo
看起来这可行。
至少理论上是这样。
链接器现在考虑库的其他部分,这些部分又依赖于其他无法解析的符号,包括(但不限于)__throw
、__cp_pop_exception
和 __builtin_delete
。我不知道现在这些功能在哪里定义。 Joxean Koret 根据猜测显示了 this blog post 中的一些位置(__builtin_new
可能是 malloc
)——但我没有那么自信。
这些发现使我得出结论,该库依赖于不同风格的异常处理,也可能依赖于内存管理。
编辑: 由于 @eukaryota 指出的 ABI 变化,结果可能纯粹是学术性的,链接描述文件确实可以用于 "alias" 符号。这是一个完整的最小示例:
foo.h:
class Foo {
public:
int bar(int);
};
foo.cpp:
#include "foo.h"
int Foo::bar(int i) {
return i+21;
}
main.cpp:
class Foo {
public:
int baa(int); // use in-place "header" to simulate different name mangling algorithm
};
int main(int, char**) {
Foo f;
return f.baa(21);
}
script.ld:
EXTERN(_ZN3Foo3barEi);
PROVIDE(_ZN3Foo3baaEi = _ZN3Foo3barEi); /* declare "alias" */
构建过程:
g++ -o libfoo.o -c foo.c
ar rvs libfoo.a libfoo.o # simulate building a library
g++ -o app main.o -L. script.ld -lfoo
app
已编译,可以执行,returns预期结果。
我正在尝试重新编译现有的 C++ 应用程序。 不幸的是,我必须依赖一个专有库,我只有一个预编译的静态存档。
我使用的是 g++ 7.3.0 版和 ld 2.30 版。
无论用什么 GCC 版本编译,它都是古老的。
头文件定义方法:
class foo {
int bar(int & i);
}
如nm lib.a
所示,库存档包含相应的导出函数:
T bar__4fooRi
nm app.o
显示我最近的编译器使用了不同类型的名称修改:
U _ZN4foo9barERi
因此链接器无法解析库提供的符号。
是否有选择名称修改算法的选项?
我可以引入映射或明确定义错位名称吗?
@Botje 的建议让我编写了一个这样的链接描述文件(PROVIDE 节中的空格很重要):
EXTERN(bar__4fooRi);
PROVIDE(_ZN4foo9barERi = bar__4fooRi);
据我了解,这会将 bar__4fooRi
视为外部定义的符号(它是)。如果搜索 _ZN4foo9barERi
但未定义,bar__4fooRi
将取而代之。
我这样从 GNU 工具链调用链接器(注意顺序——脚本需要在依赖对象之后但在定义库之前):
g++ -o application application.o script.ld -lfoo
看起来这可行。
至少理论上是这样。
链接器现在考虑库的其他部分,这些部分又依赖于其他无法解析的符号,包括(但不限于)__throw
、__cp_pop_exception
和 __builtin_delete
。我不知道现在这些功能在哪里定义。 Joxean Koret 根据猜测显示了 this blog post 中的一些位置(__builtin_new
可能是 malloc
)——但我没有那么自信。
这些发现使我得出结论,该库依赖于不同风格的异常处理,也可能依赖于内存管理。
编辑: 由于 @eukaryota 指出的 ABI 变化,结果可能纯粹是学术性的,链接描述文件确实可以用于 "alias" 符号。这是一个完整的最小示例:
foo.h:
class Foo {
public:
int bar(int);
};
foo.cpp:
#include "foo.h"
int Foo::bar(int i) {
return i+21;
}
main.cpp:
class Foo {
public:
int baa(int); // use in-place "header" to simulate different name mangling algorithm
};
int main(int, char**) {
Foo f;
return f.baa(21);
}
script.ld:
EXTERN(_ZN3Foo3barEi);
PROVIDE(_ZN3Foo3baaEi = _ZN3Foo3barEi); /* declare "alias" */
构建过程:
g++ -o libfoo.o -c foo.c
ar rvs libfoo.a libfoo.o # simulate building a library
g++ -o app main.o -L. script.ld -lfoo
app
已编译,可以执行,returns预期结果。