【问题标题】:symbol lookup error: .so.2 undefined symbol符号查找错误:.so.2 未定义符号
【发布时间】:2016-07-13 14:19:05
【问题描述】:

如何解决这个未定义的符号。

odroid@odroid:~/flycapture.2.9.3.43_armhf/bin$ sudo ./FlyCap2 ./FlyCap2:符号查找错误:/usr/lib/libflycapturegui.so.2:未定义符号:ZN5Gnome5Glade3Xml6createERKSsRKN4Glib7ustringES7

odroid@odroid:~/flycapture.2.9.3.43_armhf/bin$ sudo ldconfig -v | grep fly

/sbin/ldconfig.real: Path `/lib/arm-linux-gnueabihf' given more than once
/sbin/ldconfig.real: Path `/usr/lib/arm-linux-gnueabihf' given more than once
/sbin/ldconfig.real: /lib/arm-linux-gnueabihf/ld-2.23.so is the dynamic linker, ignoring
/sbin/ldconfig.real: /usr/lib/libflycapture.so.2 is not a symbolic link
/sbin/ldconfig.real: /usr/lib/libflycapturegui.so.2 is not a symbolic link

libflycapture.so.2 -> libflycapture.so.2.9.3.43
libflycapturegui.so.2 -> libflycapturegui.so.2.9.3.43

odroid@odroid:~/flycapture.2.9.3.43_armhf/bin$ ls -lah /usr/lib | grep fly

-rw-r--r--   1 root root 473K Jul 13 13:26 libflycapturegui.so
-rw-r--r--   1 root root 473K Jul 13 13:26 libflycapturegui.so.2
-rw-r--r--   1 root root 473K Jul 13 13:26 libflycapturegui.so.2.9.3.43
-rw-r--r--   1 root root 3.3M Jul 13 13:26 libflycapture.so
-rw-r--r--   1 root root 3.3M Jul 13 13:26 libflycapture.so.2
-rw-r--r--   1 root root 3.3M Jul 13 13:26 libflycapture.so.2.9.3.43

