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://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++ ABI之名字改变,编译器生成符号研究(以Qt为例)
		
在C++中,由于重载等技术的存在,编译器要将函数.结构体.类等等的信息传递给链接器,就不能像C语言那样简单地通过函数名来完成,它需要提供额外的参数信息,而还要和C语言共用链接器,这就需要用到名字改编( ...
 - 以QT为例谈环境搭建
		
以QT为例谈环境搭建 作者:哲思 时间:2022.1.5 邮箱:1464445232@qq.com GitHub:zhe-si (哲思) (github.com) 前言 自从实习结束,好久没写博客了. ...
 - Qt编程之Qt样例表(QSS)
		
For a long time, Qt has allowed you to decorate your GUIs with CSS’ish style sheets. Inspired by the ...
 - C++的二进制兼容问题(以QT为例)
		
二进制不兼容带来的问题(需要重新编译库文件,以前编译的失效): http://my.oschina.net/lieefu/blog/505363?fromerr=f5jn7rct 二进制不兼容的原理: ...
 - qt 单例程序
		
1.http://qt.nokia.com的网站把QtSingleApplication 的源代码qtsingleapplication-2.6_1-opensource.zip 下载下来,然后解压缩 ...
 - wchar_t是内置还是别名(亲测有效:wchar_t在windows下是16位整数的别名,在linux等平台下是32位整数的别名。MSVC2008开始默认是/Zc:wchar_t)
		
接前一篇C++ ABI之名字改编(以Qt为例),继续看看C++名字改编相关的问题. 问题 MSVC 有一对选项/Zc:wchar_t- 与 /Zc:wchar_t控制wchar_t 于是 wchar_ ...
 - C++中的名字重整技术
		
C++ 一直为人诟病之一的原因是他的二进制模块兼容性不好,即ABI(Application Binary Interface)问题.对于同一源代码,不同编译器,甚至同一编译器不同版本都不兼容,其编译出 ...
 - qt creator源码全方面分析(2-1-1)
		
目录 C++的策略/二进制兼容性问题 定义 ABI注意事项 可做与不可做 库程序员的技巧 位标志 使用d指针 故障排除 在没有d指针的情况下将新数据成员添加到类中 添加已重新实现的虚函数 使用新类 向 ...
 - 自定义的插件如何加载到Qt Designer中(详细)
		
要想在Qt Designer中使用自定义控件,必须要使Qt Designer能够知道我们的自定义控件的存在.有两种方法可以把新自定义控件的信息通知给Qt Designer:“升级(promotion) ...
 
随机推荐
- .NET Core 3.1和WorkerServices构建Windows服务
			
介绍 ASP.NET Core 3增加了一个非常有意思的功能Worker Service.他是一个ASP.NET Core模板,他允许我们创建托管长期的运行的后台服务,这些服务具体实现IHostedS ...
 - Python PyInstaller安装和使用教程
			
安装 PyInstalle Python 默认并不包含 PyInstaller 模块,因此需要自行安装 PyInstaller 模块. 安装 PyInstaller 模块与安装其他 Python 模块 ...
 - 快速开发架构Spring Boot 从入门到精通 附源码
			
导读 篇幅较长,干货十足,阅读需花费点时间.珍惜原创,转载请注明出处,谢谢! Spring Boot基础 Spring Boot简介 Spring Boot是由Pivotal团队提供的全新框架,其设计 ...
 - nginx 负载均衡的配置
			
首先搭建好三台nginx,我是用VM搭建的 nginx搭建,https://www.cnblogs.com/liubaoqing/p/10507962.html 这里的三台nginx ,ip分别是 1 ...
 - ILSpy反编译工具之C#反汇编
			
1.下载ILspy工具 https://github.com/icsharpcode/ILSpy#ilspy------- 注意: ILspy需要在电脑上安装.NET Framework 4.0. ...
 - dp - 循环数组的最大和
			
首尾相连数组的最大子数组和 时间限制:1000 ms | 内存限制:65535 KB 难度:4 描述 给定一个由N个整数元素组成的数组arr,数组中有正数也有负数,这个数组不是一般的数组,其首尾是 ...
 - java intellij 工具的简单用法
			
一.目录结构 1.新建项目(Empty Project) -> 新建module(可以有多个) => 出来src文件夹 -> 在src文件夹中新建package -> 在pa ...
 - ORM基础3 在python脚本里调用Django环境
			
1.查询 1.# all获取所有的object,结果QuerySet,列表 print('all'.center(80, '=')) ret = models.Person.objects.all() ...
 - Linux起源
			
Linux起源 操作系统出现时间线: Unix1970年诞生 ,71年用C语言重写 Apple II 诞生于1976年 window诞生于1985年 Linux诞生于1991年,由大学生Linus T ...
 - Perl语言入门(中文版)(第6版) 东南大学出版社
			
第一章简介 问题与答案 这本书适合你吗? 为何有这么多的脚注? 关于习题和解答? 习题前标的数字是什么意思? 如果我是Perl讲师? “Perl”这个词表示什么意思? Larry为什么要创造Perl? ...