zoukankan      html  css  js  c++  java
  • C++ ABI之名字改变,编译器生成符号研究(以Qt为例)

    在C++中,由于重载等技术的存在,编译器要将函数、结构体、类等等的信息传递给链接器,就不能像C语言那样简单地通过函数名来完成,它需要提供额外的参数信息,而还要和C语言共用链接器,这就需要用到名字改编(name mangling),又叫名字修饰(name decoration)。

    名字改编也罢,但由于历史原因,C++没有这方面的标准(C++没有ABI方面的标准,名字改编只是ABI问题的一部分)。于是编译器们各自为政,生成的文件无法通用。

    于是:在Windows下,你会发现,同一版本的QtCore4.dll,不同编译器编译出来的无法通用。同一个函数void f(std::wstring s),同一个编译器(MSVC),不同选项(/Zc:wchar_t-/Zc:wchar_t),导出的符号不同。

    在Qt中,我们只关注下面两种名字改编:

    • Itanium C++ ABI (GCC3、GCC4,包括MinGW)
    • Microsoft C++ ABI

    注:对于Intel编译器,在Windows下和微软ABI一致,在其他平台下和GCC保持一致。

    用例子来说话

    找个什么例子呢?额... 不妨找个简单的动态库,看看它导出的函数名字吧。Qt的Core和Gui模块都太复杂了,就拿Qt的Test模块来看看吧,QtTest4.dll 或 libQtTest.so.4.8.0

    如何看到符号呢?

    • 在windows下,我们可以使用 dumpbin 工具:

     

    dumpbin /EXPORTS qttest4.dll
    • 在linux,我们可以使用 nm 或 readelf 工具:

     

    nm -D libQtTest.so.4.8.0
    readelf -Ws libQtTest.so.4.8.0

    准备工作完毕,你运行上述命令,即可看到大量的符号出现在屏幕上,我们下面对比Qt Manual给出的函数,看看这些符号(只简单看几个,不然我也看不懂)

    放一行太长了,只好这样了,原型/Itanium/Microsoft

    1

    void QTest::qSleep(int ms)

    原型

    _ZN5QTest6qSleepEi

    Itanium ABI

    ?qSleep@QTest@@YAXH@Z

    Microsoft ABI

    2

    const char * QTest::currentTestFunction()

     

    _ZN5QTest19currentTestFunctionEv

     

    ?currentTestFunction@QTest@@YAPBDXZ

     

    3

    int QTest::qExec(QObject *testObject, int argc=0, char **argv=0)

     

    _ZN5QTest5qExecEP7QObjectiPPc

     

    ?qExec@QTest@@YAHPAVQObject@@HPAPAD@Z

     

    4

    int QTest::qExec(QObject *testObject, const QStringList &arguments)

     

    _ZN5QTest5qExecEP7QObjectRK11QStringList

     

    ?qExec@QTest@@YAHPAVQObject@@ABVQStringList@@@Z

     

    5

    QTestData & QTest::newRow(const char * dataTag)

     

    _ZN5QTest6newRowEPKc

     

    ?newRow@QTest@@YAAAVQTestData@@PBD@Z

     

    6

    ...

     

    ...

     

    ...

     

    这堆东西,乱七八糟的,怎么看啊??

    试着读读看

    void QTest::qSleep(int ms)

    原型

    _ZN5QTest6qSleepEi

    Itanium ABI

    ?qSleep@QTest@@YAXH@Z

    Microsoft ABI

    Itanium

     

    _ZN5QTest6qSleepEi

    加几个空格

    _Z N 5 QTest 6 qSleep E i

    _Z

     

    C++名字前缀

    N...E

    复合名字起始字符 QTest::qSleep

     
     

    5 QTest

    长度为5的名字QTest

     

    6 qSleep

    长度为6的名字qSleep

    i

     

    参数类型 int

    Microsoft

     

    ?qSleep@QTest@@YAXH@Z

    这个信息有些多,有些乱,比前面的风格差远了。而且很多过时的东西都混在其中。

    C++名字前缀

    qSleep

    最内层的名字

    @

    名字分隔符

    QTest

    前一个名字的外层名字

    @@

    名字结束

    Y

    函数调用是 near 方式

    A

    调用惯例__cdecl

    X

    返回值类型 void

    H

    参数类型 int

    @

    参数表结束

    Z

    表示这是一个函数

    关于这些东西的解释,详见calling_conventions

    参考

    http://blog.csdn.net/dbzhang800/article/details/6707051

  • 相关阅读:
    YGC问题排查,又让我涨姿势了!
    AI时代,还不了解大数据?
    实战篇:一个核心系统 3 万行代码的重构之旅
    监控系统选型,这篇不可不读!
    实时离线一体大数据在资产租赁saas服务中使用
    基于监控服务打造微服务治理生态体系
    CDH6.3.2升级Hive到4.0.0
    强化学习 9 —— DQN 改进算法DDQN、Dueling DQN tensorflow 2.0 实现
    强化学习 8 —— DQN 算法 Tensorflow 2.0 实现
    强化学习 7——Deep Q-Learning(DQN)公式推导
  • 原文地址:https://www.cnblogs.com/findumars/p/5104247.html
Copyright © 2011-2022 走看看