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) ...
随机推荐
- Java 自增、自减
i++/i-- 先使用变量的值,然后改变该变量的值: ++i/--i 先改变该变量的值,然后使用变量的值: : i = i++; 最终变量i的值到底是变成1呢还是保持为0呢? java中变量自增.自减 ...
- js判断各种类型
js的六种基本类型:Object,Boolean,Number,String,Undefined,Null; Object中又有:Function,Array,Date... 如何判断数据类型? Ob ...
- 阿里云ECS服务器Ubuntu配置MySQL远程访问
root账户登录服务器Ubuntu16.04 apt-get update apt-get install mysql-server mysql-client; 安装时会让你设置root密码,输入2次 ...
- Java 中级 学习笔记 1 JVM的理解以及新生代GC处理流程
写在最前 从毕业到现在已经过去了差不多一年的时间,工作还算顺利,但总是离不开CRUD ,我觉得这样下去肯定是不行的,温水煮青蛙,势必有一天,会昏昏沉沉的迷失在温水里.所以,需要将之前学习JAVA 当中 ...
- Vue.js 入门 --- vue.js 安装
本博文转载 https://blog.csdn.net/m0_37479246/article/details/78836686 Vue.js(读音 /vjuː/, 类似于 view)是一个构建数据 ...
- react路由的跳转和传参
1.路由的跳转 一.DOM跳转 在需要跳转的页面导入import {Link} from 'react-router-dom',在需要跳转的地方使用link标签的to属性进行跳转,路由配置文件中导出的 ...
- sqlserver 存储过程调Api接口
--开启Sql Server 通讯配置-- sp_configure ; GO RECONFIGURE; GO sp_configure ; GO RECONFIGURE; GO EXEC sp_co ...
- 开发一个简单的ip解析webservice接口,并用springmvc生成客户端调用
1.创建webservice工程,这次先采用jax-ws框架,下次再尝试jax-rs(restful) 2.写个实现ip解析的类,接收传入的ip,并返回解析信息 3.Myeclipse——>Ne ...
- 自学 JAVA 的几点建议
微信公众号:一个优秀的废人 如有问题或建议,请后台留言,我会尽力解决你的问题. 前言 许久不见,最近公众号多了很多在校的师弟师妹们.有很多同学都加了我微信问了一些诸如 [如何自学 Java ]的问题, ...
- MongoDB 官方文档中的 aggregate 例子当中的 $sum: 1 , 这里的 1 起什么作用?
按照 group 的条件, 满足一条就加1, db.getCollection('user_login_info').aggregate( [ {$project:{account_id:" ...