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
http://blog.csdn.net/dbzhang800/article/details/6707051
C++ ABI之名字改变,编译器生成符号研究(以Qt为例)的更多相关文章
- C++ ABI之名字改编(以Qt为例)
在C++中,由于重载等技术的存在,编译器要将函数.结构体.类等等的信息传递给链接器,就不能像C语言那样简单地通过函数名来完成,它需要提供额外的参数信息,而还要和C语言共用链接器,这就需要用到名字改编( ...
- nm 命令能够显示目标文件中重载函数的名字改变(C++)
#include <stdio.h> #include <iostream> using std::cout; using std::endl; //这里的两个不同的add函数 ...
- ip分包研究-以UDP为例
原文 http://www.jianshu.com/p/741cb12ab0c9 测试环境: 利用iOS的NE从TUN抓取IP packets,如下代码分析ip包: uint16_t iphid = ...
- Notepad++中调用cl.exe编译器(Windows)
Notepad++中调用cl.exe编译器(Windows) 近来在notepad++中写代码,写完后总是习惯性的想去VS里面编译一下,看看代码是否有误.但有时候一些零碎的小文件总是懒得再VS中打开, ...
- PL真有意思(三):名字、作用域和约束
前言 这两篇写了词法分析和语法分析,比较偏向实践.这一篇来看一下语言设计里一个比较重要的部分:名字.在大部分语言里,名字就是标识符,如果从抽象层面来看名字就是对更低一级的内存之类的概念的一层抽象.但是 ...
- lncRNA研究
------------------------------- Long noncoding RNAs are rarely translated in two human cell lines. ( ...
- VS2008编译器编译出来的文件比mingw编译的要几乎小一半
为什么要在VS2008中使用QT静态编译呢?很简单,因为VS2008编译器编译出来的文件比mingw编译的要几乎小一半. 好了现在我们来做些准备工作,VS2008自然要安装的,然后打上SP1的补丁.然 ...
- [Inside HotSpot] C1编译器HIR的构造
1. 简介 这篇文章可以说是Christian Wimmer硕士论文Linear Scan Register Allocation for the Java HotSpot™ Client Compi ...
- myeclipse修改编译器版本的方法 .
今天在导入一个工程时,发现出现java.lang.UnsupportedClassVersionError: Bad version number in .class file异常,检查了一下我的my ...
随机推荐
- Head First设计模式学习笔记
最近在学C++,直接语法之后觉得不太有意思,直接做项目又觉得太肤浅.正好之前一直想学设计模式来着,可惜之前一直在玩C,所以没有机会深入学习,于是决定用C++把设计写一遍.看了点GOF的<设计模式 ...
- bootstrap 智能表单 demo示例
1.基本配置,支持的元素类型 2.自动布局 3.自定义布局 4.自定义表单 5.数据绑定 6.带验证的表单 7.智能搜索 8.级联下拉 9.图片上传 图片有点大了,屏幕不够大的话可能看的不习惯,没事 ...
- javascript函数作用域链之词法作用域
在开发语言中常见的作用域规则有 块级作用域和词法作用域 作用域 顾名思义就是起作用的区域 定义一变量后 ,可以在此范围作用的区域 一.块级作用域就是用一个块结构分割变量的访问区域 块即{ } 代 ...
- Tomcat启动报Error listenerStart错误
http://xpenxpen.iteye.com/blog/1545648 今天启动Tomcat启动不了,报以下错: org.apache.catalina.core.StandardContext ...
- Java如何实现对Mysql数据库的行锁
场景如下: 用户账户有余额,当发生交易时,需要实时更新余额.这里如果发生并发问题,那么会造成用户余额和实际交易的不一致,这对公司和客户来说都是很危险的. 那么如何避免: 网上查了下,有 ...
- 面试题之请写出用于校验 HTML 文本框中输入的内容全部为数字 的 javascript 代码
<input type="text" id="d1" onblur=" chkNumber(this)"/> <scrip ...
- MySql 日期字符串类型互转
1.data_format 日期转字符串 select date_format(Now(), '%Y-%m-%d %H:%i'); 2.str_to_date 字符串转日期 select str_to ...
- php基础知识(很简单一套适合零基础的朋友学习)
红色的一般都是重点,还有自己的一些废话 运算符 算术运算符: 基本运算(除数不能为0) 比较运算符: 大小比较(类型比较), 如果两个类型不一样,系统会自动转换成统一类型 赋值运算符: 基本赋值和运算 ...
- 使用RUBY生成二维码
二维码现在貌似已经成为一个项目必不可少的总分了,最近在做的微信项目,更是大大的依赖于二维码,微信公众平台提供的临时二维码,局限太多,只能带一个ID,做不了太多有意义的整个,因为我们很多的二维码是需要自 ...
- 1TB到底能存放多少东西?
网盘大战逐渐升级,360和百度网盘先后推出的1TB网盘存储,而腾讯甚至为其微云网盘打出10TB的招牌来哄抢用户. 这里我们聊聊1TB的网盘究竟能放多少东西? 以下是我在网上找到的一些资料. 一)30年 ...