首页> 中国专利> 多处理器平台下的动态二进制翻译方法

多处理器平台下的动态二进制翻译方法

摘要

本发明公开了一种多处理器平台下的动态二进制翻译方法。目的是提供一种利用操作系统缺页中断机制实现翻译控制的方法。技术方案是先搭建由多个处理器组成的硬件平台,然后设计翻译软件,由翻译软件负责二进制代码的转换;接着实现动态二进制翻译VMM,该VMM包含全局变量表、翻译控制例程和模式切换模块三大部分,具有普通模式和翻译模式两种工作模式;整合软硬件构建翻译系统,将VMM安装到主处理器,将翻译软件安装到协处理器,启动主处理器和协处理器;最后使用软硬结合的多处理器动态二进制翻译系统翻译执行用户程序。采用本发明能使翻译过程和执行过程在两个不同的处理器上并行,使程序高效翻译执行且具有更大的灵活性和可扩展性。

著录项

法律信息

  • 法律状态公告日

    法律状态信息

    法律状态

  • 2015-04-08

    未缴年费专利权终止 IPC(主分类):G06F9/45 授权公告日:20130605 终止日期:20140223 申请日:20110223

    专利权的终止

  • 2013-06-05

    授权

    授权

  • 2011-07-20

    实质审查的生效 IPC(主分类):G06F9/45 申请日:20110223

    实质审查的生效

  • 2011-06-08

    公开

    公开

说明书

技术领域

本发明涉及微处理器体系结构领域动态二进制翻译方法,特别是一种多处理器平台下的动态二进制翻译方法。

背景技术

动态二进制翻译方法是虚拟化计算系统的重要支撑技术之一。动态二进制翻译方法是一种运行时的二进制代码转换方法,它能够在运行时将程序的二进制代码(源机器码)转换为与目标体系结构兼容的二进制代码。运用动态二进制翻译方法,可以使源软件不需重编译就能够直接在目标平台上高效地执行。近年来,随着体系结构的多元化发展和应用软件的极大丰富,动态二进制翻译方法广泛应用于构建虚拟计算平台,实现软件跨平台移植和辅助微处理器设计几个方面,从而成为工业界与学术界关注的热点。

传统面向单个处理器的动态二进制翻译方法一般采用软件手段实现一个翻译程序,在单核平台下对另一种体系结构的用户程序进行翻译执行。通常来说,这种用户程序在该系统下的翻译执行过程分为两个阶段。即翻译阶段和执行阶段。在翻译阶段,处理器将源体系结构的代码块翻译成目标体系结构的代码块。在执行阶段,已翻译的代码块在处理器上执行。具体翻译流程一般分为以下几个步骤:

第一步:未翻译程序加载并在动态二进制翻译器的监控下开始执行。

第二步:当遇到未翻译的指令时,翻译器启动一次翻译过程,从该指令开始翻译一个基本块或一个页面的源体系结构代码。并将翻译后的代码块储存在特定的存储区域中。

第三步:将已翻译的代码块链接到原始代码段,从翻译后代码的入口处继续执行程序。

第四步:当已翻译代码块执行完毕后,系统跳转回到原始程序代码段,并产生下一次翻译请求,开始新的翻译执行周期。

传统动态二进制翻译流程中,由于只有一个处理器,翻译过程和执行过程是串行的,在翻译执行的过程中需要不断进行现场切换,翻译执行速度受到严重的限制。另外,纯软件实现的动态二进制翻译器也存在一些不足。如翻译速度较慢,翻译执行过程中必须对用户程序每条指令的执行进行主动监控以获取运行时信息等等。这些都成为制约翻译系统性能提升的瓶颈。随着微体系结构和虚拟化技术的飞速发展,传统的“由纯软件动态二进制翻译器与单核平台组成翻译系统进行翻译”的翻译方法不能满足用户需求。为此,人们考虑采用新的翻译方法来进行动态二进制翻译。

