【发布时间】:2020-01-04 09:01:54
【问题描述】:
我有一个已编译的 ELF 文件 libfoo.so,它导出了一些类方法,例如:
struct Bar {
void f();
void g();
};
我知道这些类的确切声明,但定义被编译到 .so 中。我使用与 .so 相同的编译器 (gcc >= 7),因此名称修饰和 ABI 匹配。这意味着如果我将上述声明添加到我的代码中,我将能够直接调用 libfoo.so 中实现的方法。
但是,我不想用顶级 libfoo 的东西污染我的命名空间(而且我不控制 libfoo 源)。所以我想在namespace foo {} 中声明struct Bar。现在,一旦我这样做了,名称修饰就不再匹配,加载程序将无法找到有问题的函数。
我不想为所有这些都写 thunk,因为 a) 有数千个 b) 它会导致虚函数和析构函数出现问题。
我正在考虑使用 objcopy 并重命名 libfoo.so 中的所有导出符号,但希望这里有更好的解决方案。
libfoo 和我的代码都使用 C++14(可以移动到 C++17)和 gcc 7(可以移动到以后)。在 Linux 上为 64 位 ELF 编译。
【问题讨论】:
-
编译后的代码将完全损坏、不可信和//或不稳定。并非不可能,但我认为您必须采取不同的方法
-
你能详细说明@memosdp 吗?编译后的 libfoo.so 不应该关心可执行文件的其他部分做什么,或者它的导出符号的名称是什么。它是完全独立的,即使 99% 的符号被完全剥离也可以运行。
-
它仍然是一个库,不仅如此,它还是一个
so,意思是shared object。你将如何重构重定位?我认为您必须深入了解elflib才能做到这一点,而不仅仅是objcopy -
我根本不会更改重定位。 objcopy 只会重命名符号,因为它们在外部中看到。在内部,lib 使用保持不变的相对偏移量。 lib 的所有代码都保持不变,只是符号名称(即
nm的输出)得到了更多的修饰 - 但这从未被 lib 本身使用,它仅适用于 lib 的消费者(和调试器,打印堆栈跟踪等) -
问题和解决方案都非常符合C++的精神。干得好。