dalvik是android中使用的虚拟机,基于寄存器,分析基于android4.2源代码。本篇主要分析的是dalvik中的解释器部分,源码位于/dalvik/vm,主要代码在interp和mterp文件夹下。

我们知道java能运行在各个平台在于它运行在虚拟机上,由虚拟机来与各个硬件平台打交道(所以说"跨平台"都是假的啰(⊙▽⊙))。则虚拟机中解释器(将字节码解释成机器码)代码必然是依赖于各平台的,且为了方便管理必定是可配置式模块化。怎么理解呢     ◔ ‸◔?  直接在android中进行分析。

.. 21-Nov-2012 4 KiB
  arm-vfp/ 21-Nov-2012 4 KiB
  armv5te/ 21-Nov-2012 12 KiB
  armv6/ 21-Nov-2012 4 KiB
  armv6t2/ 21-Nov-2012 4 KiB
  armv7-a/ 21-Nov-2012 4 KiB
  c/ 21-Nov-2012 12 KiB
  common/ 21-Nov-2012 4 KiB
  config-allstubs 21-Nov-2012 1.4 KiB
  config-armv5te 21-Nov-2012 1.6 KiB
  config-armv5te-vfp 21-Nov-2012 3.2 KiB
  config-armv7-a 21-Nov-2012 5.2 KiB
  config-armv7-a-neon 21-Nov-2012 5.1 KiB
  config-mips 21-Nov-2012 1.7 KiB
  config-portable 21-Nov-2012 1.1 KiB
  config-x86 21-Nov-2012 1.7 KiB
  cstubs/ 21-Nov-2012 4 KiB
  gen-mterp.py 21-Nov-2012 19.9 KiB
  Makefile-mterp 21-Nov-2012 1.8 KiB
  mips/ 21-Nov-2012 20 KiB
  Mterp.cpp 21-Nov-2012 3 KiB
  Mterp.h 21-Nov-2012 1.3 KiB
  NOTES.txt 21-Nov-2012 3.2 KiB
  out/ 21-Nov-2012 4 KiB
  portable/ 21-Nov-2012 4 KiB
  README.txt 21-Nov-2012 13 KiB
  rebuild.sh 21-Nov-2012 1.1 KiB
  x86/

上面是mtero目录下代码分布,主要分析out/、gen-mterp.py、configxxx。先来看下gen-mterp.py是干什么吃的,我们知道要根据硬件平台来写解释器,当然解释器最好是能根据配置自动生成啰。

所谓模块化代码生成方法,就是说将解释器的实现划分成若干个模块,每一个模块都对应有一系列的输入文件(本身也是源代码文件),最后通过工具(一个Python脚本)将这些输入文件组装起来形成一个C语言文件或者汇编语言文件。这个最终得到的C语言文件或者汇编语言文件就是Dalvik虚拟机的解释器的实现文件。有了这种模块化代码生成方法之后,为某一个特定的平台生成优化过的解释器就是相当容易的:我们只需要为该平台的Dalvik虚拟机解释器的相关模块提供一个特殊版本的输入文件即可。也就是说,我们需要为每一个支持的平台提供一个配置文件,该配置文件描述了该平台的Dalvik虚拟机解释器的各个模块所要使用的输入文件。这种模块化代码生成方法不仅能避免手动编写解释器容易出错的问题,还能方便快速地将Dalvik虚拟机从一个平台移植到另外一个平台。
     --by 老罗

ok,既然这个gen-mterp.py能帮我们自动生成解释器。那我们就去一探究竟吧~( ̄▽ ̄~)(~ ̄▽ ̄)~

<span style="font-size:18px;"># ===========================================================================
# "main" code
# Check args.
if len(sys.argv) != 3:
print "Usage: %s target-arch output-dir" % sys.argv[0]
sys.exit(2)
# target-arch要生成的模式:portable fast
target_arch = sys.argv[1]
# output-dir输出目录
output_dir = sys.argv[2]
# Extract opcode list.
# 提取dexopcode列表
opcodes = getOpcodeList()
# Open config file.
# 打开配置文件sys.ary[1]
......
# Open and prepare output files.
# 打开输出文件sys.ary[2]/InterpC-sys.ary[1].cpp sys.ary[2]/InterpC-sys.ary[1].s
try:
c_fp = open("%s/InterpC-%s.cpp" % (output_dir, target_arch), "w")
asm_fp = open("%s/InterpAsm-%s.S" % (output_dir, target_arch), "w")
except:
print "Unable to open output files"
print "Make sure directory '%s' exists and existing files are writable" \
% output_dir
# Ideally we'd remove the files to avoid confusing "make", but if they
# failed to open we probably won't be able to remove them either.
sys.exit(1)
......
file_header = """/*
* This file was generated automatically by gen-mterp.py for '%s'.
*
* --> DO NOT EDIT <--
*/""" % (target_arch)
c_fp.write(file_header)
asm_fp.write(file_header)</span>