利用多处理器进行动态二进制翻译是一种新的思路。在翻译系统中引入一个或多个协处理器并开发相应的翻译软件在其上运行,以此来对用户程序进行动态翻译。这种多处理器翻译系统能够在翻译的同时不影响已翻译程序的执行,通过翻译与执行的并行使翻译系统整体性能提升。“协处理器+翻译软件”的多处理器动态二进制翻译方法与传统方法相比具有以下几个明显优势。首先,协处理器对用户程序翻译与主处理器对已翻译代码的执行可以并行。具体来说,当主处理器执行翻译后的目标体系结构代码的同时,协处理器能够对源体系结构代码块进行翻译,生成后续目标体系结构代码。当主处理器执行完一个目标体系结构代码块时,若后续代码块已经就绪,就只需要从指定的位置开始执行该代码块即可,而协处理器则转而翻译其他的源体系结构代码块。这样就大大节省了翻译开销。其次,多个协处理器在翻译时也可以通过分段翻译的方式实现并行,从而使翻译的整体效率提升。第三,翻译软件能够提供覆盖整个源体系结构指令集的翻译,具有较好的可扩展性和灵活性。

引入协处理器的方法使翻译系统具有极大的性能提升潜力,然而要发挥这种潜力,必须开发相应的支持多处理器翻译的软件,如上面所说的翻译程序。此外,由于翻译过程和执行过程分别在不同处理器上运行,传统动态二进制翻译方法中采用的翻译与控制一体化的翻译软件也不适合运用在新的系统中。必须在主处理器上实现一套支持多处理器翻译控制和通信机制的软件,才能够最终使系统正常运转,发挥多处理器翻译带来的优势。

发明内容

本发明要解决的技术问题是提出一个运用多处理器平台进行动态二进制翻译的方法,利用操作系统缺页中断机制实现翻译控制,支持“主处理器+协处理器+翻译程序”以页面为单位对用户程序进行翻译执行。

本发明的技术方案是:

第一步,选择两个或两个以上的处理器并搭建硬件平台。主处理器与协处理器可同构也可异构,也可以是支持不同指令集的处理器。连接方式可采用总线方式或采用全局共享存储方式。

采用总线方式连接的硬件平台的搭建方法是:

1.1选择通信接口。可以选择GPIO(General Purpose IO),PCI等常用的通信接口作为主处理器和协处理器间交互的通信接口。

1.2定制通信总线。根据总线两端的通信接口定制通信总线。

1.3用通信总线连接主处理器和协处理器。

1.4安装通信接口的驱动程序。

采用共享存储方式连接的硬件平台的搭建方法是将主处理器和协处理器与全局共享存储器的两个访问端口连接。

第二步,结合协处理器的总线宽度、访存协议、地址空间大小设计翻译软件。翻译软件负责二进制代码的转换,由协处理器运行。翻译软件将传统软件实现的动态二进制翻译系统中的基本块构建,代码生成和链接部分抽取出来,作为独立可运行的软件,并在其中添加了通信和代码Cache管理功能。

翻译软件通过维护分支目标地址映射表完成代码链接功能。分支目标地址映射表是记录翻译前后的用户程序中分支目标地址的对应关系的表,该表有以下几个字段:

●用户程序分支目标地址:用户程序未翻译时包含的分支目标地址。

●标志位:该标志位为1时,表示用户程序分支目标地址已翻译,为0时表示未翻译。

●翻译后的分支目标地址:用户程序分支目标地址翻译后对应的地址。

翻译软件通过维护代码Cache页面管理表对代码Cache中的代码页面进行管理。该表由以下几个字段:

●页地址。为页面在代码Cache已翻译区中的地址。

●有效位。表示页地址所指的页是否为空。

●LRU值。LRU值为页地址所指的页被访问的次数,翻译软件总是选择LRU值最小的页面进行替换。

翻译软件的流程如下:

2.1初始化分支目标地址映射表和代码cache页面管理表,将表中各个字段设为0。进入空闲状态,等待来自主处理器的翻译请求。

2.2接收到翻译请求后,在分支目标地址映射表中查询发生缺页的页地址,若不存在对应记录,则说明该地址未翻译,转步骤2.3。若存在对应记录则不启动翻译任务,直接将对应的分支目标地址发送给主处理器,转步骤2.4。

2.3翻译用户程序页面。翻译软件新建一个翻译任务,查代码Cache页面管理表,在表中找到一个空页面(有效位为0的记录),并将该空页面的记录中的有效位置为1,更新LRU值,然后开始翻译用户程序页面,并将生成的已翻译代码存放到该空页面中。每翻译到一个分支目标地址,翻译软件在分支目标地址映射表中添加一项,并将翻译后的对应地址填入该项的翻译后分支目标地址字段中。当空页面满时,翻译软件暂停翻译动作。

