• opt: undefined symbol when load


    0. 问题描述

    跟着教程写第一个llvm pass的时候,在opt load动态库的时候遇到了下面的报错

    $ opt -load ./libLLVMmypass.so 
    Error opening './libLLVMmypass.so': ./libLLVMmypass.so: undefined symbol: _ZTIN4llvm12FunctionPassE
      -load request ignored.
     
    $ c++filt _ZTIN4llvm12FunctionPassE
    typeinfo for llvm::FunctionPass
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    报错的原因是动态链接器没有找到typeinfo for llvm::FunctionPass这个类的定义。为了理解这个类,我们需要一些背景。

    1. rtti in c++

    C++里的dynamic_casttypeid运算符使用到了RTTI(run-time type identification),用于在运行时动态获取变量的类型信息。typeid返回的是一个具有static storage duration作用域的std::type_info类的引用,C++中每个类型都至少有一个对应的type_info类(可能会存在多个,考虑模板+动态库的情形,主程序实例化头文件中的某个模板类,因此主程序中有一个type_info,主程序再load一个动态库,该动态库也用同样的方法实例化了该头文件中的同一个模板类,因此该动态库中也存在对应同一个类的type_info)。

    注意不要把rtti与多态搞混了,从No RTTI but still virtual methods可以看出,在没有rrti的情况下,vtable也会正常工作。

    另外从文档中可以看出,异常处理也貌似依赖于rtti,不过这部分我从来没用过,就暂时不讨论了。

    2. 问题解答

    gcc中关于-fno-rtti的论述如下:

    -fno-rtti
    Disable generation of information about every class with virtual functions for use by the C++ run-time type identification features (“dynamic_cast” and “typeid”). If you don’t use those parts of the language, you can save some space by using this flag. Note that exception handling uses the same information, but G++ generates it as needed. The “dynamic_cast” operator can still be used for casts that do not require run-time type information, i.e. casts to “void *” or to unambiguous base classes.
    Mixing code compiled with -frtti with that compiled with -fno-rtti may not work. For example, programs may fail to link if a class compiled with -fno-rtti is used as a base for a class compiled with -frtti.

    最后一段解释了问题所在,表明我编译LLVM时没有保留rtti的信息。查询文档发现

    LLVM_ENABLE_RTTI:BOOL
    Build LLVM with run-time type information. Defaults to OFF.

    这下找到了问题的根源。在LLVMConfig.cmake定义了LLVM_ENABLE_RTTI来表明LLVM是否包含RTTI信息。因此在cmake中可以这样写

    if(NOT LLVM_ENABLE_RTTI)
    target_compile_options(${mypass} PRIVATE "-fno-rtti")
    endif()
    
    • 1
    • 2
    • 3

    3. 其它可能出问题的地方

    通常编译LLVM时我们会设置LLVM_BUILD_LLVM_DYLIB=ON来得到一个包含所有符号的LLVM动态库,但还有一个重要的设置是LLVM_LINK_LLVM_DYLIB,这个变量控制生成的二进制工具是与各个components静态链接还是与这个大的LLVM动态库进行动态链接。

    如果没有设置LLVM_LINK_LLVM_DYLIBldd opt会发现opt并不依赖于任何llvm相关的库(因为是静态链接的)。这时候在编译自己的pass的时候,就不要链接任何LLVM的库了(因为opt中已经静态链接过一次了),否则会得到类似于下面的报错

    : CommandLine Error: Option 'help-list' registered more than once!
    LLVM ERROR: inconsistency in registered CommandLine options
    
    • 1
    • 2
  • 相关阅读:
    深入URP之Shader篇4: Depth Only Pass
    室友1把王者的时间写出了快速排序?(python实现)
    后端接口性能优化分析-数据库优化
    Github Copilot Chat 初体验
    MySQL 学习记录 1
    前端知识记录
    QT+OSG/osgEarth编译之五十:osgTerrain+Qt编译(一套代码、一套框架,跨平台编译,版本:OSG-3.6.5工具库osgTerrain)
    Java面试编程相关题目
    推荐一个非常实用的程序员导航网站,码农必备!
    maven无法下载时的解决方法——笔记
  • 原文地址:https://blog.csdn.net/passenger12234/article/details/127817191