C++ ABI之名字改编(以Qt为例)
2016-07-22 13:54
417 查看
在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 工具:
在linux,我们可以使用 nm 或 readelf 工具:
准备工作完毕,你运行上述命令,即可看到大量的符号出现在屏幕上,我们下面对比Qt Manual给出的函数,看看这些符号(只简单看几个,不然我也看不懂)
这堆东西,乱七八糟的,怎么看啊??
加几个空格
这个信息有些多,有些乱,比前面的风格差远了。而且很多过时的东西都混在其中。
关于这些东西的解释,详见calling_conventions
http://www.agner.org/optimize/calling_conventions.pdf
http://en.wikipedia.org/wiki/Name_mangling
http://stackoverflow.com/questions/4667266/c-name-mangling-by-hand
http://labs.qt.nokia.com/2009/08/12/some-thoughts-on-binary-compatibility/
http://developer.qt.nokia.com/wiki/toStdWStringAndBuiltInWchar_SimplifiedChinese
名字改编也罢,但由于历史原因,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 | 表示这是一个函数 |
参考
http://www.agner.org/optimize/calling_conventions.pdfhttp://en.wikipedia.org/wiki/Name_mangling
http://stackoverflow.com/questions/4667266/c-name-mangling-by-hand
http://labs.qt.nokia.com/2009/08/12/some-thoughts-on-binary-compatibility/
http://developer.qt.nokia.com/wiki/toStdWStringAndBuiltInWchar_SimplifiedChinese
相关文章推荐
- C++ ABI之名字改编(以Qt为例)
- C++学习笔记——string型 到 int,double,float型的相互转换:ostringsream,istringstream,stringstream
- c语言中结构体的使用
- C++常见问题: 字符串分割函数 split
- Eclispe 阅读C++代码
- protobuf C++入门
- Cpp环境 【poj 2940 】【Uva11054】【Vijos2909】Wine Trading in Gergovia 格尔高维亚的肮脏红酒交易
- C++中嵌入python程序——使用API接口,从函数到类
- C++学习之路(2) C++输入输出 new delete操作符 函数重载
- C++之离港篇学习笔记之内存管理
- POJ 1862 Stripies(G++与C++的抉择)
- poj2531 Network Saboteur
- C++主要特性/优势
- C++之离港篇学习笔记之新特性
- c++重载>>与<<
- C++虚函数的工程应用2
- NYOJ 76超级台阶问题
- C++识别中文标点
- 【高精度算法】A-B 要求:除数与被减数均为正整数
- NYOJ236心急的c小加