clang:使用O3导出隐式实例化函数的符号

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了clang:使用O3导出隐式实例化函数的符号相关的知识,希望对你有一定的参考价值。

TL,DR:即使-O3处于活动状态,我如何强制clang导出隐式实例化函数的符号?

我们来看下面的代码:

#include <iostream>
#include <llvm/Support/DynamicLibrary.h>
#include <llvm/ExecutionEngine/ExecutionEngine.h>
#include <llvm/ExecutionEngine/RTDyldMemoryManager.h>

template <typename T>
__attribute__((noinline))
int twice(const T& t) {
    return t * 2;
}

int thrice(const int& t) {
    return t * 3;
}

int main() {
    std::cout << twice(5) << std::endl;
    std::cout << thrice(5) << std::endl;

    llvm::sys::DynamicLibrary::LoadLibraryPermanently(nullptr);  // Make symbols from current process visible
    std::cout << "address of twice: " << llvm::RTDyldMemoryManager::getSymbolAddressInProcess("__Z5twiceIiEiRKT_") << std::endl;
    std::cout << "address of thrice: " << llvm::RTDyldMemoryManager::getSymbolAddressInProcess("__Z6thriceRKi") << std::endl;
}

有两个功能,两次和三次。第一个是模板化,第二个不是。我先定期调用它们,然后尝试使用libLLVM获取它们的地址。可以把它想象成一个超级简化的JIT编译器(它有一个提供名称的mangler)的一部分。

使用clang++ -O0 -I/usr/local/opt/llvm/include -L/usr/local/opt/llvm/lib/ jit.cpp -lLLVM(OS X上的clang版本6.0.0),输出符合预期:

10
15
address of twice: 4350763184
address of thrice: 4350762224

如果我启用优化,twice的符号将不再导出,如nm a.out | grep twice中所示:

00000001000010b0 T __Z5twiceIiEiRKT_ (with -O0)
00000001000009c0 t __Z5twiceIiEiRKT_ (with -O3)

因此,libLLVM不再找到该函数:

10
15
address of twice: 0
address of thrice: 4315621072

使用gcc,符号将被导出。

如果我明确地实例化它,我可以让clang导出符号:

template int twice<int>(const int& t);

然而,这不是一个真正的选择,因为我们不知道JIT引擎将调用哪些实例。

我知道this post,但它只涉及显式实例化。

答案

添加属性used,如下所示:

template <typename T>
__attribute__((used))
int twice(const T& t) {
    return t * 2;
}

这将迫使Clang导出符号。

以上是关于clang:使用O3导出隐式实例化函数的符号的主要内容,如果未能解决你的问题,请参考以下文章

MSVC:显式模板实例化失败,而隐式实例化成功

clang 编译器挂着 -std=c++17 -O3

MSVC:隐式模板实例化,但未使用模板构造函数

没有前向声明的嵌套函数模板实例化可以在 GCC 上编译,但不能在 clang 上编译

为啥 gcc -O3 处理 avx256 的内在比较与 gcc -O0 和 clang 不同?

Clang - 链接时“找不到符号”