发明内容
本公开实施例至少提供一种系统库的访问方法、装置以及计算机可读存储介质。
第一方面,本公开实施例提供了一种系统库的访问方法,包括:
通过调用系统接口获取应用进程中加载的各动态库的动态库标识和程序头信息;
根据待查询符号所属目标动态库的动态库标识,从获取的各动态库的程序头信息中,查找到所述目标动态库的程序头信息;
根据所述待查询符号对应的用于查询的符号标识,和查找到的所述目标动态库的程序头信息,确定所述待查询符号的运行地址信息。
在一种可能的实施方式中,根据所述待查询符号的符号标识,和查找到的所述目标动态库的程序头信息,确定所述待查询符号的运行地址信息,包括:
基于查找到的所述目标动态库的程序头信息,计算得到符号运行起始地址信息,和所述目标动态库的动态Dynamic段信息;
基于所述Dynamic段信息,和所述待查询符号的符号标识,确定所述待查询符号的偏移信息;
基于所述符号运行起始地址信息和所述待查询符号的偏移信息,确定所述待查询符号的运行地址信息。
在一种可能的实施方式中,基于所述Dynamic段信息,和所述待查询符号的符号标识,确定所述待查询符号的偏移信息,包括:
基于所述Dynamic段信息,查找到符号表;
基于所述待查询符号的符号标识,从所述符号表中查找到所述待查询符号的偏移信息。
在一种可能的实施方式中,基于所述待查询符号的符号标识,从所述符号表中查找到所述待查询符号的偏移信息,包括:
基于所述Dynamic段信息,查找到哈希表;并基于所述待查询符号的符号标识计算哈希值;
基于所述哈希值从所述哈希表中查找到所述待查询符号的偏移信息在所述符号表中的位置信息,并基于该位置信息,从所述符号表中查找到所述待查询符号的偏移信息。
在一种可能的实施方式中,所述偏移信息包括运行地址偏移信息;
所述基于所述符号运行起始地址信息和所述待查询符号的偏移信息,确定所述待查询符号的运行地址信息,包括:
基于所述符号运行起始地址信息和所述运行地址偏移信息,确定所述待查询符号的运行地址信息。
在一种可能的实施方式中,所述偏移信息还包括符号标识地址偏移信息;
所述方法还包括:
基于所述Dynamic段信息,查找到字符串表地址信息;
基于所述符号标识地址偏移信息,和所述字符串表地址信息,查找到与所述运行地址信息对应的符号标识;
判断查找到的与所述运行地址信息对应的符号标识与所述待查询符号对应的用于查询的符号标识是否一致;
若一致,则基于确定的所述运行地址信息运行所述待查询符号。
第二方面,本公开实施例还提供一种系统库的访问装置,包括:
获取模块,用于通过调用系统接口获取应用进程中加载的各动态库的动态库标识和程序头信息;
查找模块,用于根据待查询符号所属目标动态库的动态库标识,从获取的各动态库的程序头信息中,查找到所述目标动态库的程序头信息;
确定模块,用于根据所述待查询符号对应的用于查询的符号标识,和查找到的所述目标动态库的程序头信息,确定所述待查询符号的运行地址信息。
在一种可能的实施方式中,确定模块用于根据以下步骤确定所述待查询符号的运行地址信息:
基于查找到的所述目标动态库的程序头信息,计算得到符号运行起始地址信息,和所述目标动态库的动态Dynamic段信息;
基于所述Dynamic段信息,和所述待查询符号的符号标识,确定所述待查询符号的偏移信息;
基于所述符号运行起始地址信息和所述待查询符号的偏移信息,确定所述待查询符号的运行地址信息。
在一种可能的实施方式中,确定模块用于根据以下步骤确定所述待查询符号的偏移信息:
基于所述Dynamic段信息,查找到符号表;
基于所述待查询符号的符号标识,从所述符号表中查找到所述待查询符号的偏移信息。
在一种可能的实施方式中,确定模块用于根据以下步骤从所述符号表中查找到所述待查询符号的偏移信息:
基于所述Dynamic段信息,查找到哈希表;并基于所述待查询符号的符号标识计算哈希值;
基于所述哈希值从所述哈希表中查找到所述待查询符号的偏移信息在所述符号表中的位置信息,并基于该位置信息,从所述符号表中查找到所述待查询符号的偏移信息。
在一种可能的实施方式中,确定模块查找到的偏移信息包括运行地址偏移信息;
确定模块,在基于所述符号运行起始地址信息和所述待查询符号的偏移信息,确定所述待查询符号的运行地址信息时,用于:
基于所述符号运行起始地址信息和所述运行地址偏移信息,确定所述待查询符号的运行地址信息。
在一种可能的实施方式中,确定模块查找到的偏移信息还包括符号标识地址偏移信息;
所述查找模块还用于:
基于所述Dynamic段信息,查找到字符串表地址信息;基于所述符号标识地址偏移信息,和所述字符串表地址信息,查找到与所述运行地址信息对应的符号标识;
所述访问装置还包括:
校验模块,用于判断所述查找模块查找到的与所述运行地址信息对应的符号标识与所述待查询符号对应的用于查询的符号标识是否一致;
运行模块,用于在所述校验模块确定与所述运行地址信息对应的符号标识与所述待查询符号对应的用于查询的符号标识一致后,基于确定的所述运行地址信息运行所述待查询符号。
第三方面,本公开实施例还提供一种计算机设备,包括:处理器、存储器和总线,所述存储器存储有所述处理器可执行的机器可读指令,当计算机设备运行时,所述处理器与所述存储器之间通过总线通信,所述机器可读指令被所述处理器执行时执行上述第一方面,或第一方面中任一种可能的实施方式中的步骤。
第四方面,本公开实施例还提供一种计算机可读存储介质,该计算机可读存储介质上存储有计算机程序,该计算机程序被处理器运行时执行上述第一方面,或第一方面中任一种可能的实施方式中的步骤。
本公开实施例提供的系统库的访问方法,可以通过调用系统接口(比如高版本安卓系统支持的一个接口)获取各个动态库的动态库标识和程序头(program header)信息,然后基于待查询符号所属目标动态库的动态库标识(也可以称为文件名),从获取到的各个动态库的program header信息中,找到该待查询符号所属目标动态库的program header信息,再根据待查询符号的符号标识,和查找到的program header信息,得到待查询符号的运行地址信息,从而可以实现对符号的运行地址的自动查找,不需要借助系统程序来返回符号访问地址,从而可以避免因系统限制无法对非公开系统库中的符号进行查找,使得应用软件调试优化方案得以顺利实施,提高了应用软件开发的效率。
为使本公开的上述目的、特征和优点能更明显易懂,下文特举实施例,并配合所附附图,作详细说明。
具体实施方式
为使本公开实施例的目的、技术方案和优点更加清楚,下面将结合本公开实施例中附图,对本公开实施例中的技术方案进行清楚、完整地描述,显然,所描述的实施例仅仅是本公开一部分实施例,而不是全部的实施例。通常在此处附图中描述和示出的本公开实施例的组件可以以各种不同的配置来布置和设计。因此,以下对在附图中提供的本公开的实施例的详细描述并非旨在限制要求保护的本公开的范围,而是仅仅表示本公开的选定实施例。基于本公开的实施例,本领域技术人员在没有做出创造性劳动的前提下所获得的所有其他实施例,都属于本公开保护的范围。
经研究发现,随着操作系统的不断更新,操作系统对一些常用接口做了改变。例如,有的操作系统限制了应用动态链接非公开系统库NDK库,也即是应用程序无法通过调用系统接口直接获取动态库中特定符号的运行地址信息,极大程度的增加了依赖该操作系统运行的应用软件的开发难度。
基于上述研究,本公开实施例提供了一种系统库的访问方法,可以通过调用系统接口(比如高版本安卓系统支持的一个接口)获取各个动态库的动态库标识信息和programheader信息,然后结合待查询符号所属目标动态库的动态库标识(也可以称为文件名),确定该待查询符号所属目标动态库的program header信息,进而基于该program header信息和待查询符号的符号标识,得到待查询符号的运行地址信息,从而可以实现对符号的运行地址的自动查找。
需要说明的是,上述问题的发现过程以及本公开针对上述问题所提出的解决方案,都应该是发明人在本公开过程中对本公开做出的贡献。
为便于对本实施例进行理解,首先对本公开实施例所公开的一种系统库的访问方法进行详细介绍,本公开实施例所提供的系统库的访问方法的执行主体一般为对应用进行开发测试的计算机设备,在一些可能的实现方式中,该系统库的访问方法可以通过该计算机设备中的处理器调用存储器中存储的计算机可读指令的方式来实现。
参见图1所示,为本公开实施例提供的系统库的访问方法的流程图,包括步骤S101~S103。
针对有的操作系统限制了应用动态链接非公开系统库符号,也即是应用无法通过调用系统接口直接获取动态库中特定符号的运行地址信息的情况,本实施例提出基于系统接口获取应用进程中加载的各个动态库的动态库标识和program header信息,然后使用待查询符号所属的目标动态库标识来匹配获得目标动态库的program header信息,并根据目标动态库的program header信息与待查询符号的符号标识,来进行进一步查找,得到待查询符号的运行地址信息,以实现绕过系统限制访问系统库。
基于上述思想,首先获取应用进程中加载的各动态库的动态库标识和programheader信息,具体操作如S101所述:
S101:通过调用系统接口获取应用进程中加载的各动态库的动态库标识和程序头信息;
在具体的实施过程中,通过调用系统接口获取应用进程中加载的各动态库的动态库标识和program header信息。在应用进程中,应用会加载所需动态库为应用中程序运行提供支持,其中待查询符号所属目标动态库也会在应用进程中被应用所加载。为找到目标动态库的program header信息,首先可获取应用启动时加载的各个动态库信息,再进行筛选得出待查询符号所属目标动态库的program header信息。
在具体操作中,可以通过调用系统接口,也即利用系统中的链接器Linker中的函数获取应用进程中加载的动态库信息,该函数为dl_iterate_phdr函数。具体地,dl_iterate_phdr函数遍历应用启动时加载的各个动态库,并将遍历到的动态库信息(包括动态库标识以及其对应的program header信息)返回给应用中的回调函数。基于此,应用即可获取应用启动时加载的各个动态库的动态库标识以及与动态库标识对应的programheader信息。结合待查询符号所属目标动态库的动态库标识,即可查找到与该动态库标识对应的program header信息,具体操作详见S102所述:
S102:根据待查询符号所属目标动态库的动态库标识,从获取的各动态库的program header信息中,查找到所述目标动态库的program header信息;
具体实施过程中,在获取到应用启动时加载的各个动态库的动态库标识和program header信息后,可以根据待查询符号所属目标动态库的动态库标识,从获取的各个动态库的program header信息中,查找到目标动态库的program header信息。也即,在上述S101中,调用系统接口后得到返回的应用启动时加载的各个动态库的动态库标识以及对应的program header信息,也即是每个动态库标识均对应一个program header信息。根据已知的待查询符号所属动态库的动态库标识,与应用启动时加载的动态库标识进行比对,即可找到目标动态库标识所对应的program header信息。再根据获取到的目标动态库program header信息可进一步得到用于查找待查询符号所需的必要信息,详见S103所述。
S103:根据所述待查询符号对应的用于查询的符号标识,和查找到的所述目标动态库的program header信息,确定所述待查询符号的运行地址信息。
在具体实施过程中,得到目标动态库标识对应的program header信息后,基于program header信息和所述用于查询的符号标识,进行进一步查询、计算,可以得到待查询符号的运行地址信息。
具体地,可以基于program header信息计算出符号运行起始地址信息(Load_bias),以及目标动态库的动态Dynamic段信息,再依据得到的目标动态库的动态Dynamic段信息,进一步找到用于查询符号所必须的数据表:哈希表(hash table)和符号表(symboltable),除此之外,还可以得到字符串表(string table)。根据待查询符号对应的用于查询的符号标识,以及上述用于查询符号所必须的数据表,即可获取符号运行地址偏移信息;在此基础上,将符号运行地址偏移信息与符号运行起始地址信息进行相加运算,即可获取待查询符号运行地址信息。除此之外,string table可以用于待查询符号运行地址信息的确认以及验证过程,将在下文详细描述。
下面对上述过程做进一步解释说明。
基于上述描述,在确定待查询符号的运行地址信息时,可以根据所述待查询符号的符号标识,和查找到的所述目标动态库的程序头信息,确定所述待查询符号的运行地址信息,具体可以包括:
基于查找到的所述目标动态库的程序头信息,计算得到符号运行起始地址信息,和所述目标动态库的动态Dynamic段信息;
基于所述Dynamic段信息,和所述待查询符号的符号标识(比如符号名),确定所述待查询符号的偏移信息;
基于所述符号运行起始地址信息和所述待查询符号的偏移信息,确定所述待查询符号的运行地址信息。
上述基于目标动态库的程序头信息进行符号运行地址信息查找的具体过程中,首先可以由目标动态库的Program Header信息,计算符号运行起始地址信息,和目标动态库的Dynamic段信息。基于上述目标动态库的程序头信息,也即是Program Header值,即可获取符号运行起始地址信息以及目标动态库的Dynamic段信息,再基于目标动态库的Dynamic段信息(如地址信息),即可跳转至目标动态库的Dynamic段,在目标动态库的Dynamic段中,存放有symbol table以及hash table的地址信息,基于symbol table以及hash table的地址信息,即可获取symbol table以及hash table。
在具体操作中,基于目标动态库Dynamic段获取symbol table以及hash table,再结合待查询符号的符号标识,即可查询到待查询符号的偏移信息,这里具体获取待查询符号的偏移信息的过程将在下文中详细描述。根据获取到的待查询符号的偏移信息,以及上面基于目标动态库的Program Header信息计算的待查询符号的运行起始地址信息,即可得到待查询符号的运行地址信息。基于待查询符号的偏移信息以及运行起始信息确定待查询符号的运行地址在下文中详细描述。
在上述基于所述Dynamic段信息,和所述待查询符号的符号标识,确定所述待查询符号的偏移信息时,具体执行过程包括:
基于所述Dynamic段信息,查找到symbol table;
基于所述待查询符号的符号标识,从所述symbol table中查找到所述待查询符号的偏移信息。
在获取待查询符号的偏移信息时,首先要进行的操作是基于目标动态库的Dynamic段信息获取symbol table,该symbol table中存放有目标动态库中符号的偏移信息,根据待查询符号的偏移信息在symbol table中的位置信息,即可查找到待查询符号的偏移信息;具体可以在symbol table中遍历得到待查询符号的偏移信息,也可以基于hashtable实现快速查找,详见下述描述。
上述过程中,可以通过hash table对待查询符号的偏移信息在symbol table中的位置进行快速查找,具体包括:
基于所述Dynamic段信息,查找到hash table;并基于所述待查询符号的符号标识计算hash值;基于所述hash值从所述hash table中查找到所述待查询符号的偏移信息在所述symbol table中的位置信息。
在上述实施过程中,首先基于目标动态库的Dynamic段信息获取hash table,上述hash table中存放有hash值以及hash值所对应的符号的偏移信息在symbol table中的位置信息。在具体操作中,通过哈希算法,依据待查询符号的符号标识(符号名),获取符号标识所对应的hash值,继而在hash table中依据获取的hash值即可快速查找到对应符号偏移信息在symbol table中的位置信息。
从symbol table中查找到待查询符号的偏移信息包括运行地址偏移信息;所述基于所述符号运行起始地址信息和所述待查询符号的偏移信息,确定所述待查询符号的运行地址信息,包括:
基于所述符号运行起始地址信息和所述运行地址偏移信息,确定所述待查询符号的运行地址信息。
参见图2所示,为本公开实施例提供的系统库的访问方法中,查找符号运行地址具体方法的示意图;
在前述内容中有说明,在获取到目标动态库的Program Header信息后,首先可以由目标动态库的program header信息,计算符号运行起始地址信息,和目标动态库的Dynamic段信息。再基于目标动态库的Dynamic段,定位到symbol table、hash table、以及string table,下面对如何使用symbol table、hash table、以及string table来最终得到并确认符号运行地址作进一步说明:
参见图2,基于待查询符号的符号名(上述符号标识)计算得到对应的hash值,根据hash值在hash table中比对即可查找到得到符号偏移信息在symbol table中的位置,从而得到符号的偏移信息。该符号的偏移信息也即包括符号的运行地址偏移信息,以及符号名地址偏移信息(即所述符号标识地址偏移信息);在应用进程中,符号运行地址相对符号运行起始地址存在偏移;因而,在查询符号运行地址时,则需要符号运行起始地址信息加上符号运行地址的偏移信息,方能得到符号的实际运行地址。在找到符号运行地址后,还可基于符号名对该符号运行地址进行验证,判断获取的符号运行地址是否正确,在确认无误后,则基于确定的所述运行地址信息运行所述待查询符号。
上述验证过程即可以概括为如下步骤:基于所述Dynamic段信息,查找到stringtable地址信息;基于所述符号标识地址偏移信息,和所述string table地址信息,查找到与所述运行地址信息对应的符号标识;判断查找到的与所述运行地址信息对应的符号标识与所述待查询符号对应的用于查询的符号标识是否一致;
需要再次说明的是,在上文中提到依据Dynamic段信息可找到用于验证待查询符号运行地址的string table。以及在上文中还提到,基于Dynamic段信息,可以查找到symbol table,基于待查询符号的符号标识,从symbol table中可以查找到待查询符号的偏移信息(可以基于hash table实现快速查找),这里的偏移信息除了包括上述介绍的运行地址偏移信息外,还包括符号标识地址偏移信息。如图3所示,基于符号标识地址偏移信息以及字符串表地址信息,可以得到符号标识地址信息,进而可以查找到与所述运行地址信息对应的符号标识,符号标识可以为所述符号名。当确定查找到的符号标识与用于查找的符号标识一致,则查找到的符号运行地址正确,则可以基于确定的符号运行地址运行所查找的符号。
本领域技术人员可以理解,在具体实施方式的上述方法中,各步骤的撰写顺序并不意味着严格的执行顺序而对实施过程构成任何限定,各步骤的具体执行顺序应当以其功能和可能的内在逻辑确定。
基于同一发明构思,本公开实施例中还提供了与系统库的访问方法对应的系统库的访问装置,由于本公开实施例中的装置解决问题的原理与本公开实施例上述系统库的访问方法相似,因此装置的实施可以参见方法的实施,重复之处不再赘述。
参照图4所示,为本公开实施例提供的一种系统库的访问装置的示意图,该访问装置包括:获取模块41、查找模块42、确定模块43;其中,
获取模块41,用于通过调用系统接口获取应用进程中加载的各动态库的动态库标识和程序头信息;
查找模块42,用于根据待查询符号所属目标动态库的动态库标识,从获取的各动态库的程序头信息中,查找到所述目标动态库的程序头信息;
确定模块43,用于根据所述待查询符号对应的用于查询的符号标识,和查找到的所述目标动态库的程序头信息,确定所述待查询符号的运行地址信息。
在一种可能的实施方式中,确定模块43用于根据以下步骤确定所述待查询符号的运行地址信息:
基于查找到的所述目标动态库的程序头信息,计算得到符号运行起始地址信息,和所述目标动态库的动态Dynamic段信息;
基于所述Dynamic段信息,和所述待查询符号的符号标识,确定所述待查询符号的偏移信息;
基于所述符号运行起始地址信息和所述待查询符号的偏移信息,确定所述待查询符号的运行地址信息。
在一种可能的实施方式中,确定模块43根据以下步骤确定所述待查询符号的偏移信息:
基于所述Dynamic段信息,查找到符号表;
基于所述待查询符号的符号标识,从所述符号表中查找到所述待查询符号的偏移信息。
在一种可能的实施方式中,确定模块43用于根据以下步骤从所述符号表中查找到所述待查询符号的偏移信息时,用于:
基于所述Dynamic段信息,查找到哈希表;并基于所述待查询符号的符号标识计算哈希值;
基于所述哈希值从所述哈希表中查找到所述待查询符号的偏移信息在所述符号表中的位置信息,并基于该位置信息,从所述符号表中查找到所述待查询符号的偏移信息。
在一种可能的实施方式中,确定模块43查找到的偏移信息包括运行地址偏移信息;
确定模块43基于所述符号运行起始地址信息和所述待查询符号的偏移信息,用于确定所述待查询符号的运行地址信息:
基于所述符号运行起始地址信息和所述运行地址偏移信息,确定所述待查询符号的运行地址信息。
在一种可能的实施方式中,确定模块43查找到的偏移信息还包括符号标识地址偏移信息;
所述查找模块42还用于:
基于所述Dynamic段信息,查找到字符串表地址信息;基于所述符号标识地址偏移信息,和所述字符串表地址信息,查找到与所述运行地址信息对应的符号标识;
所述访问装置还包括:
校验模块44,用于判断所述查找模块查找到的与所述运行地址信息对应的符号标识与所述待查询符号对应的用于查询的符号标识是否一致;
运行模块45,用于在所述校验模块确定与所述运行地址信息对应的符号标识与所述待查询符号对应的用于查询的符号标识一致后,基于确定的所述运行地址信息运行所述待查询符号。
本公开实施例通过调用系统接口(比如高版本安卓系统支持的一个接口)获取各个动态库的动态库标识和程序头program header信息,然后基于待查询符号所属目标动态库的动态库标识(也可以称为文件名),从获取到的各个动态库的program header信息中,找到该待查询符号所属动态库的program header信息,进而得到待查询符号的运行地址信息,从而可以实现对符号的运行地址的自动查找,不需要借助系统程序来返回符号访问地址,从而可以避免因系统限制无法对非公开系统库中的符号进行查找,使得应用软件调试优化方案得以顺利实施,提高了应用软件开发的效率。
关于访问装置中的各模块的处理流程、以及各模块之间的交互流程的描述可以参照上述方法实施例中的相关说明,这里不再详述。
对应于图5中的系统库的访问的方法,本公开实施例还提供了一种计算机设备50,如图5所示,为本公开实施例提供的计算机设备50结构示意图,包括:处理器51、存储器52、和总线53。所述存储器52存储有所述处理器51可执行的机器可读指令,当计算机设备50运行时,所述处理器51与所述存储器52之间通过总线53通信,所述机器可读指令被所述处理器51执行时执行响应访问请求的方法,这里不再赘述。
本公开实施例还提供一种计算机可读存储介质,该计算机可读存储介质上存储有计算机程序,该计算机程序被处理器运行时执行上述方法实施例中所述的系统库的访问方法的步骤。其中,该存储介质可以是易失性或非易失的计算机可读取存储介质。
本公开实施例所提供的系统库的访问方法的计算机程序产品,包括存储了程序代码的计算机可读存储介质,所述程序代码包括的指令可用于执行上述方法实施例中所述的系统库的访问方法的步骤,具体可参见上述方法实施例,在此不再赘述。
该计算机程序产品可以具体通过硬件、软件或其结合的方式实现。在一个可能实施例中,所述计算机程序产品具体体现为计算机存储介质,在另一个可能实施例中,计算机程序产品具体体现为软件产品,例如软件开发包(Software Development Kit,SDK)等等。
所属领域的技术人员可以清楚地了解到,为描述的方便和简洁,上述描述的系统和装置的具体工作过程,可以参考前述方法实施例中的对应过程,在此不再赘述。在本公开所提供的几个实施例中,应该理解到,所揭露的系统、装置和方法,可以通过其它的方式实现。以上所描述的装置实施例仅仅是示意性的,例如,所述单元的划分,仅仅为一种逻辑功能划分,实际实现时可以有另外的划分方式,又例如,多个单元或组件可以结合或者可以集成到另一个系统,或一些特征可以忽略,或不执行。另一点,所显示或讨论的相互之间的耦合或直接耦合或通信连接可以是通过一些通信接口,装置或单元的间接耦合或通信连接,可以是电性,机械或其它的形式。
所述作为分离部件说明的单元可以是或者也可以不是物理上分开的,作为单元显示的部件可以是或者也可以不是物理单元,即可以位于一个地方,或者也可以分布到多个网络单元上。可以根据实际的需要选择其中的部分或者全部单元来实现本实施例方案的目的。
另外,在本公开各个实施例中的各功能单元可以集成在一个处理单元中,也可以是各个单元单独物理存在,也可以两个或两个以上单元集成在一个单元中。
所述功能如果以软件功能单元的形式实现并作为独立的产品销售或使用时,可以存储在一个处理器可执行的非易失的计算机可读取存储介质中。基于这样的理解,本公开的技术方案本质上或者说对现有技术做出贡献的部分或者该技术方案的部分可以以软件产品的形式体现出来,该计算机软件产品存储在一个存储介质中,包括若干指令用以使得一台计算机设备(可以是个人计算机,服务器,或者网络设备等)执行本公开各个实施例所述方法的全部或部分步骤。而前述的存储介质包括:U盘、移动硬盘、只读存储器(Read-OnlyMemory,ROM)、随机存取存储器(Random Access Memory,RAM)、磁碟或者光盘等各种可以存储程序代码的介质。
最后应说明的是:以上所述实施例,仅为本公开的具体实施方式,用以说明本公开的技术方案,而非对其限制,本公开的保护范围并不局限于此,尽管参照前述实施例对本公开进行了详细的说明,本领域的普通技术人员应当理解:任何熟悉本技术领域的技术人员在本公开揭露的技术范围内,其依然可以对前述实施例所记载的技术方案进行修改或可轻易想到变化,或者对其中部分技术特征进行等同替换;而这些修改、变化或者替换,并不使相应技术方案的本质脱离本公开实施例技术方案的精神和范围,都应涵盖在本公开的保护范围之内。因此,本公开的保护范围应所述以权利要求的保护范围为准。