2.4发送响应消息。翻译软件以缺页地址为索引查分支目标地址映射表,找到其对应的“翻译后的分支目标地址”并发送给主处理器上运行的VMM。

2.5继续翻译用户程序。翻译软件继续翻译用户程序页面剩下的代码,直至翻译完毕。

2.6若当前没有新的翻译任务,则等待主处理器的翻译请求。

第三步,实现动态二进制翻译VMM,该VMM基于linux操作系统内核实现,包含全局变量表、翻译控制例程和模式切换模块三大部分,具有普通模式和翻译模式两种工作模式。

3.1实现全局变量表。

全局变量表中包含VMM支持翻译过程必须的各种变量,该表在编译时被加入到内核中。其实现方法为:

在内核/include/文件夹下添加“transsupport.h”文件。在文件中定义如下全局变量:

●workmode:描述当前操作系统的执行模式。0为普通模式,1为翻译模式,2为翻译模式且有任务正在运行。

●start_readyzone/end_readyzone:记录执行区起始/终止地址。

●fault_address:记录发生缺页的地址,发送翻译请求时由主处理器发送给协处理器。一般为一个基本块的入口地址。翻译过程中将产生该地址对应的翻译后地址。该对应地址将作为鉴别首先可用页面的依据。

●xaddr:交换地址,由协处理器翻译产生,发送翻译结果时发送给主处理器。该交换地址的偏移地址部分(后12位)实际上即为新入口地址的偏移地址。

●start_code/end_code:原始程序代码段起始/终止地址。

●start_data/end_data:原始程序数据段起始/终止地址。

3.2实现翻译控制例程

翻译控制例程为VMM的核心部分。通过在内核中与用户程序加载、缺页处理、用户程序结束的多个函数中添加一系列if块构成。这些if块的判断条件均为全局变量workmode的值,当VMM工作在翻译模式下,workmode值为2,翻译控制例程激活,内核在用户程序加载,处理缺页,用户程序结束等阶段将引入翻译控制例程代码。翻译控制例程实现方式如下:

3.2.1在内核文件fs/exec.c中的do_execve()函数中添加翻译控制例程代码,由翻译控制例程代码判断当前操作系统的执行模式,若当前workmode值为1,则设置workmode为2,打开后续翻译控制例程入口。

3.2.2在内核文件fs/binfmt_elf.c中load_elf_binary()函数中添加如下翻译控制例程代码。

1)在调用函数elf_check_arch()对当前可执行文件的指令集进行检查处添加翻译控制例程代码,判断可执行文件的指令集是否为目标指令集,若是则将workmode值置为1,不启动后续翻译控制例程代码,按正常模式执行。否则跳过该指令集检查,按翻译模式执行。

2)在调用函数elf_mmap()将可执行文件映射到虚存处添加翻译控制例程代码,将代码Cache已翻译区挂载到用户进程,以便用户程序可以执行存放在代码Cache中的已翻译代码。

3)在调用start_thread()函数设置程序返回点处添加翻译控制例程代码。若当前workmode值为2,则将原始程序代码段和数据段加载到的虚存空间的起始和终止地址分别记录到对应的环境变量中。

3.2.3在缺页中断处理例程前端,内核文件fault.c的do_page_fault()函数中添加如下翻译控制例程代码。

1)在调用handle_mm_fault()函数之前加入翻译控制例程代码,若当前workmode值为2且缺页发生在原始程序代码段,则将该缺页地址记录到对应环境变量中。

2)在do_page_fault()函数返回前加入翻译控制例程代码,若当前workmode值为2且缺页发生在原始程序代码段,则将返回后的PC值reg.PC设置为已翻译页面上的入口地址。该地址保存在全局变量xaddr中。

3.2.4在缺页中断处理例程后端,内核文件mm/memory.c的do_fault()中添加如下翻译控制例程代码。

a)调用vmf.fault()函数,获取缺页中断页面处添加翻译控制例程代码。若当前workmode值为2,且该页地址位于原始程序代码段,则向协处理器发送翻译请求,并将缺页中断发生的地址一并发送给协处理器,然后等待翻译结果产生。

b)在a)中所述翻译控制例程代码后添加翻译控制例程代码,若当前workmode值为2且页地址位于原始程序代码段,则将接收到的响应消息包含的交换地址记录到对应的环境变量xaddr中,并直接返回上层函数,不填操作系统页表。