【问题讨论】:

    标签: symbols


    【解决方案1】:

    首先,我们可以查看可用信息,并使用它开始搜索。当您使用 Linux 时,它很可能是 GCC 或 Clang 重整符号,这为我们提供了一个很好的起点:我们可以查找有关 GNU 重整方案的信息。

    接下来,寻找符号中的模式。有多个一数多字母字符串,其中数字为字符串中字母的总数;这可能表明这些是名称。

    考虑到这一点,我们可以将符号ZN5Gnome5Glade3Xml6createERKSsRKN4Glib7ustringES7 分解为:

    Z
    N
    5Gnome
    5Glade
    3Xml
    6create
    E
    R
    K
    S
    s
    R
    K
    N
    4Glib
    7ustring
    E
    S
    7
    

    现在,根据PDF "Calling Conventions" (pg.38) 中描述的 GNU3-4 修改方案,名称被编码为:

    <public name>    ::= _Z <qualified name>
    <qualified name> ::= N [<simple name>]<sup>∞</sup><sub>2</sub> E
        There are a minimum of 2 "simple name" symbols.
    <simple name>    ::= <name length> <name>
        "Name length" is a decimal number indicating the length of "name".
    Nested names are listed inwards, with the leftmost one being the outermost.
    

    我们可以用它来拼凑一个部分符号,以及它的含义:

    Symbol: _ZN5Gnome5Glade3Xml6createE
    Means : The symbol's qualified name is "Gnome::Glade::Xml::create".
    Note  : At least one underscore appears to have been dropped by the error message.
    

    考虑到它后面的垃圾和名称本身,这是一个函数符号。因此,考虑到这一点,我们可以将符号输入谷歌,并得到a link to the class' reference. 根据这个链接,函数定义为:

    Class  :   Gnome::Glade::Xml
    Section: "Static Public Member Functions"
    Full declaration:
        static Glib::RefPtr< Xml >
        create (const std::string &filename, const Glib::ustring &root=Glib::ustring(),
                const Glib::ustring &domain=Glib::ustring())
    

    要仔细检查,我们可以使用该参数列表来确定函数的错位名称:

    static Glib::RefPtr< Xml >
    Gnome::Glade::Xml::create (const std::string &filename,
                               const Glib::ustring &root=Glib::ustring(),
                               const Glib::ustring &domain=Glib::ustring());
    

    直接将其放入一个简单的 C++ 程序中(使用 Glib::RefPtr&lt;T&gt;Glib::ustringGnome::Glade::Xml 的虚拟类),然后将 typeid(Gnome::Glade::Xml::create).name() 输出到 cout 不会生成正确的符号,这表明修改方案或 ABI 的变化。更具体地说,std::string 被修改为NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE,而不是预期的Ss。在a bit of digging around 之后,我发现这是由于 GCC 5.1 及更高版本的更改,其中宏_GLIBCXX_USE_CXX11_ABI 表示使用新的string(和新名称)而不是旧的。这也给出了问题原因的可能指示(见本文末尾)。

    因此,考虑到这一点,最好使用旧方案手动修改函数的名称,看看它是否与符号匹配。

    <public name> ::= <simple or qualified name> [<parameter type>]<sup>∞</sup><sub>1</sub>
        There is a minimum of 1 "parameter type" symbols.
    
    Name      : Gnome::Glade::Xml::create
    Parameters:
        const std::string&   : RKSs
            "RK" is "Reference (R), const (K)", and "Ss" is a special symbol for std::string.
        const Glib::ustring& : RK4Glib7ustringE
            "RK" is followed by the type's "qualified name".
        const Glib::ustring& : RK4Glib7ustringE
    

    由于第三个参数是第三个的重复,所以它使用缩写规则,其中Sx_是一个缩写符号。根据 PDF,每个用户定义的类型名称、命名空间名称和非简单类型都分配了一个缩写,但实体名称本身没有。所以……

    S0_ : 5Gnome
    S1_ : 5Glade
    S2_ : 3Xml
    S3_ : Ss
    S4_ : RKSs
    S5_ : 4Glib
    S6_ : 7ustring
    S7_ : RK4Glib7ustringE
    

    因此,第三个参数是S7_。考虑到这一点,最终的符号是:

    Name          : _ZN5Gnome5Glade3Xml6createE
    Parameter list: RKSsRKN4Glib7ustringES7_
        Parameters:
            RKSs              : const std::string&
            RKN4Glib7ustringE : const Glib::ustring&
            S7_               : const Glib::ustring&
    Symbol        : _ZN5Gnome5Glade3Xml6createERKSsRKN4Glib7ustringES7_
        Two underscores were apparently dropped somewhere, one on each end.
    

    将其提供给实用程序站点 Demangler.com 会生成以下解组符号:

    Gnome::Glade::Xml::create(std::string const&, Glib::ustring const&, Glib::ustring const&)
    

    由于 PDF 声明返回类型不包含在普通函数的修饰方案中,这似乎是正确的。


    现在,如上所述,ABI 已更改,导致修改方案和/或库类型名称发生更改。所以,为了检查这一点,我做了一些测试。

    // main.cpp
    //#undef  _GLIBCXX_USE_CXX11_ABI
    //#define _GLIBCXX_USE_CXX11_ABI 0
    
    //#include <iostream>
    //#include <typeinfo>
    #include <string>
    
    
    namespace Glib {
        template<typename T>
        class RefPtr {};
    
        class ustring {};
    }
    
    namespace Gnome {
        namespace Glade {
            class Xml {
              public:
                static Glib::RefPtr< Xml >
                create (const std::string &filename,
                        const Glib::ustring &root=Glib::ustring(),
                        const Glib::ustring &domain=Glib::ustring());
            };
        }
    }
    
    Glib::RefPtr< Gnome::Glade::Xml >
    Gnome::Glade::Xml::create (const std::string &filename,
                               const Glib::ustring &root /*=Glib::ustring()*/,
                               const Glib::ustring &domain /*=Glib::ustring()*/) {
                                   return Glib::RefPtr<Gnome::Glade::Xml>();
                               }
    
    int main() {
    //    std::cout << typeid(const std::string&).name() << std::endl;
    //    std::cout << typeid(Gnome::Glade::Xml::create).name() << std::endl;
    
    //    std::cout << typeid(std::string).name() << std::endl;
    }
    

    通过这段代码,我首先使用typeid输出函数符号,然后注释掉前两个#includes和main()的主体,使用-c编译器选项编译文件,然后使用nm main.o 输出符号列表。虽然typeid 与符号不匹配,但nm 显示的名称是:

    // With macros commented out:
    _ZN5Gnome5Glade3Xml6createERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKN4Glib7ustringESD_
    
    // With macros active:
    _ZN5Gnome5Glade3Xml6createERKSsRKN4Glib7ustringES7_
    

    由于第二个与错误信息中提到的符号相同,这表明修改方案仍然相同,因此问题的解决方案是:

    您尝试链接的目标文件是使用不同版本的 GCC(或您使用的任何 GCC 兼容编译器)编译的,或者是使用设置为 0_GLIBCXX_USE_CXX11_ABI 宏编译的而另一个不是。

    【讨论】:

      【解决方案2】:

      我在 Arch linux 上安装 flycapture 时遇到了同样的问题。最终我发现有一个更新版本的 flycapture (2.11.3.121) 没有这个问题。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-06-19
        • 2017-01-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-10-02
        相关资源
        最近更新 更多