• 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
  • 相关阅读:
    halcon学习和实践(第一个范例threshold.hdev)
    【Linux从入门到精通】信号(信号保存 & 信号的处理)
    wxpython:wx.grid 表格显示 Excel xlsx文件
    【代码随想录算法训练营】第38天 | 第九章 动态规划(一)+ 复习第9天 第四章 字符串(二)
    【Python 实战基础】Pandas如何计算最大值最小值所在的行
    9 款顶级 iPhone 系统修复软件,可修复各种 iPhone 软件问题
    数据库 与 数据仓库
    labview信号时域分析编程笔记
    flink 技术总结待续
    javascript包管理工具npm、pnpm、webpack
  • 原文地址:https://blog.csdn.net/passenger12234/article/details/127817191