doi:10.3772/j.issn.1002-0470.2021.01.004
MIPS安卓平台上ARM二进制翻译系统①
赵保华②……杯安宁饪③*…**徐哲冲**杜安利**苏涛“
「北京工业大学信息学部北京100124)
("全球能源互联网研究院有限公司北京102209)
(”"电力系统人工智能(联研院)国家电网公司联合实验室北京102209)
(**“龙芯中科技术有限公司北京100095)
摘要无内部互锁流水级的微处理器(MIPS)是重要的处理器架构,安卓是目前主流的移动终端操作系统。在MIPS架构处理器上运行安卓操作系统可以有效拓展使用领域,但存在的问题是调用高级精简指令集处理器(ARM)架构本地库的安卓应用程序不能运行,即存在应用不兼容问题。本文提出了一种动态库跨平台二进制兼容模型,以及通用的跨平台二进制翻译系统的架构,并在MIPS安卓平台上设计实现了ARM二进制翻译系统。该系统能够进行ARM动态库的跨平台加载,并采用动态二进制翻译,将ARM动态库中的二进制指令翻译成为MIPS架构的二进制指令,从而能够在MIPS架构处理器上执行。实验结果表明,
该系统可以运行调用ARM本地库的安卓应用程序,解决了MIPS平台安卓应用的兼容性问题。本文工作对跨平台二进制翻译系统的研究具有重要参考价值。
关键词二进制翻译;无内部互锁流水级的微处理器(MIPS);高级精简指令集处理器(ARM);Android
0引言
无内部互锁流水级的微处理器(microprocessor without interlocked piped stages,MIPS)架构是1981年由斯坦福大学开发的简洁、具有高度可拓展性的精简指令集计算机(reduced instruction set computer, RISC)架构,MIPS公司的R系列处理器就是在这个架构的基础上研制岀来的微处理器。MIPS架构处理器被广泛应用于游戏机、机顶盒、网络路由器,以及其他嵌入式设备和通设备中。我国自主研制的龙芯CPU基于开放授权的MIPS架构,并在此基础上扩展形成了自己的指令架构。目前,龙芯CPU已经广泛地应用于办公、卫星导航、信息安全等关键领域。
目前安卓(Android)操作系统是移动终端上的主流操作系统。安卓应用是采用谷歌公司的软件开发工具包安卓SDK(standard development kit)和NDK(native development kit)开发的⑷。仅使用SDK开发的应用可以凭借Java语言的通用性在所有安卓虚拟机支持的架构(目前包括ARM.X86和MIPS)上正常运行。然而使用NDK开发的安卓应用会在程序包中生成动态共享库文件,这种文件包含有与相应体系结构相对应的机器代码片段,由安卓虚拟机通过Java本地接口JNI(Java native inter-face)调用⑸,只能
在相应架构的硬件设备上运行。由于采用高级精简指令集处理器(advanced RISC machine,ARM)架构处理器在移动设备市场上垄断性的地位,大部分采用NDK开发的应用只支持
国家自然科学基金(61521092)和国家电网有限公司总部科技(SGGR0000JSJS18002031)资助项目。
男,1984年生,博士生;研究方向:计算机科学与技术;E-mail;*****************
通信作者,E-mail:anningyu@geiri.sgcc
(收稿日期:2019-12-ll)
—31
ARM架构,导致了兼容性问题。
二进制翻译是解决不同指令系统兼容的重要技术3]。二进制翻译技术通过在宿主机上用软件模拟出一个目标机指令系统兼容的CPU,从而在宿主机上执行客户机的二进制代码,达到兼容的目的。如在MIPS计算机上模拟ARM指令系统,从而实现ARM兼容。但是二进制翻译存在较严重的效率问题,用软件模拟的CPU比硬件直接实现的CPU慢很多。如在MIPS计算机上使用二进制翻译的方法运行ARM程序,比起把该程序直接从源代码编译成MIPS指令并在MIPS计算机上执行,运行速度一般有数量级的差异。
本文针对安卓应用程序在MIPS平台上不兼容的原因,设计了二进制翻译系统来解决安卓应用程序在MIPS平台上的不兼容问题。设计的二进制翻译系统实现了动态库的跨平台加载,并采用动态二进制翻译技术,将ARM动态库中的二进制指令翻译成为MIPS架构的二进制指令,从而解决安卓应用的兼容性问题。
1相关工作
libhoudini⑼是由美国Intel公司开发的项目,用于在基于X86处理器平台的安卓系统上支持ARM 的二进制运行,解决安卓应用程序的兼容性问题。libhoudini把ARM的二进制代码动态翻译成X86处理器平台上的可执行代码。
Qemu IOJ是由Fabrice Bellard开发的开源的纯软件虚拟化模拟器,几乎可以模拟任何硬件设备。Qemu主要是提取源体系结构代码,然后将其翻译成可信计算组织(trusted computing group,TCG)中间代码,然后将TCG中间代码翻译成目标体系结构代码。它支持X86、ARM、MIPS、SPARC和Power PC 等架构。
DigitalBridge是中国科学院计算所开发的一个固定源和固定目标的二进制翻译器"⑵,能将X86程序运行在MIPS平台上,支持Adobe ReaderFirefox^MySQL^Apache等应用程序。DigitalBridge在动态翻译过程中,先不计算标志寄存器的结果,使用延—32—迟技术,然后在下一阶段收集程序运行的信息。
根据这一信息对前一阶段生成的代码进行在热路径的优化,这个优化主要是在热路径上进行。这样系统可以首先迅速生成执行效率比较差的代码。在实际的优化过程中,要针对标志位计算进行优化,采用两种方式,针对基于模式的指令组合翻译优化和针对延迟标志位计算的优化。DigitalBridge虽然使用两种模式处理指令流,但仍需对只执行一次的代码生成基本块,生成基本块的操作开销比解释执行大问。
2MIPS安卓平台上ARM二进制翻译系统的设计
2.1动态库跨平台二进制兼容模型
安卓应用的开发工具包括安卓SDK和NDK。其中,SDK是安卓软件开发工具包,使用该工具包开发的应用程序采用Java语言,不存在兼容性问题。NDK是安卓本地开发工具包。采用NDK开发的应用程序可能调用了本地库,本地库代码是和某种架构对应的机器码。如果安装平台的架构和应用程序中调用的动态库不匹配,则无法正常执行,即出现不兼容。
由上述分析可知,造成MIPS平台上安卓应用程序不兼容的原因是使用了JNI函数的安卓应用程序中没有MIPS版本的动态库,导致程序运行过程中,加载动态共享库时出错。针对这一问题,本文提出了一种动态库跨平台二进制兼容模型,并根据该模型提出通用的翻译系统架构。
mysql下载选x86还是arm动态库跨平台二进制兼容模型所要解决的问题是要通过二进制兼容技术,使得动态链接库中的二进制代码段能够在不同体系结构的硬件平台上被正确加载、链接及执行。携带第三方动态库的程序由目标体系结构的主程序和源体系结构的动态库两部分组成,图1所示为该模型的结构图。该模型分为动态链接和代码执行阶段。在动态链接阶段,目标体系结构的主程序调用源体系结构的共享库时,通过定制的链接器将源体系结构的共享库进行动态链接加载;在程序执行阶段,目标体系结构的二进制代码直接运行在CPU上,而源体系结构的共享库代码
赵保华等:MIPS 安卓平台上ARM 二进制翻译系统
通过二进制翻译技术在目标体系结构CPU 上运行。
图1动态库跨平台二进制兼容模型
动态链接阶段
目标体系结构
二进制代码
源体系结构共享库
运行阶段
源-目标体系结构
二进制翻译
目标体系结构CPU
根据动态库跨平台二进制兼容模型,本文提出
通用的跨平台二进制代码翻译系统架构(如图2所
示),主要包含3个功能模块。
(1) 自定义动态链接器。由于目标体系结构平
台上的动态链接器在加载源体系结构平台动态库时
会出错,故要完成第三方动态库在目标体系结构平 台上的加载,就需要提供一个工作在目标体系结构
平台上的自定义动态链接器完成工作。主要完成符
号决议、重定位等链接工作。
(2) 二进制翻译器。在完成源体系结构平台动
态库在目标机上的动态加载链接工作后,根据调用
函数的名称得到跳转地址,但此时跳转到的二进制
代码是不同体系结构的代码,因此需要一个二进制
翻译器模块将源体系结构平台二进制指令翻译为目
标体系结构平台的二进制指令。
(3) 控制核心。在指令的执行过程中,需要对
指令处理的中间结果进行存储,并且维护虚拟CPU 的寄存器状态。另外,当所调用的函数为系统调用
时,需要将该系统调用转换成本地系统调用。
图2跨平台二进制代码翻译系统架构本文二进制翻译系统的目标体系结构平台是
MIPS,而程序所携带的动态库是源体系结构ARM
的动态库文件。在图2所示的跨平台二进制代码动
态翻译系统架构中,动态链接器主要用于在MIPS
二进制代码中链接ARM 共享库文件,二进制翻译
器主要用于将ARM 二进制代码翻译为MIPS 代码 来执行。下面具体介绍二进制翻译系统各模块的设
计。
2.2二进制翻译器的设计
二进制翻译器设计的依据是目标机器的指令集
架构,不同体系结构的指令集在指令架构、寻址方
式、内存访问形式上都有很大的不同。设计一个二 进制翻译器需要主要包含2个基本功能。
(1) 解释源平台二进制指令。根据源平台指令
的格式对二进制指令进行解析,分析出指令的操作
码、操作数、执行条件等信息。
(2) 在目标平台上执行源指令等价操作。根据
获得的指令信息将源指令转换成在目标平台上能够
执行的微操作或者目标代码,并执行生成的目标代 码实现源指令的等价操作。
本系统的动态二进制翻译模块整体结构如图3 所示,由系统控制核心、ARM 指令译码器、微码转换
器、编译器4部分组成。其中控制核心、ARM 指令
译码器、微码转换器是系统的运行时模块,编译器是
系统编译时依赖的编译工具,负责将解释器中的C
微码指令编译成目标平台的二进制代码。
图3二进制翻译器的流程图
二进制翻译模块运行时,源平台的所有资源都 通过CPU 基址加上特定的偏移量来访问。系统控
制核心首先会根据动态链接器对ARM 动态库的加
—
33
—
高技术通讯2021年1月第31卷第1期
载和分析,返回文件中所调动的子函数的入口位置,从而获得文件执行的代码段入口地址,并存放在程序计数器中。然后控制核心读取一条ARM二进制指令并传入ARM指令译码器,译码器按照ARM指令的格式和译码规则翻译为汇编指令,并将形成的汇编指令送入微码转换器。微码转换器会将接收到的汇编指令翻译成等价的C函数微码片段。运行时通过动态代码生成器把以上微操作组合成一个函数并执行,就相当于执行了一条源指令,通过执行这些指令流完成对源平台指令的等价执行。
2.3控制核心的设计
ARM二进制代码动态翻译系统需要一个控制核心来在运行时记录环境变量,该控制核心需要包含以下3个基本功能。
(1)系统初始化。系统初始化主要包括虚拟CPU寄存器的初始化,代码区和栈区的内存空间的分配以及其他系统参数的初始化。系统初始化过程中,由于不同体系结构下寄存器的名称、数量、位数及功能不相同,需要根据具体目标平台设置相应的系统初始化流程。
(2)运行时管理。运行时管理是对运行时的内存数据和目标机的虚拟CPU寄存器状态的管理。运行时管理模块包含线程共享的堆数据管理、线程独享的栈数据管理以及程序计数器的管理等,具体实现可根据虚拟内存的布局进行具体的管理。运行时的虚拟CPU管理主要是根据程序的执行情况更新虚拟CPU的寄存器状态,包括通用寄存器、段寄存器、标志位寄存器等。此外,运行时管理的一个重要工作是处理两种不同的架构之间代码相互调用,为此准备必要的胶合代码。
(3)系统调用的处理。劫持系统调用,并将源平台的系统调用转换成本地系统调用。常用的本地系统调用劫持的方法有:1)通过修改sys_call table中对应的内核函数地址进行系统调用劫持。2)对于特定的系统调用,通过修改vfs文件系统进行劫持。3)构造新的中断描述符替换原系统调用使用的中断号,并在新的中断处理函数中处理系统调用。但是,第三方动态库中的系统调用劫持和本地系统调用劫持不一样,实际上是将源平台系统调用转换到本地平台,比较简单的方法就是在进行第三方动态库中的系统调用过程中,将系统调用相关函数转化为本地系统调用,在调用时获取翻译系统此时的寄存器和内存状态,转化为MIPS进行系统调用的寄存器和内存状态。接着在MIPS中调用本地的系统调用,获取结果,并返回给翻译系统。
2.4动态链接器设计
动态链接器的流程图如图4所示。动态链接器包含链接器和加载器[⑷,但在实际的Linux系统中,任何一个链接器需要实现以下3个基本功能。
图4动态链接器的流程图
(1)程序加载。根据动态库的名称将程序从磁盘拷贝到主内存中,需要注意的是当程序加载异架构的动态库文件失败时,则用自己开发的二进制模块实现对动态库的装入和链接。共享库文件在内存加载的过程中根据ELF文件的段表对共享库文件的ELF头部(ELF Header)、PLT表、GOT表、字符串表(String Table)以及其他链接所需要的所有节区进行解析,同时记录过程中所需要的属性值。
(2)重定位。根据加载地址调整程序中的数据和代码以使程序的变量和函数地址指向实际逻辑地址。需要注意的是在对第三方动态库的重定位过程
—34
—
赵保华等:MIPS安卓平台上ARM二进制翻译系统
中对系统调用的处理。系统调用是用户程序与内核间的接口,内核函数可以驱动硬件设备,因为不同硬件设备的内核函数实现不同,所以需要将原系统调用进行捕获转移到目标机的系统调用上。
(3)符号解析。可执行文件和动态库文件间的变量和函数的相互引用是通过符号进行的,需要链接器解析符号来给引用符号分配在库中的地址,使得call指令时直接调用该地址。在共享库的符号解析过程中,实际是解析.dynsym节区中保存的动态符号表的过程。
3ARM二进制翻译系统的实现
3.1二进制翻译模块
二进制翻译模块主要负责第三方动态库的二进制代码翻译工作,基于二进制翻译技术的分析对比,本系统中二进制翻译模块基于开源项目Unicorn】”]进行开发,Unicorn基于动态翻译技术。使用Unicorn引擎的基本流程是:(1)初始化二进制翻译器,初始化一个64bit的ARM架构的模拟器;(2)映射二进制翻译器的虚拟地址,将代码区映射到0x10000、栈区映射到0x20000的内存空间;(3)把二进制数据写入二进制翻译器的虚拟地址;(4)初始化二进制翻译器的寄存器;(5)设置hook回调函数,其中hook_co
de就是一个回调函数,可以用来打印一些中间执行结果,由用户自己实现。Unicorn 的hook回调机制极大地方便了对指令的调试,通过hook机制查看当前的寄存器和栈区的数据;(6)执行指令。
在指令译码器设计方面,指令译码器所要执行的任务是将一条二进制指令翻译成其对应的汇编指令,也就是反汇编的过程。当获得一条二进制指令时,根据ARM指令集的指令格式,获取执行指令的操作码、操作数、条件码等信息。这一步骤的重点在于获取不同寻址方式下的操作数,通过分析指令字助记符和指令码,可以很方便地得到不同寻址方式的操作数。
在微码转换器设计方面,微码转换器根据指令译码器产生的指令操作码、操作数个数、寻址模式等信息,将汇编指令转换成对应功能的C语言中间代码,采用类似Qemu的微操作形式。例如,当遇到如下ARM指令:
Add r3r316#r3=r3+16
微码转换器将其分解为如下的微操作。
movl_T0_rl#TO=rl
addl_T0_im16#TO=TO+16
movl_rl_TO#rl=TO
随后在转换器中会出这3条指令的对应C 函数为
void op_movl_TO_rl(void){
TO=env->regs[1];}
void op_addl_TO__im(void){
TO=TO+((long)(&_op_paraml));}
void op_movl_rl_TO(void){
env->regs[1]=TO;j
而立即数16会被送入控制核心中保存立即数的堆栈中以备运行时使用。本系统对中间代码转换函数进行了简化,直接将C函数中的代码内联到微码转换环节,“Add r3r316”指令将被直接转换为如下微码。这些微码片段在编译二进制翻译模块源代码的时候就已经被编译成了MIPS平台的二进制代码。
TO=env->regs[1];
TO=TO+((long)(&_op_paraml));
env->regs[1]=TO;
3.2控制核心模块
控制核心中需要实现包括不同架构的函数互调用、处理系统调用、地址空间协调等功能。
不同架构有不同的应用程序二进制接口(application binary interface,ABI)o ABI是在二进制级别上定义的一套函数调用规范,涵盖诸如数据类型、大小、对齐方式、参数如何传递并返回值等。控制核心模块必须处理ARM ABI和MIPS ABI之间的差异。针对MIPS代码调用ARM本地库的情况,在龙芯安卓系统中,调用本地库是通过dvmPlatformlnvoke实现的。dvmPlatformlnvoke的功能是根据调用函数的签名来为该函数准备调用环境,从Java的运行数据里取出函数的参数,按C程序的要求准备好寄存器
—35—
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论