上面这么一大段代码究竟是干什么的呢,其实就做了2件事:

1 在out文件夹下创建arch对应的cpp和asm解释器代码(以InterpC-armv7-a为例(以下涉及到config不再重复),会在out下创建InterpC-armv7-a.cpp和InterpAsm-armv7-a.S;看到最后的一大串字符了,你打开out下每个文件都包含);

2 打开对应的arch配置(就是上面的一大段config-xxx文本),后面的代码就是解析这个配置文件;

3 打开/dalvik/libdex/DexOpcodes.h 头文件,将 DEFINE_GOTO_TABLE(指令字符串)提取组成键值对(根据指令字符可到序列号)中,这个在后面构成汇编解释器时会用到

再来看gen-mterp.py下相关的代码

# Process the config file.
# 处理配置文件
failed = False
try:
# 逐行读取配置文件内容
for line in config_fp:
line = line.strip() # remove CRLF, leading spaces
tokens = line.split(' ') # tokenize
#print "%d: %s" % (len(tokens), tokens)
if len(tokens[0]) == 0:
#print " blank"
pass
elif tokens[0][0] == '#':
#print " comment"
pass
else:
# 不分析空行和注释行,解析代码行
if tokens[0] == "handler-size":
# Set handler_size_bytes,二进制位数
setHandlerSize(tokens)
elif tokens[0] == "import":
# 将import文件copy到输出文本:c_fp或asm_fp
importFile(tokens)
elif tokens[0] == "asm-stub":
# copy asm-stub文本到asm-stub-txt
setAsmStub(tokens)
elif tokens[0] == "asm-alt-stub":
# Record location of default alt stub
setAsmAltStub(tokens)
elif tokens[0] == "op-start":
# in_op_start = 1 且设置default_op_dir = op-start
opStart(tokens)
......
elif tokens[0] == "op":
# 设置opcode指令的文件地址 组成键值对
opEntry(tokens)
elif tokens[0] == "handler-style":
# Set interpreter style
setHandlerStyle(tokens)
......

上面的for ...in...语句就是在逐行解析config文本,我们只挑选重要解释:

handler-style:设置解释器的类型

handler-size:提到这个是因为在它需要跟 handler-style相关联,必须先设置style的值,这就关系到config文本的编写:

handler-style computed-goto

handler-size 64                                             先handler-style后handler-size

import:直接将import的cpp和s文本写入到InterpC-armv7-a.cpp(对于cpp来说这就是全部的工作)和InterpAsm-armv7-a.S

op-start:开始填写指令解释符,主要是设置in_op_start
= 1,供下面OP 判断状态使用

op:根据文本设置对应的opcode_locations值:op OP_ADD_DOUBLE_2ADDR armv6t2-->opcode_locations[OP_ADD_DOUBLE_2ADDR]
= armv6t2 ,存储的是opcode的解释代码的文件目录,不理解看下面

op-end:首先opcodes[index]去除opcode,然后opcode_locations[opcode]得到opcode的解释代码的文件目录Dstr,最后利用Dstr/opcode.s得到具体opcode解释代码的asm文本并将其写入InterpAsm-armv7-a.S。

对于op-start,op,op-end举例说明:op OP_MOVE armv6t2——>op指令解析“op_mov”指令文件夹为"armv6t2",构成对应的指令解释文本为armv6t2/op_mov.s

 最后提几点:

 本篇讲解的是dalvik解释器部分,而解释器的工作是把java代码翻译机器码。在dalvik虚拟机中执行函数由CallStaticVoidMethod来执行,但最终是通过dvmCallMethodV(请重点关注它,很重要哎;xposed框架就是基于此来实现的):

void dvmCallMethodV(Thread* self, const Method* method, Object* obj,
bool fromJni, JValue* pResult, va_list args)
{
...... if (dvmIsNativeMethod(method)) {
TRACE_METHOD_ENTER(self, method);
/*
* Because we leave no space for local variables, "curFrame" points
* directly at the method arguments.
*/
(*method->nativeFunc)(self->curFrame, pResult, method, self);
TRACE_METHOD_EXIT(self, method);
} else {
dvmInterpret(self, method, pResult);
} ......
}
 看上面红色代码,先判断method是否为native,是则执行其curFrame(其实是native code);否则去执行dvmInterpret。dvmInterpret是解释器入口,在interp.cpp文件中,会根据指令来调用上面编译生成的解释代码。

参考资料:

1 生成dalvik解释器原文件的脚本:gen-mterp.py

2老罗android之旅

版权声明:本文为博主原创文章,未经博主允许不得转载。