3.2.5在内核文件fs/exit.c的do_exit()函数中添加翻译控制例程代码。若当前workmode值为2,则设置workmode值为1。

3.3实现模式切换模块

模式切换模块为一内核模块。通过挂载/卸载模式切换模块,修改全局变量workmode的值为1/0,即可完成内核工作模式的切换。模式切换模块的实现方法如下:

3.3.1建立文件MChange.c。

3.3.2在文件MChange.c中加入内核模块的加载和卸载入口函数init_module()和卸载函数clean_module()。

3.3.3在init_module()函数中添加代码,将workmode值置为1,在clean_module()函数中添加代码,将workmode值置为0。

3.4在实现了修改的全局变量表,翻译控制例程和模式切换模块后,编译修改后的linux内核及模式切换模块,得到VMM。

第四步,整合软硬件构建翻译系统。将VMM安装到主处理器,将翻译软件安装到协处理器。启动主处理器和协处理器。至此,软硬结合的多处理器动态二进制翻译系统构建完毕。

第五步,使用该软硬结合的多处理器动态二进制翻译系统翻译执行用户程序。具体流程如下:

5.1将已在源体系结构处理器上编译的用户程序拷贝到文件系统下。

5.2挂载模式切换模块,将VMM切换到翻译模式。

5.3运行用户程序。

5.4软硬结合的多处理器动态二进制翻译系统采用以下步骤翻译执行用户程序:

5.4.1用户程序加载。当用户程序刚开始运行,产生“execve”系统调用进入内核时,VMM开始执行初始化工作。位于函数load_elf_binary()中的翻译控制例程保证程序通过指令集检查,挂载代码Cache已翻译区,同时记录用户程序代码段加载的位置,随后设置返回用户态后的PC值为用户程序代码段入口地址,返回用户态。

5.4.2产生翻译请求。当主处理器从原始程序代码段入口取第一条指令时,由于当前页面不在内存,产生缺页中断再次进入内核,VMM开始处理翻译任务。

5.4.3发送翻译请求。由于发生缺页的位置位于原始程序代码段,VMM中的翻译控制例程将截获该缺页中断,获取缺页地址,并将缺页地址发送给协处理器进行翻译。

5.4.4等待响应消息。主处理器等待在do_fault()函数中,直到获得来自协处理器的响应消息为止。

5.4.5翻译软件接收到翻译请求,查分支目标映射表确定该缺页地址处指令是否已翻译,若无需翻译则直接根据查表结果发送响应消息,若需要翻译则启动翻译任务。

5.4.6翻译软件启动翻译任务,首先查代码Cache管理表确定已翻译代码写入的位置,若代码Cache满则根据LRU值进行页面替换,然后开始从缺页地址处翻译用户程序页面,并在翻译过程中不断更新分支目标映射表,直至产生第一个已翻译页面为止。

5.4.7发送响应消息。产生第一个已翻译页面后,翻译软件将缺页地址对应的已翻译的分支目标地址发送给VMM。

5.4.8翻译软件发送完响应消息后,若用户程序页面还有未翻译完的代码,则继续翻译直至完成。

5.4.9翻译完用户页面后,翻译软件等待新的翻译请求产生。

5.4.10VMM接收到响应消息后,位于此处的翻译控制例程将响应消息中的地址保存在全局变量xaddr中,然后直接让缺页处理例程返回上层函数do_page_fault(),不填页表。

5.4.11链接已翻译页面。在函数do_page_fault()返回之前,翻译控制例程将regs.PC,即返回用户态后的用户程序入口点设置为xaddr的值,然后返回用户态。主处理器从代码Cache已翻译区的已翻译页面开始执行。主处理器执行已翻译代码过程中若遇到未翻译的分支目标地址,将跳回用户程序代码段,再次产生缺页中断,从而产生新的翻译请求。

5.4.12用户程序执行结束,VMM位于exit()函数中的翻译控制例程将workmode置为1,关闭前面一系列翻译控制例程入口。

至此,用户程序在该软硬结合的多处理器动态二进制翻译系统上翻译执行的过程结束。

采用本发明可以达到以下技术效果

1.该方法引入协处理器和翻译程序协助翻译,能够使翻译过程和执行过程在两个不同的处理器上并行,使程序高效翻译执行。

