一、轧名Name mangling和修饰名 Decoration name
在现代编程语言中,许多情况下需要解析程序实体的唯一既定名称,轧名(Name mangling)(又叫命名修饰)是解决这些问题的一种手段。它在函数、结构、类或者其他数据结构的名称中加入额外的信息编码,因此能从编译器传递更多的语义信息给链接器。
轧名允许编程语言在不同的名称空间(不同的作用域)中为不同的实体提供同名的标识符,而不会有命名的冲突。
编译器产生的目标代码(object code)通常会和其他的目标代码相链接,这通常是由链接器来完成的。链接器需要知道每个程序实体的许多信息。例如,为了成功链接一个函数,需要知道的函数的名字、参数的数目、类型等等。
轧名解决了现代编程语言中的很多问题,比如重载等等。它为连接器提供了额外的信息,在编译器和连接器之间传递信息。
Windows平台的C轧名规则
总之,实际上像C一样不支持重载的语言,并不怎么需要轧名。轧名在C语言中可以为函数提供额外信息,比如调用约定(calling conventions)。例如,Windows平台的编译器支持一系列调用约定,这些约定决定了调用参数是如何被传递给子例程并返回的结果。
为什么有调用约定呢?
汇编语言只提供了一条指令,call ptr,其功能是把CS:IP (指令段:指令指针,决定着下一条执行指令的地址)压栈,并且修改CPU的指令指针,作一个跳转。在函数结束的地方,我们使用另一条指令,ret,其功能是把栈中的返回地址取出,并且跳转到那条指令。
不幸的是,汇编语言只提供了指令跳转的命令,作为函数调用另一个重要组成部分的参数传递,其方式就很五花八门了,你可以通过寄存器传值,可以通过调用栈传值,可以通过某一块具体的内存传值(类似全局变量)。然后在被调用函数中,从寄存器,栈或者是内存中读取这些信息。
想象一下如果被调用函数是某一个程序员所编写的,调用者是另一个程序员,那么他俩之间对于参数的传递方式就有了一个约定。
高级语言的出现,把这个问题隐藏了起来。我们在编写一般的c++程序的时候,通常不需要顾虑参数传递的底层实现,但是,这并不意味着这一问题不再出现——我们只是把责任推给了编译器。编译器作为一个计算机程序,总是遵照一定的规则工作,每一个规则对应了一种调用约定,比如一些已经不再被使用的调用约定__fortran,__pascal...
由于这些调用约定之间并不兼容,编译器利用命名变形来标明具体采用了哪一种调用约定。这套轧名规则是由微软建立的,之后为其他各大编译器厂商包括Digital Mars,Borland, and GNU gcc所遵从。这套规则甚至应用到其他的语言,比如Pascal,D,Delphi,Fortran和C#。这些语言编写的子例程,就以种有异于其默认的约定调用呼叫既有的Windows的类库,反之亦然。
int _cdecl f (int x) { return 0; }
int _stdcall g (int y) { return 0; }
int _fastcall h (int z) { return 0; }
使用32为编译器,轧名后的结果为
_f
_g@4
@h@4
stdcall和fastcall的变形规则里,方法名被编码成_name@X和@name@X,其中X是个十进制数,表示的函数参数列表大小(byte)(包括Fastcall中用寄存器传递的参数),而对于cdecl,方法名只是简单的以下划线开头。
分享到:
相关推荐
函数调用方式决定了函数参数入栈的顺序,是由调用者函数还是被调用函数负责清除栈中的参数等问题,而函数名修饰规则决定了编译器使用何种名字修饰方式来区分不同的函数,如果函数之间的调用约定不匹配或者名字修饰不...
Visual C/C++的编译器提供了几种函数调用约定,了解这些函数调用约定的含义及它们之间的区别可以帮助我们更好地调试程序。在这篇文章里,我就和大家共同探讨一些关于函数调用约定的内容。 Visual C/C++的编译器支持...
在C++中,为了允许操作符重载和函数重载,C++编译器往往按照某种规则改写每一个入口点的符号名,以便允许同一个名字(具有不同的参数类型或者是不同的作用域)有多个用法,而不会 打破现有的基于C的链接器。...
调用约定(Calling Convention)是指在程序设计语言中为了实现函数调用而建立的一 种协议。这种协议规定了该语言的函数中的参数传送方式、参数是否可变和由谁来处理堆栈等问题。不同的语言定义了不同的调用约定!
C_C++函数符号生成规则(函数名的修饰);C++ 函数重载.pdf
纯html标签静态调用xml文件并显示,不包含js方法。 以及xsl对xml文件的的显示修饰方法
C++调用其它语言的函数,由于编译器生成函数的机制不一样,所以需要经过特殊处理,才可以调用。调用C语言的函数,需要在函数声明的地方语句extern “C”。如果不使用该语句,在链接的时候,编译器就会报以下这种错误...
本文给大家介绍了C++中的const限定修饰符。
静态连接库,动态链接库知识。__declspec(dlldexport)/__declspec(dllimport)含义及使用 __stdcall含义及使用 ...3、在函数名的前面用下划线修饰,在函数名的后面由@来修饰并加上栈需要的字节数的空间
如果使用“__stdcall”调用方式,可能产生C不识别的修饰名,所以设置导出函数时要采用.def文件形式,而不是__declspec(dllexport)形式。后者会进行修饰名转换,C语言无法识别函数。 下面的代码是一个定义文件的示例...
static:修饰符:修饰变量,函数。作用域:变量仅仅在本文件可见,函数在本文件可以被调用。static在函数内部定义的话,分配在堆中,数值保存在data段,而不是在栈中,而且只赋值一次。 extern:修饰符:修饰变量,...
DTD元素的修饰符DTD元素的修饰符DTD元素的修饰符DTD元素的修饰符DTD元素的修饰符DTD元素的修饰符
关于C和C++的兼容问题 如果要写C和C++兼容的DLL,因为在C和C++下使用了不同的名字修饰规则以及不同的调用约定,所以,如果DLL是用C编写和编译的,则在
写论文时,图表线条及坐标轴的修饰是很麻烦的,本程序可以解决常用的修饰问题。最后保存图片。
Java 访问修饰符 public protected private
C# 访问修饰符 比较
主要对Java的主要修饰符进行分析,相关特点与用法。
超赞的皮肤修饰PS动作下载
应用WinAPI函数修饰程序窗体实例
字体修饰标记提供专业字体修饰标记