android dalvik浅析一:解释器及其执行的更多相关文章

  1. dalvik浅析三:类加载

    android的安装包是个apk文件,其中包含dex.资源及签名文件.其中dex是包含程序运行的类代码,而android是运行在dalvik(5.0之前)上的.本篇我们就来看下dalvik是如何把de ...

  2. Android逆向基础----Android Dalvik虚拟机

    Android Dalvik虚拟机的特点: l  体积小,占用内存空间小. l  专有DEX可执行文件. l  常量池采用32位索引值,寻址类方法名,字段名,常量更快. l  基于寄存器架构,并拥有一 ...

  3. Android Dalvik虚拟机

    虽然Android平台使用Java来开发应用程序,但Android程序却不是运行在标准Java虚拟机上的. 可能是出于效率和版权的考虑,Google为Android专门设计了一套虚拟机Dalvik V ...

  4. dalvik浅析二:jni、so

    android大多使用java来开发,java中有个概念叫jni.当然说到jni,必然是少不了native code.在android中就是so库.我们来分析下jni在android dalvik的使 ...

  5. [Android]Dalvik的BOOTCLASSPATH和dexopt流程

    BOOTCLASSPATH简介1.BOOTCLASSPATH是Android Linux的一个环境变量,可以在adb shell下用$BOOTCLASSPATH看到.2.BOOTCLASSPATH于/ ...

  6. [转帖]浅析java程序的执行过程

    浅析java程序的执行过程 转帖来源: https://www.cnblogs.com/wangjiming/p/10315983.html 之前学习过 这一块东西 但是感觉理解的不深刻. copy一 ...

  7. Android 设备,如何root,执行adb shell,查看设备中的数据库信息等【转】

    原文地址: Android 设备,如何root,执行adb shell,查看设备中的数据库信息等

  8. Android P(9.0) userdebug版本执行adb remount失败

    [DESCRIPTION]      在android P版本上如果按照“FAQ18076 android 6.0 M userdebug版本执行adb remount失败”的做法在userdebug ...

  9. 使用Android的硬件缩放技术优化执行效率

    Unity3D研究院之使用Android的硬件缩放技术优化执行效率 http://www.xuanyusong.com/archives/3205 Android中GLSurfaceView在横竖屏切 ...

随机推荐

  1. 关于python中的[::-1],[:,:,::-1]的反转理解

    其实就是单纯的关于反转,我们只需要记住每一个列表的中间有两个冒号: 即[a: b:c],意思是从a到b,间隔是c,因为经常省略c,所以经常看到[a:b]. 一.在一维数据中的反转 import num ...

  2. 靶场练习-Sqli-labs通关记录(1-4关)

                              0x00 实验环境 本地:Win 10 靶场:sqli-labs(共65关,每日一关) 0x02 通关记录 简介:一天一关! (1)第一关: 简单的 ...

  3. 如何安装jenkins并简单的使用

    如何安装jenkins并使用 一.jenkins 简介: Jenkins是基于Java开发的一种持续集成工具,用于监控持续重复的工作,功能包括 : 1.持续的软件版本发布/测试项目: 2.监控外部调用 ...

  4. uni-app(二)接口请求封装,全局输出api

    在项目 main.js 同级创建 utils 文件夹, utils里创建 config.js文件,存储重要参数 // 获取平台信息 const { system, } = uni.getSystemI ...

  5. Redis的常用淘汰策略以及算法实现

    一.Redis的内存配置 1,Redis配置内存为多少合适? 默认:如果不设置最大内存大小或者设置最大内存大小为0,在64为操作系统下不限制内存大小,在32位操作系统下最多使用3GB内存. 极限情况: ...

  6. 攻防世界 reverse hackme

    hackme XCTF 3rd-GCTF-2017 __int64 __fastcall sub_400F8E(__int64 a1, __int64 a2) { char input[136]; / ...

  7. Jmeter(四十) - 从入门到精通进阶篇 - Jmeter配置文件的刨根问底 - 中篇(详解教程)

    1.简介 为什么宏哥要对Jmeter的配置文件进行一下讲解了,因为有的童鞋或者小伙伴在测试中遇到一些需要修改配置文件的问题不是很清楚也不是很懂,就算修改了也是模模糊糊的.更有甚者觉得那是禁地神圣不可轻 ...

  8. Java 并发编程 Executor 框架

    本文部分摘自<Java 并发编程的艺术> Excutor 框架 1. 两级调度模型 在 HotSpot VM 的线程模型中,Java 线程被一对一映射为本地操作系统线程.在上层,Java ...

  9. JS实现鼠标点击爱心&绘制多边形&每日一言功能

    本篇文章主要介绍我的个人博客 程序猿刘川枫 中页面使用的美化功能(基于JS实现): 1.鼠标点击出现不同颜色爱心特效 2.页面浮动多边形跟随鼠标移动 3.每日一言功能 1.鼠标点击出现爱心特效 经常在 ...

  10. maven 打包和构建的Linux命令(mvn)

    maven 打包构建相关命令 命令 mvn clean package 依次执行clean.resources.compile.testResources.testCompile.test.jar(打 ...