2.在该方法中,传统动态二进制翻译系统的翻译模块和执行模块被抽取出来,作为可以独立运行的翻译软件和VMM,分别运行在协处理器和主处理器上,并可以独立更新,使翻译系统具有更大的灵活性和可扩展性。

3.在该方法中,通过修改linux内核实现支持“一核翻译,一核执行”的VMM,以较低的开销完成用户程序加载,翻译请求产生和发送,响应消息接收,已翻译代码链接和用户程序退出扫尾等工作。且隐藏了部分传统动态二进制翻译系统中由于在二进制翻译系统与用户程序间频繁切换现场带来的开销。

4.该方法通过一系列措施,如翻译软件维护分支目标地址映射表,VMM接收响应消息后不填页表等措施,保证了程序翻译执行过程的正确性。

5.采用该方法搭建的动态二进制翻译器对用户完全透明,用户在挂载模式切换模块后,就可以像运行无需翻译的程序一样在主处理器上执行待翻译程序,十分方便。

附图说明

图1为传统动态二进制翻译方法流程图;

图2为传统动态二进制翻译系统工作原理图;

图3为本发明总体流程图;

图4为本发明第一步中采用总线方式连接的硬件平台结构图;

图5为本发明第一步中采用全局共享存储方式连接的硬件平台结构图;

图6为本发明第二步设计的翻译软件流程图;

图7为本发明第三步中基于linux内核实现VMM流程图;

图8为本发明第五步所述方法进行一次翻译执行的流程图;

图9为以本发明所述方法构建动态二进制翻译系统的工作原理图。

具体实施方式

图3为本发明总体流程图;本发明包括以下步骤:

第一步,选择两个或两个以上的处理器并搭建硬件平台;

第二步,结合协处理器的总线宽度、访存协议、地址空间大小设计翻译软件;

第三步,实现动态二进制翻译VMM;

第四步,整合软硬件构建翻译系统;

第五步,使用该软硬结合的多处理器动态二进制翻译系统翻译执行用户程序。

图4为本发明第一步中采用总线方式连接的硬件平台结构图;采用总线方式连接的硬件平台的搭建方法是:

1.1选择通信接口。可以选择GPIO(General Purpose IO),PCI等常用的通信接口作为主处理器和协处理器间交互的通信接口。

1.2定制通信总线。根据总线两端的通信接口定制通信总线。

1.3用通信总线连接主处理器和协处理器。

1.4安装通信接口驱动程序。

图5为本发明第一步中采用全局共享存储方式连接的硬件平台结构图;

采用共享存储方式连接的硬件平台的搭建方法只需将主处理器和协处理器与全局共享存储器的两个访问端口连接即可。

图6为本发明第二步设计的翻译软件流程图

翻译软件工作流程如下:

2.1初始化阶段。翻译软件启动后,初始化基本块入口地址映射表和代码cache管理表,将其中各个字段设为0。进入空闲状态,等待来自主处理器的翻译请求。

2.2接收翻译请求和确定是否需要启动翻译任务。接收到翻译请求后,在分支目标地址映射表中查询发生缺页的页地址,若不存在对应记录,则说明该地址未翻译,转2.3。若存在对应记录则不需要启动翻译任务,直接将对应的分支目标地址发送给主处理器,转2.4。

2.3翻译用户程序页面。翻译软件新建一个翻译任务,查代码Cache管理表找到一个空页面,并在其相应记录中的有效位置为1,更新LRU值,然后开始翻译用户程序页面,并将生成的已翻译代码存放到该空页面中。每翻译到一个分支目标地址,翻译软件在分支目标地址映射表中添加一项,并将翻译后的对应地址填入表中。当页面满时,翻译软件暂停翻译动作。

2.4发送响应消息。翻译软件将包含缺页地址的对应地址的已翻译页面(即主处理器马上要执行的页面)地址发送给主处理器上运行的VMM。

2.5继续翻译用户程序。翻译软件继续翻译用户程序页面剩下的代码,直至翻译完毕。

2.6若当前没有新的翻译任务,则等待主处理器的翻译请求。

图7为本发明第三步中基于linux内核实现VMM流程图;

其具体实现方法如下:

3.1实现全局变量表。

3.2实现翻译控制例程

3.3实现模式切换模块

3.4编译内核和模式切换模块,实现动态二进制翻译VMM。

