用于函数调用的方法和装置制造方法

文档序号:6492021阅读:203来源:国知局
用于函数调用的方法和装置制造方法【专利摘要】本发明公开了一种用于函数调用的方法和装置,所述方法包括:响应于检测到程序中的函数调用,获取用于执行所述函数调用的多个备选代码模块,所述多个备选代码模块分别符合多个调用约定;获取被调用函数所采用的特定调用约定;依照所获取到的所述特定调用约定,从所述多个备选代码模块中选择符合所述特定调用约定的代码模块来执行所述函数调用。所述装置与方法对应。利用本发明的方法和装置,可以确保函数的调用方和被调用方之间调用约定上的匹配,避免由于调用约定不一致引起的问题。【专利说明】用于函数调用的方法和装置【
技术领域
】[0001]本发明涉及程序中的函数调用,更具体而言,涉及一种用于函数调用的方法和装置。【
背景技术
】[0002]多数高级程序语言都提供有函数调用的功能。在函数调用过程中,调用方和被调用方需要遵从预定的调用约定(CallingConvention)。具体地,调用约定是指在程序设计语言中为了实现函数调用而建立的一种协议。这种协议规定了在调用过程中的多种操作方式,包括,参数如何传送、参数是否可变、由谁来清理堆栈等。不同的语言、不同的编译器定义了不同的调用约定。例如,VC++6.0定义了下面几种调用约定。[0003]_cdecl是C/C++和MFC程序默认使用的调用约定,也可以在函数声明时加上—cdecl关键字来手工指定。采用—cdecl约定时,函数参数按照从右到左的顺序入栈,并且由函数调用方(caller)把参数弹出栈以清理堆栈。因此,实现可变参数的函数只能使用该调用约定。[0004]—tdcall调用约定用于调用Win32API函数。采用—stdcal约定时,函数参数按照从右到左的顺序入栈,函数的被调用方(callee)在返回前清理传送参数的栈。在该调用约定下,函数参数个数固定。[0005]—fastcall约定用于对性能要求非常高的场合。—fastcall约定将函数的从左边开始的两个大小不大于4个字节(DWORD)的参数分别放在ECX和EDX寄存器,其余的参数仍旧自右向左压栈传送,被调用的函数在返回前清理传送参数的堆栈。[0006]在其他程序语言中,相应地定义有不同的调用约定。例如,PASCAL是Pascal语言的函数调用方式,也可以在C/C++中使用。在该调用约定下,参数压栈顺序为从左到右,与—cdecl和—stdcall相反。返回时的清栈方式与_stdcall相同。[0007]不同的调用约定应用于不同的语言和不同的需要。一般来说,通过寄存器传递参数有利于提高程序运行时的性能。但是,如果将过多的参数通过寄存器进行传递也会影响执行性能,因为编译器无法在单个函数中完全利用所有的硬件寄存器。因此,在应用中,通常为不同函数选择不同的调用约定来优化性能。例如,不同的函数库可能采用不同的调用约定。此外,不同的编译器对于不同的调用约定也有其选择偏好。例如,一些编译器倾向于通过通用寄存器来传递复数参数,而另一些编译器倾向于通过浮点寄存器传递复数。[0008]多种不同的调用约定为用户的使用带来一定的困恼。如果在进行函数调用时,调用方和被调用方采用了不同的调用约定,将会导致严重的运行时错误。为了避免这样的错误,一种可能的解决方案是由用户处理每个要调用的函数。这就需要用户获得相应的头文件、源代码等。这样的方案使得用户的工作变得非常繁重,并且在许多情况下甚至是无法实现的。另一种可能的方案是要求所有的函数库提供者使用相同的“标准”调用约定。然而,这无疑会影响函数调用的执行性能,并且也并不实际。因此,希望针对调用约定提出更好的方案,来解决上述问题,从而避免因为调用约定不匹配而导致的错误。【
发明内容】[0009]考虑到现有技术中存在的问题,提出本发明,旨在减少或者避免由调用约定不匹配引发的错误。[0010]根据本发明的一个方面,提供了一种用于函数调用的方法,包括:响应于检测到程序中的函数调用,获取用于执行所述函数调用的多个备选代码模块,所述多个备选代码模块分别符合多个调用约定;获取被调用函数所采用的特定调用约定;依据所获取到的所述特定调用约定,从所述多个备选代码部分中选择符合所述特定调用约定的代码模块来执行所述函数调用。[0011]根据本发明的另一个方面,提供了一种用于函数调用的装置,包括:代码模块获取单元,配置为,响应于检测到程序中的函数调用,获取用于执行所述函数调用的多个备选代码模块,所述多个备选代码模块分别符合多个调用约定;调用约定获取单元,配置为获取被调用函数所采用的特定调用约定;代码模块选择单元,配置为,依据所获取到的所述特定调用约定,从所述多个备选代码部分中选择符合所述特定调用约定的代码模块来执行所述函数调用。[0012]利用本发明实施例的方法和装置,可以在相对于用户透明的情况下确保函数的调用方和被调用方之间调用约定上的匹配,避免由于调用约定不一致引起的问题。【专利附图】【附图说明】[0013]通过结合附图对本公开示例性实施方式进行更详细的描述,本公开的上述以及其它目的、特征和优势将变得更加明显,其中,在本公开示例性实施方式中,相同的参考标号通常代表相同部件。[0014]图1示出了适于用来实现本发明实施方式的示例性计算机系统/服务器12的框图;[0015]图2示出根据本发明一个实施例的用于函数调用的方法的流程图;[0016]图3示出根据一个实施例的确定特定调用约定的子步骤;[0017]图4示出根据一个实施例的代码示例;以及[0018]图5示出根据本发明实施例的装置的框图。【具体实施方式】[0019]下面将参照附图更详细地描述本公开的优选实施方式。虽然附图中显示了本公开的优选实施方式,然而应该理解,可以以各种形式实现本公开而不应被这里阐述的实施方式所限制。相反,提供这些实施方式是为了使本公开更加透彻和完整,并且能够将本公开的范围完整地传达给本领域的技术人员。[0020]所属【
技术领域
】的技术人员知道,本发明可以实现为系统、方法或计算机程序产品。因此,本公开可以具体实现为以下形式,即:可以是完全的硬件、也可以是完全的软件(包括固件、驻留软件、微代码等),还可以是硬件和软件结合的形式,本文一般称为“电路”、“模块”或“系统”。此外,在一些实施例中,本发明还可以实现为在一个或多个计算机可读介质中的计算机程序产品的形式,该计算机可读介质中包含计算机可读的程序代码。[0021]可以采用一个或多个计算机可读的介质的任意组合。计算机可读介质可以是计算机可读信号介质或者计算机可读存储介质。计算机可读存储介质例如可以是一但不限于——电、磁、光、电磁、红外线、或半导体的系统、装置或器件,或者任意以上的组合。计算机可读存储介质的更具体的例子(非穷举的列表)包括:具有一个或多个导线的电连接、便携式计算机磁盘、硬盘、随机存取存储器(RAM)、只读存储器(ROM)、可擦式可编程只读存储器(EPR0M或闪存)、光纤、便携式紧凑磁盘只读存储器(CD-ROM)、光存储器件、磁存储器件、或者上述的任意合适的组合。在本文件中,计算机可读存储介质可以是任何包含或存储程序的有形介质,该程序可以被指令执行系统、装置或者器件使用或者与其结合使用。[0022]计算机可读的信号介质可以包括在基带中或者作为载波一部分传播的数据信号,其中承载了计算机可读的程序代码。这种传播的数据信号可以采用多种形式,包括——但不限于——电磁信号、光信号或上述的任意合适的组合。计算机可读的信号介质还可以是计算机可读存储介质以外的任何计算机可读介质,该计算机可读介质可以发送、传播或者传输用于由指令执行系统、装置或者器件使用或者与其结合使用的程序。[0023]计算机可读介质上包含的程序代码可以用任何适当的介质传输,包括一但不限于一无线、电线、光缆、RF等等,或者上述的任意合适的组合。[0024]可以以一种或多种程序设计语言或其组合来编写用于执行本发明操作的计算机程序代码,所述程序设计语言包括面向对象的程序设计语言一诸如Java、Smalltalk、C++,还包括常规的过程式程序设计语言一诸如”C”语言或类似的程序设计语言。程序代码可以完全地在用户计算机上执行、部分地在用户计算机上执行、作为一个独立的软件包执行、部分在用户计算机上部分在远程计算机上执行、或者完全在远程计算机或服务器上执行。在涉及远程计算机的情形中,远程计算机可以通过任意种类的网络一包括局域网(LAN)或广域网(WAN)—连接到用户计算机,或者,可以连接到外部计算机(例如利用因特网服务提供商来通过因特网连接)。[0025]下面将参照本发明实施例的方法、装置(系统)和计算机程序产品的流程图和/或框图描述本发明。应当理解,流程图和/或框图的每个方框以及流程图和/或框图中各方框的组合,都可以由计算机程序指令实现。这些计算机程序指令可以提供给通用计算机、专用计算机或其它可编程数据处理装置的处理器,从而生产出一种机器,这些计算机程序指令通过计算机或其它可编程数据处理装置执行,产生了实现流程图和/或框图中的方框中规定的功能/操作的装置。[0026]也可以把这些计算机程序指令存储在能使得计算机或其它可编程数据处理装置以特定方式工作的计算机可读介质中,这样,存储在计算机可读介质中的指令就产生出一个包括实现流程图和/或框图中的方框中规定的功能/操作的指令装置(instructionmeans)的制造品(manufacture)。[0027]也可以把计算机程序指令加载到计算机、其它可编程数据处理装置、或其它设备上,使得在计算机、其它可编程数据处理装置或其它设备上执行一系列操作步骤,以产生计算机实现的过程,从而使得在计算机或其它可编程装置上执行的指令能够提供实现流程图和/或框图中的方框中规定的功能/操作的过程。[0028]图1示出了适于用来实现本发明实施方式的示例性计算机系统/服务器12的框图。图1显示的计算机系统/服务器12仅仅是一个示例,不应对本发明实施例的功能和使用范围带来任何限制。[0029]如图1所示,计算机系统/服务器12以通用计算设备的形式表现。计算机系统/服务器12的组件可以包括但不限于:一个或者多个处理器或者处理单元16,系统存储器28,连接不同系统组件(包括系统存储器28和处理单元16)的总线18。[0030]总线18表示几类总线结构中的一种或多种,包括存储器总线或者存储器控制器,外围总线,图形加速端口,处理器或者使用多种总线结构中的任意总线结构的局域总线。举例来说,这些体系结构包括但不限于工业标准体系结构(ISA)总线,微通道体系结构(MAC)总线,增强型ISA总线、视频电子标准协会(VESA)局域总线以及外围组件互连(PCI)总线。[0031]计算机系统/服务器12典型地包括多种计算机系统可读介质。这些介质可以是任何能够被计算机系统/服务器12访问的可用介质,包括易失性和非易失性介质,可移动的和不可移动的介质。[0032]系统存储器28可以包括易失性存储器形式的计算机系统可读介质,例如随机存取存储器(RAM)30和/或高速缓存存储器32。计算机系统/服务器12可以进一步包括其它可移动/不可移动的、易失性/非易失性计算机系统存储介质。仅作为举例,存储系统34可以用于读写不可移动的、非易失性磁介质(图3未显示,通常称为“硬盘驱动器”)。尽管图1中未示出,可以提供用于对可移动非易失性磁盘(例如“软盘”)读写的磁盘驱动器,以及对可移动非易失性光盘(例如⑶-ROM,DVD-ROM或者其它光介质)读写的光盘驱动器。在这些情况下,每个驱动器可以通过一个或者多个数据介质接口与总线18相连。存储器28可以包括至少一个程序产品,该程序产品具有一组(例如至少一个)程序模块,这些程序模块被配置以执行本发明各实施例的功能。[0033]具有一组(至少一个)程序模块42的程序/实用工具40,可以存储在例如存储器28中,这样的程序模块42包括——但不限于——操作系统、一个或者多个应用程序、其它程序模块以及程序数据,这些示例中的每一个或某种组合中可能包括网络环境的实现。程序模块42通常执行本发明所描述的实施例中的功能和/或方法。[0034]计算机系统/服务器12也可以与一个或多个外部设备14(例如键盘、指向设备、显示器24等)通信,还可与一个或者多个使得用户能与该计算机系统/服务器12交互的设备通信,和/或与使得该计算机系统/服务器12能与一个或多个其它计算设备进行通信的任何设备(例如网卡,调制解调器等等)通信。这种通信可以通过输入/输出(I/O)接口22进行。并且,计算机系统/服务器12还可以通过网络适配器20与一个或者多个网络(例如局域网(LAN),广域网(WAN)和/或公共网络,例如因特网)通信。如图所示,网络适配器20通过总线18与计算机系统/服务器12的其它模块通信。应当明白,尽管图中未示出,可以结合计算机系统/服务器12使用其它硬件和/或软件模块,包括但不限于:微代码、设备驱动器、冗余处理单元、外部磁盘驱动阵列、RAID系统、磁带驱动器以及数据备份存储系统等。[0035]以下结合附图和具体例子描述本发明的实施方式。根据本发明的实施例,在程序编译阶段,为程序中的函数调用提供分别遵从多个不同调用约定的多个备选代码模块。此夕卜,根据编译时提供的附加代码,程序在运行时能够确定被调用函数所采用的特定调用约定,并据此从所提供的多个备选代码模块中选择其中的一个来执行所述函数调用。由此,确保了调用方和被调用方之间调用约定上的匹配,避免了由于调用约定不一致引起的问题。[0036]现在参看图2,其示出根据本发明一个实施例的用于函数调用的方法的流程图。如图2所示,所述方法包括:步骤21,响应于检测到程序中的函数调用,获取用于执行所述函数调用的多个备选代码模块,所述多个备选代码模块分别符合多个调用约定;步骤22,获取被调用函数采用的特定调用约定;步骤23,依据所获取到的所述特定调用约定,从所述多个备选代码模块中选择符合所述特定调用约定的代码模块来执行所述函数调用。下面结合具体例子描述以上各个步骤的执行方式。[0037]在一个实施例中,首先在步骤21,响应于检测到程序中的函数调用,获取分别符合多个调用约定的多个备选代码模块,用以执行该函数调用。可以理解,在现有技术中,已经存在多种方式来检测程序中的函数调用,例如,检测函数调用采用的关键词,检测函数调用采用的格式等等。不同的程序语言可能采用不同的关键词或格式来引导或指示函数的调用。针对不同的程序语言,本领域技术人员能够相应地采用不同方式和标准来检测函数调用。[0038]响应于检测到函数调用,在步骤21中针对该函数调用获取多个备选代码模块,这多个备选代码模块分别符合多个不同调用约定,并且均用于执行上述函数调用。可以理解,在调用同一程序语言提供的内部函数库中的函数时,一般不会存在调用约定不匹配的问题。因此,在一个实施例中,在检测到程序中的函数调用的情况下,进一步判断该函数是否来自内部函数库。仅在被调用的函数为外部函数库中的函数的情况下,获取上述的多个备选代码模块。[0039]在一个实施例中,获取多个备选代码模块包括,在程序编译过程中准备多个备选代码模块,并将其插入在已编译程序中。也就是说,程序设计者或者用户仅需要在源程序中指明要调用的函数和其所属的函数库,而不必知晓其调用约定,也不必关注其调用执行过程。根据本发明实施例的方法,在程序编译阶段,不仅对源程序进行编译,而且将多个版本的调用执行代码,也就是多个备选代码模块,插入到编译的程序中,该多个备选代码模块分别用于根据不同调用约定来执行调用过程。上述备选代码模块的功能和形式类似于现有技术中插入在程序中用以执行特定功能的“桩代码”。[0040]例如,在一个具体例子中,在C程序中调用了函数FncA。为此,在编译该C程序时,可以准备3个备选代码模块,分别用于根据C程序中可能的调用约定—cdecl,—stdcall和—fastcall来执行调用过程。[0041]在一个实施例中,多个备选代码模块中的至少一个包含前序部分(prologue)、主体部分和结尾部分(epilogue)。前序部分用于完成函数调用之前的准备工作,例如,准备参数、将参数放入栈或者寄存器等。主体部分用于执行函数调用。结尾部分用于进行函数调用之后的清理工作。根据所采用的调用约定的不同,各个备选代码模块所包含的前序部分、结尾部分也不相同。下面仍然以前述的C程序为例描述不同调用约定下各个部分的执行方式。[0042]如前所述,在C程序的情况下,获取3个备选代码模块分别用于—cdecl,—stdcall和—fastcall。用于—cdecl的备选代码模块中的前序部分,或称为用于—cdecl的前序部分,根据—cdecl的调用约定将准备的参数按照从右到左的顺序推入栈中,并且,用于—cdecl的结尾部分在函数调用执行完毕之后把参数弹出栈以清理堆栈。用于—stdcal的前序部分类似地将函数参数推入栈中,但是不同的是,在该调用约定下,由函数的被调用方来清理传送参数的栈。因此,用于—stdcal的结尾部分并不执行栈的清理。另外,根据—fastcall的调用约定,用于—fastcall的前序部分将部分参数放在ECX和EDX寄存器中,并将其余参数自右向左推入栈中,并且由被调用的函数进行堆栈清理。[0043]可以理解,取决于不同的程序语言、不同的被调用函数库,有可能需要不同数目的备选代码模块,以遵从不同的调用约定。并且,取决于不同的调用约定,备选代码模块的各个组成部分的执行方式也有所不同。本领域技术人员在阅读本说明书的情况下,能够根据不同需要获取相应的备选代码模块。[0044]由于如上所述在编译过程中预先获取了多个版本的代码模块以适应于多种不同调用约定,在程序运行过程中就有可能根据被调用函数实际使用的调用约定来选择适当的代码模块来执行调用过程。为此,在步骤22,获取上述程序中的被调用函数采用的特定调用约定。[0045]在一个实施例中,获取上述特定调用约定包括,通过查询运行时对被调用函数的加载信息来确定特定调用约定。更具体而言,根据一个实施例,可以通过分析加载信息中被调用函数的修饰名来确定上述特定调用约定。可以理解,在程序运行时,系统加载器不仅要加载程序的已编译代码,还会加载程序中所调用的函数库,例如DLL(动态链接库)。另一方面,不同的编译器在对程序进行编译时,会根据一些规则来改写符号名,这又称为名称改编(NameMangling)或者名称修饰(NameDecoration)。许多编译器对函数进行名称改编时依据的规则与该函数的调用约定有关。例如,许多C程序编译器会遵从以下规则:对于_^(1(^11调用约定,在输出函数名前加上一个下划线前缀,在函数名后面加上一个〃@〃符号和其参数的字节数,格式为_functionname@number。例如,在—stdcall调用约定下,function(inta,intb)的修饰名为:_function@8。对于—cdecl调用约定,仅在输出函数名前加上一个下划线前缀,格式为—functionname。而对于—fastcall调用约定,在输出函数名前加上一个符号,在函数名后面也加一个符号和其参数的字节数,格式为@functionname@number。由此,如果被调用的函数库是由C程序编写的,那么在加载该函数库时,就可以获得按照以上改编规则进行了名称改编的导出函数。这样的导出函数具有与调用约定相对应的修饰名。因此,有可能通过分析该修饰名来获得被调用函数的调用约定。[0046]具体地,图3示出根据一个实施例的确定特定调用约定的子步骤,即步骤22的子步骤。如图3所示,首先,在步骤221,向运行时发出查询请求。根据一个实施例,该步骤由编译器插入在已编译程序中的查询语句或查询代码来实现。具体地,在程序编译阶段,编译器可以在已编译的程序体的适当位置插入查询语句,用于向运行时发出查询请求。查询请求中可以包含有待查询的被调用函数的标识信息,例如函数名称以及其他标识。接着在步骤222,响应于查询请求,获取被调用函数的修饰名。该步骤可以通过运行时环境中的系统加载器来实现。具体地,在程序运行时,加载器与现有技术类似地加载已编译的程序和调用的函数库。当执行到编译器插入的查询请求时,加载器响应于该查询请求识别出被调用函数,并从加载的函数库信息中获取导出的被调用函数的修饰名。接着在步骤223,根据所述修饰名,确定与被调用函数对应的特定调用约定。如前所述,修饰名与调用约定之间存在预定的对应关系。因此,在获取了从函数库中导出的被调用函数的修饰名的基础上,结合预定的对应关系,就可以确定与被调用函数对应的特定调用约定。[0047]根据一个实施例,在如上所述确定特定调用约定的过程中,还需要进一步注意不同编译器对函数进行名称改编可能导致的名称不一致问题。例如,假定LI语言编写的程序调用了用L2语言编写的函数库中的函数FncA。LI程序编译器在对程序进行编译时根据LI语言的约定将FncA改编为名称Al,并基于Al发出查询请求;而系统加载器通过加载函数库信息获得的导出函数FncA的修饰名为A2。在这样的情况下,在执行以上的步骤222时,就难以通过Al定位到A2,也就是难以获得被调用函数FncA的修饰名。为此,在一个实施例中,通过以下方式执行以上的步骤222,即,首先对与查询请求对应的函数标识信息(例如已修饰的函数名)进行名称解改编(demangle),从而获得原始函数名。例如,通过对Al解改编可以获得原始函数名FncA。接着,基于原始函数名获取被调用函数在函数库中的修饰名。在一个例子中,可以基于原始函数名进行部分匹配,从而获得上述修饰名。例如,由于A2是通过某种规则对原始函数名FncA进行的修饰,一般地,A2会包含FncA的符号名,或者说,A2与FncA在字符上部分匹配。通过进行这样的部分匹配,就可以从FncA找到A2。或者,在一个例子中,可以基于原始函数名进行多种备选修饰,直到获得匹配的修饰名。也就是说,尝试根据各种修饰规则对原始函数名进行修饰,直到修饰后的函数名与加载的函数库中的函数名一致。这不仅获得了被调用函数的修饰名,同时也获得了相应的修饰规则。基于以上获取的被调用函数的修饰名,就可以确定被调用函数遵从的调用约定。[0048]在一个实施例中,通过分析加载信息中被调用函数的其他特性来确定被调用函数采用的特定调用约定。例如,可以获取被调用函数的部分指令,从中分析出栈的分配、返回地址寄存器的设定等与调用约定相关的信息。通过这样的信息,也可以确定被调用函数采用的调用约定。[0049]在步骤22获取到被调用函数采用的特定调用约定的基础上,在步骤23,就可以基于上述特定调用约定,从步骤21所提供的多个备选代码部分中选择出符合所述特定调用约定的代码模块来执行函数调用。在一个实施例中,利用索引标识不同的调用约定,并相应地使得步骤21所提供的多个代码模块通过其对应的调用约定的索引来标识。这样,利用上述索引就可以快速地基于特定调用约定选择出对应的代码模块。由此,程序中的函数调用能够适合于各种不同的调用约定,而不会出现调用约定不匹配的问题。[0050]在一个实施例中,为了进一步提高执行性能,在前述的步骤22的基础上进行扩展,使得在通过查询加载信息而确定了被调用函数的特定调用约定之后,记录该特定调用约定,以便再次调用该被调用函数时直接获取上述特定调用约定。这样,仅在一个函数被初次调用时,需要向加载器查询特定调用约定;在该函数被再次调用时,可以直接读取记录的调用约定来选择适当的代码模块,从而更加快速地执行调用过程。[0051]为了实现上述过程,在一个实施例中,通过设置状态参数实现上述特定调用约定的记录。具体地,可以在已编译的程序体中设置一状态参数,该状态参数具有O和I两个可能值,O表示初次调用,I表示之后的调用。将该状态参数的初始值设置为O。每次进行函数调用时,首先判断状态参数的值。如果状态参数为0,则执行前述的调用约定的查询。在通过查询确定了特定调用约定之后,存储该调用约定,并将状态参数的值修改为I。此后调用同样的函数时,响应于状态参数的值1,直接读取之前存储的特定调用约定,从而简单地获取被调用函数采用的特定调用约定。[0052]在一个实施例中,通过地址的重新定向实现上述特定调用约定的记录。具体地,如前所述,可以使得所提供的多个代码模块通过其对应的调用约定的索引来标识。此外,为了查询加载信息以确定特定调用约定,可以理解,在已编译程序中插入有查询代码,来执行上述查询。根据本实施例,为查询代码设置指向地址,例如称为第一地址。在上述查询代码段执行完毕因而确定了特定调用约定之后,记录该特定调用约定对应的索引,并且对地址进行重新定向,也就是将原本指向上述查询代码的地址(第一地址)修改为第二地址,该第二地址指向与上述特定调用约定的索引对应的备选代码模块。这样,当再次执行函数调用时,将通过重新定向的地址直接执行与特定调用约定对应的代码模块。下面结合一段代码描述上述实施例的执行。[0053]图4示出根据一个实施例的代码示例。如图4A所示,根据该示例性代码,首先在FncA_stubs_table中定义了多个地址,其中resolve_FncA_addr指向查询代码,FncA_stubl_addr指向第一个备选代码模块,FncA_stub2_addr指向第二个备选代码模块。可以理解,尽管此处没有示出,还有可能存在更多的代码模块和相应的指向地址。多个代码模块对应于多个调用约定,并且根据调用约定的索引来标识。每次函数FncA的调用执行都从goto语句开始,该语句指向了下划线标识的地址FncA_stub_addr=FncA_stubs_table[O]?在第一次执行函数调用时,FncA_stubs_table[O]指向FncA_stubs_table中的第一个地址,即reS0lve_FncA_addr,而该地址指向查询代码。因此,执行过程进行到查询代码。如图所示,查询代码中包含了用于进行调用约定查询的语句(QueryConvention)。通过该查询代码的返回结果可以确定函数FncA采用的调用约定。之后的语句FncA_stubs_table[O]=FncA_stubs_base[stub_index]不仅记录调用约定对应的索引(stub_index),还将原来指向查询代码的地址(FncA_stubs_table[0]中的地址)修改为指向与上述特定调用约定对应的代码模块。在一个例子中,假定确定的调用约定的索引为2,于是,FncA_stubs_table[O]中的地址由resolve_FncA_addr改变为FncA_stub2_addr,如图4B所不。于是,当再次调用FncA时,仍然从地址FncA_stub_addr=FncA_stubs_table[O]开始执行。然而此时,FncA_stubs_table[O]中的地址变为FncA_stub2_addr,即指向了第二个备选代码模块。因此,执行过程将直接跳转到第二个备选代码模块来执行函数调用。从而,通过将指向查询代码的地址重新定向,直接获得了记录的调用约定进而可以获得该调用约定所对应的代码模块。[0054]可以理解,以上的代码仅仅为了示例地址的重新定向过程。实际执行的代码可以采用不同语言,具有不同形式。[0055]此外,尽管以上描述了记录所确定的特定调用约定用于函数的再次调用的具体执行方式,但是记录方式并不局限于以上的具体描述。本领域技术人员在本说明书教导下有可能采用其他方式实现上述记录,以使得所记录的特定调用约定可以直接用于同一函数的再次调用。[0056]如前所述,根据本发明的实施例的方法,提供用于不同调用约定的多个版本的代码模块,并基于被调用函数实际使用的调用约定来执行适当版本的代码模块。由此,确保了调用方和被调用方之间调用约定上的匹配,避免了由于调用约定不一致引起的问题。[0057]基于同一发明构思,本发明的实施例还提供了一种用于函数调用的装置。图5示出根据本发明实施例的装置的框图,该装置总体上标注为50。如图5所示,该用于函数调用的装置50包括:代码模块获取单元51,配置为,响应于检测到程序中的函数调用,获取用于执行所述函数调用的多个备选代码模块,所述多个备选代码模块分别符合多个调用约定;调用约定获取单元52,配置为获取被调用函数所采用的特定调用约定;代码模块选择单元53,配置为,依照所获取到的所述特定调用约定,从所述多个备选代码模块中选择符合所述特定调用约定的代码模块来执行所述函数调用。[0058]根据一个实施例,所述代码模块获取单元配置为,响应于被调用函数为外部函数库中的函数,获取所述多个备选代码模块。[0059]根据一个实施例,所述多个备选代码模块中的至少一个包括:前序部分,用于完成函数调用之前的准备工作;主体部分,用于执行函数调用;结尾部分,用于进行函数调用之后的清理工作。[0060]在一个实施例中,所述调用约定获取单元包括调用约定确定子单元(未示出),该子单元配置为通过查询所述程序运行时中所述被调用函数的加载信息来确定特定调用约定。[0061]在一个实施例中,所述调用约定确定子单元配置为:向所述程序运行时发出查询请求,其中包含被调用函数的标识信息;响应于查询请求,获取被调用函数的修饰名;基于所述修饰名,确定与被调用函数对应的特定调用约定。[0062]根据一个实施例,所述调用约定确定子单元进一步配置为:基于所述被调用函数的标识信息进行名称解改编,获得原始函数名;基于所述原始函数名获取被调用函数在函数库中的修饰名。[0063]根据一个实施例,所述调用约定获取单元还包括记录子单元,该子单元配置为,记录所确定的特定调用约定,以便再次调用该被调用函数时直接获取上述特定调用约定。[0064]根据一个实施例,所述记录子单元配置为,记录所述特定调用约定对应的索引,并将第一地址修改为第二地址,所述第一地址指向用于查询所述加载信息的代码,所述第二地址指向所述多个代码模块中与上述特定调用约定的索引对应的代码模块装置。[0065]以上用于函数调用的装置50的具体执行方式可以参照之前结合具体例子对图2的方法的描述,在此不再赘述。在一个实施例中,上述装置50中的代码模块获取单元51和代码模块选择单元53通过程序编译器来实现,调用约定获取单元52由程序编译器和系统加载器共同实现。在另一实施例中,上述装置50可以实现为与已有的编译器和/或加载器独立的装置或工具。[0066]利用本发明实施例的方法和装置,可以在相对于用户透明的情况下确保函数的调用方和被调用方之间调用约定上的匹配,避免由于调用约定不一致引起的问题。[0067]附图中的流程图和框图显示了根据本发明的多个实施例的系统、方法和计算机程序产品的可能实现的体系架构、功能和操作。在这点上,流程图或框图中的每个方框可以代表一个模块、程序段或代码的一部分,所述模块、程序段或代码的一部分包含一个或多个用于实现规定的逻辑功能的可执行指令。也应当注意,在有些作为替换的实现中,方框中所标注的功能也可以以不同于附图中所标注的顺序发生。例如,两个连续的方框实际上可以基本并行地执行,它们有时也可以按相反的顺序执行,这依所涉及的功能而定。也要注意的是,框图和/或流程图中的每个方框、以及框图和/或流程图中的方框的组合,可以用执行规定的功能或操作的专用的基于硬件的系统来实现,或者可以用专用硬件与计算机指令的组合来实现。[0068]以上已经描述了本发明的各实施例,上述说明是示例性的,并非穷尽性的,并且也不限于所披露的各实施例。在不偏离所说明的各实施例的范围和精神的情况下,对于本【
技术领域
】的普通技术人员来说许多修改和变更都是显而易见的。本文中所用术语的选择,旨在最好地解释各实施例的原理、实际应用或对市场中的技术的技术改进,或者使本【
技术领域
】的其它普通技术人员能理解本文披露的各实施例。【权利要求】1.一种用于函数调用的方法,包括:响应于检测到程序中的函数调用,获取用于执行所述函数调用的多个备选代码模块,所述多个备选代码模块分别符合多个调用约定;获取被调用函数所采用的特定调用约定;依据所获取到的所述特定调用约定,从所述多个备选代码模块中选择符合所述特定调用约定的代码模块来执行所述函数调用。2.根据权利要求1的方法,其中获取多个备选代码模块包括,响应于被调用函数为外部函数库中的函数,获取所述多个备选代码模块。3.根据权利要求1的方法,其中所述多个备选代码模块中的至少一个包括:前序部分,用于完成函数调用之前的准备工作;主体部分,用于执行函数调用;结尾部分,用于进行函数调用之后的清理工作。4.根据权利要求1的方法,其中获取所述特定调用约定包括,查询所述程序运行时中所述被调用函数的加载信息以确定特定调用约定。5.根据权利要求4的方法,其中查询所述程序运行时中所述被调用函数的加载信息以确定特定调用约定包括:向所述程序运行时发出查询请求,其中包含被调用函数的标识信息;响应于查询请求,获取被调用函数的修饰名;基于所述修饰名,确定与被调用函数对应的特定调用约定。·6.根据权利要求5的方法,其中获取被调用函数的修饰名包括:基于所述被调用函数的标识信息进行名称解改编,获得原始函数名;基于所述原始函数名获取被调用函数在函数库中的修饰名。7.根据权利要求4的方法,其中获取所述特定调用约定还包括,记录所确定的特定调用约定,以便再次调用该被调用函数时直接获取上述特定调用约定。8.根据权利要求7的方法,其中记录所确定的特定调用约定包括,记录所述特定调用约定对应的索引,并将第一地址修改为第二地址,所述第一地址指向用于查询所述加载信息的代码,所述第二地址指向所述多个代码模块中与上述特定调用约定的索引对应的代码模块。9.一种用于函数调用的装置,包括:代码模块获取单元,配置为,响应于检测到程序中的函数调用,获取用于执行所述函数调用的多个备选代码模块,所述多个备选代码模块分别符合多个调用约定;调用约定获取单元,配置为获取被调用函数所采用的特定调用约定;代码模块选择单元,配置为,依据所获取到的所述特定调用约定,从所述多个备选代码模块中选择符合所述特定调用约定的代码模块来执行所述函数调用。10.根据权利要求9的装置,其中所述代码模块获取单元配置为,响应于被调用函数为外部函数库中的函数,获取所述多个备选代码模块。11.根据权利要求9的装置,其中所述多个备选代码模块中的至少一个包括:前序部分,用于完成函数调用之前的准备工作;主体部分,用于执行函数调用;结尾部分,用于进行函数调用之后的清理工作。12.根据权利要求9的装置,其中所述调用约定获取单元包括调用约定确定子单元,配置为通过查询所述程序运行时中所述被调用函数的加载信息以确定特定调用约定。13.根据权利要求12的装置,其中所述调用约定确定子单元配置为:向所述程序运行时发出查询请求,其中包含被调用函数的标识信息;响应于查询请求,获取被调用函数的修饰名;基于所述修饰名,确定与被调用函数对应的特定调用约定。14.根据权利要求13的装置,其中所述调用约定确定子单元配置为:基于所述被调用函数的标识信息进行名称解改编,获得原始函数名;基于所述原始函数名获取被调用函数在函数库中的修饰名。15.根据权利要求12的装置,其中所述调用约定获取单元还包括记录子单元,配置为记录所确定的特定调用约定,以便再次调用该被调用函数时直接获取上述特定调用约定。16.根据权利要求15的装置,其中所述记录子单元配置为,记录所述特定调用约定对应的索引,并将第一地址修改为第二地址,所述第一地址指向用于查询所述加载信息的代码,所述第二地址指向所述多个代码模块中与上述特定调用约定的索引对应的代码模块装置。【文档编号】G06F9/44GK103853532SQ201210500365【公开日】2014年6月11日申请日期:2012年11月29日优先权日:2012年11月29日【发明者】官孝峰,郭久福,蒋健,朱鸿伟申请人:国际商业机器公司
网友询问留言 已有0条留言
  • 还没有人留言评论。精彩留言会获得点赞!
1