第五步,使用该软硬结合的多处理器动态二进制翻译系统翻译执行用户程序。具体流程如下:

5.1将已在源体系结构处理器上编译的用户程序拷贝到文件系统下。

5.2挂载模式切换模块,将VMM切换到翻译模式。

5.3运行用户程序。

图8为本发明第五步中所述的动态二进制翻译系统对用户程序翻译执行流程图。其具体流程如下:

5.4.1用户程序加载。当用户程序刚开始运行,产生“exeeve”系统调用陷入内核时,VMM开始执行前初始化工作。位于函数load_elf_binary()中的翻译控制例程保证程序通过指令集检查,挂载代码Cache已翻译区,同时记录用户程序代码段加载的位置,随后设置返回用户态后的PC值为用户程序代码段入口地址,返回用户态。

5.4.2产生翻译请求。当主处理器从原始程序代码段入口取第一条指令时,由于当前页面不在内存,产生缺页中断再次陷入内核,VMM开始处理翻译任务。

5.4.3发送翻译请求。由于发生缺页的位置位于原始程序代码段,VMM中的翻译控制例程将截获该缺页中断,获取缺页地址,并将缺页地址发送给协处理器进行翻译。

5.4.4等待响应消息。主处理器等待在do_fault()函数中,直到获得来自协处理器的响应消息为止。

5.4.5接收翻译请求。翻译软件接收到翻译请求,查分支目标映射表确定该缺页地址处指令是否已翻译,若无需翻译则直接根据查表结果发送响应消息,若需要翻译则启动翻译任务。

5.4.6启动翻译任务。翻译软件启动翻译任务,首先查代码Cache管理表确定已翻译代码写入的位置,若代码Cache满则根据LRU值进行页面替换,然后开始从缺页地址处翻译用户程序页面,并在翻译过程中不断更新分支目标映射表,直至产生第一个已翻译页面为止。

5.4.7发送响应消息。产生第一个已翻译页面后,翻译软件将缺页地址对应的已翻译的分支目标地址发送给VMM。

5.4.8继续翻译。翻译软件发送完响应消息后,若用户程序页面还有未翻译完的代码,则继续翻译直至完成。

5.4.9翻译完用户页面后,翻译软件等待新的翻译请求产生。

5.4.10接收响应消息。VMM接收到响应消息后,位于此处的翻译控制例程将响应消息中的地址保存在全局变量xaddr中,然后直接让缺页处理例程返回上层函数do_page_fault(),不填页表。

5.4.11链接已翻译页面。在函数do_page_fault()返回之前,翻译控制例程将regs.PC,即返回用户态后的用户程序入口点设置为xaddr的值,然后返回用户态。主处理器从代码Cache已翻译区的已翻译页面开始执行。主处理器执行已翻译代码过程中若遇到未翻译的分支目标地址,将跳回用户程序代码段,再次产生缺页中断,从而产生新的翻译请求。

5.4.12执行结束。用户程序执行结束,VMM位于exit()函数中的翻译控制例程将workmode置为1,关闭前面一系列翻译控制例程入口。

图9为采用本发明所述方法实现的动态二进制翻译系统中主处理器与协处理器并行工作示意图。其中圆角框标示的步骤为可以并行的步骤。

主处理器按以下流程工作:

(1)主处理器开始执行用户程序。

(2)遇到未翻译指令,产生翻译请求。

(3)向协处理器发送翻译请求,等待。

(4)接收翻译结果,链接已翻译页面。

协处理器按以下流程工作:

(1)无翻译任务时,处于空闲状态。

(2)接收到翻译请求,新建翻译任务。

(3)启动翻译,结果存放到代码cache。

(4)产生已翻译页面后发送给主处理器。

(5)继续翻译直至完成翻译任务。

其中,主处理器在执行用户程序和链接已翻译页面时(第1、4步)时,协处理器可以同时继续翻译后续用户程序(第5步),即实现了在执行已翻译代码同时可以继续翻译用户页面。

去获取专利,查看全文>

相似文献

  • 专利
  • 中文文献
  • 外文文献
获取专利

客服邮箱:kefu@zhangqiaokeyan.com

京公网安备:11010802029741号 ICP备案号:京ICP备15016152号-6 六维联合信息科技 (北京) 有限公司©版权所有
  • 客服微信

  • 服务号