注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

时间记录器

记录我的Linux、Android学习之路

 
 
 

日志

 
 

Dalvik/vm/mterp目录下文件生成规则  

2012-12-25 19:49:20|  分类: Dalvik |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

下面以分析config-armv7-a-neon配置的文件为例分析。

  1. Instruction file format,指令文件格式,主要针对不同架构下的汇编文件,比如armv5te/unop.S文件等。

    几个替换宏:

    $opcode – 操作码名,形如 "OP_NOP"

    $opnum – 操作码数,比如0 代表 OP_NOP

    $handler_size_bytes – 指令句柄的最大字节数

    $handler_size_bits – 指令句柄的最大bit数,2次幂

2、%include "filename" [subst-dict]

    将include进来的文件替换当前行。你能指定替换字典的值,使用的是标准的python语法。例如:

%include "armv5te/unop.S" {"result":"r1"}

会将armv5te/unop.S替换本行,同时将unop.S中的$result替换为r1

3、%default <subst-dict>

指定的默认替换字典值,使用标准的python语法。当你想有一个基本版本和变种的时候很有用。

4、%break

    指令主体部分代码(必须适合"handler-size"的字节数)和姊妹代码(添加在指令handler块结尾处的代码)的分隔标记符

5、%verify "message"

    给自己留下的note,用来提醒自己哪些东西需要被测试。这里没什么作用。

6、一些常用宏在out/InterpAsm-armv7-a-neon.S文件下(源文件在架构文件夹下的header.S中)

/* single-purpose registers, given names for clarity */

#define rPC r17

#define rFP r18

#define rGLUE r19

#define rINST r20

#define rIBASE r21

 

/* save/restore the PC and/or FP from the glue struct */

#define LOAD_PC_FROM_GLUE() ldw rPC, [rGLUE+], #offGlue_pc

#define SAVE_PC_TO_GLUE() stw rPC, [rGLUE+], #offGlue_pc

#define LOAD_FP_FROM_GLUE() ldw rFP, [rGLUE+], #offGlue_fp

#define SAVE_FP_TO_GLUE() stw rFP, [rGLUE+], #offGlue_fp

#define LOAD_PC_FP_FROM_GLUE() ldm (rPC, rFP), [rGLUE]+

#define SAVE_PC_FP_TO_GLUE() stm (rPC, rFP), [rGLUE]+

#define FETCH_INST() ldh rINST, [rPC+]

#define FETCH_ADVANCE_INST(_count) ldh.w rINST, [rPC+], #(_count*2)

#define GOTO_OPCODE(_reg) add pc, rIBASE, _reg << #6

 

#define FETCH_INST() ldrh rINST, [rPC]

#define FETCH_ADVANCE_INST(_count) ldrh rINST, [rPC, #(_count*2)]!

#define PREFETCH_ADVANCE_INST(_dreg, _sreg, _count) ldrh _dreg, [_sreg, #(_count*2)]!

 

handler-size 64

 

Out目录下的InterpAsm-armv7-a-neon.S和InterpC-armv7-a-neon.c文件的生成:

$ cd mterp

$ ./rebuild.sh

执行mterp下的rebuild.sh脚本,该脚本的内容为:

1 set -e

2

3 for arch in portstd portdbg allstubs unicore armv4t armv5te armv5te-vfp armv7-a armv7-a-neon x86 x86-atom;

4 do TARGET_ARCH_EXT=$arch make -f Makefile-mterp;

5 done

6

7 echo Removing unneeded assembly source for portable interpreter

8 rm -f out/InterpAsm-portstd.S out/InterpAsm-portdbg.S

Line 3中for查看传入的arch是否支持;

Line 4,执行make -f Makefile-mterp这个makefile。Makefile-mterp的内容如下:

OUTPUT_DIR := out

SOURCE_DEPS := \

    $(shell find . -path ./$(OUTPUT_DIR) -prune -o -type f -print) \

    ../Android.mk ../../Android.mk

GEN_SOURCES := \

    $(OUTPUT_DIR)/InterpC-$(TARGET_ARCH_EXT).c \

    $(OUTPUT_DIR)/InterpAsm-$(TARGET_ARCH_EXT).S

target: $(GEN_SOURCES)

$(GEN_SOURCES): $(SOURCE_DEPS)

    @mkdir -p out

    ./gen-mterp.py $(TARGET_ARCH_EXT) $(OUTPUT_DIR)

其中的GEN_SOURCES表示输出的两个文件名;最后一行执行一个python脚本,展开后为:

./gen-mterp.py armv7-a-neon out

查看gen-mterp.py脚本:

interp_defs_file = "../../libdex/OpCode.h" # need opcode list

这行定义了opcode的列表文件,后面会使用到该文件中opcode数组的排列顺序。

label_prefix = ".L" # use ".L" to hide labels from gdb

这行定义了标签前缀,以.L开始的label标签将对gdb不可见。

def getOpcodeList():

opcodes = []

opcode_fp = open(interp_defs_file)

opcode_re = re.compile(r"^\s*H\(OP_(\w+)\),.*", re.DOTALL)

for line in opcode_fp:

match = opcode_re.match(line)

if not match:

continue

opcodes.append("OP_" + match.group(1))

opcode_fp.close()

 

if len(opcodes) != 256:

print "ERROR: found %d opcodes in Interp.h (expected 256)" \

% len(opcodes)

raise SyntaxError, "bad opcode count"

return opcodes

函数getOpcodeList()首先打开interp_defs_file指向的文件libdex/OpCode.h,然后通过一个for循环,去查找以正则表达式"^\s*H\(OP_(\w+)\),.*"匹配的行,下面是该正则表达式用到的语法:

^ 匹配输入字符串的开始位置

\s 匹配任何空白字符,包括空格、制表符、换页符等等。等价于[ \f\n\r\t\v]

* 匹配前面的子表达式零次或多次

H\(OP_(\w+)\),.* 匹配H(),括号里面的内容是OP_****型的,

\w 匹配包括下划线的任何单词字符,

+ 匹配前面的子表达式一次或多次。例如,"zo+"能匹配"zo"以及"zoo",但不能匹配"z"

所以,

opcode_re = re.compile(r"^\s*H\(OP_(\w+)\),.*", re.DOTALL)

会去匹配形如:

H(OP_MOVE),

H(OP_MOVE_FROM16),

H(OP_MOVE_16),

H(OP_MOVE_WIDE),

H(OP_MOVE_WIDE_FROM16),

这样的行。

最后,会返回opcodes数组。

下面是python脚本的入口:

#

# ===========================================================================

# "main" code

#

 

#

# Check args.

# 参数校验

if len(sys.argv) != 3:

print "Usage: %s target-arch output-dir" % sys.argv[0]

sys.exit(2)

 

target_arch = sys.argv[1] //第二个参数为目标架构,这里是armv7-a-neon

output_dir = sys.argv[2] //输出目录,这里是out

 

#

# Extract opcode list.

#

opcodes = getOpcodeList() //从libdex/opcode.h文件获取opcodeList

#for op in opcodes:

# print " %s" % op

 

#

# Open config file.

#

try:

config_fp = open("config-%s" % target_arch) //尝试打开配置文件config-armv7-a-neon

except:

print "Unable to open config file 'config-%s'" % target_arch

sys.exit(1)

 

#

# Open and prepare output files.

#

try: //以写入方式打开输出文件

c_fp = open("%s/InterpC-%s.c" % (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)

 

print "Generating %s, %s" % (c_fp.name, asm_fp.name)

 

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)

 

#

# 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":

setHandlerSize(tokens)

elif tokens[0] == "import":

importFile(tokens)

elif tokens[0] == "asm-stub":

setAsmStub(tokens)

elif tokens[0] == "op-start":

opStart(tokens)

elif tokens[0] == "op-end":

opEnd(tokens)

elif tokens[0] == "op":

opEntry(tokens)

else:

raise DataParseError, "unrecognized command '%s'" % tokens[0]

except DataParseError, err:

print "Failed: " + str(err)

# TODO: remove output files so "make" doesn't get confused

failed = True

c_fp.close()

asm_fp.close()

c_fp = asm_fp = None

 

config_fp.close()

所以,按照python文件描述的,最终生成的两个文件是以cong-*文件为模版来组织的。

这样,输出文件InterpAsm-armv7-a-neon.S的组成顺序大致是:

armv5te/header.S

armv7-a/platform.S

armv5te/entry.S

# opcode list

import armv5te/footer.S

 

 

 

 

 

 

.global dvmAsmInstructionStart

.type dvmAsmInstructionStart, %function

dvmAsmInstructionStart = .L_OP_NOP

.text

 

/* ------------------------------ */

.balign 64

.L_OP_NOP: /* 0x00 */

/* File: armv5te/OP_NOP.S */

FETCH_ADVANCE_INST(1) @ advance to next instr, load rINST

GET_INST_OPCODE(ip) @ ip<- opcode from rINST

GOTO_OPCODE(ip) @ execute it

 

#ifdef ASSIST_DEBUGGER

/* insert fake function header to help gdb find the stack frame */

.type dalvik_inst, %function

dalvik_inst:

.fnstart

MTERP_ENTRY1

MTERP_ENTRY2

.fnend

#endif

其中dvmAsmInstructionStart是汇编指令集的起始地址,后面的每一条指令都使用".balign 64"来自动64字节对其

 

 

在处理Dex文件时,会调用函数集合:dvm_dalvik_system_DexFile

dalvik_system_DexFile.c (vm\native)

const DalvikNativeMethod dvm_dalvik_system_DexFile[] = {

{ "openDexFile", "(Ljava/lang/String;Ljava/lang/String;I)I",

Dalvik_dalvik_system_DexFile_openDexFile },

{ "closeDexFile", "(I)V",

Dalvik_dalvik_system_DexFile_closeDexFile },

{ "defineClass", "(Ljava/lang/String;Ljava/lang/ClassLoader;ILjava/security/ProtectionDomain;)Ljava/lang/Class;",

Dalvik_dalvik_system_DexFile_defineClass },

{ "getClassNameList", "(I)[Ljava/lang/String;",

Dalvik_dalvik_system_DexFile_getClassNameList },

{ "isDexOptNeeded", "(Ljava/lang/String;)Z",

Dalvik_dalvik_system_DexFile_isDexOptNeeded },

{ NULL, NULL, NULL },

};

 

在 (vm\native\ dalvik_system_DexFile.c)文件中的

static void Dalvik_dalvik_system_DexFile_openDexFile(const u4* args, JValue* pResult)

函数,描述了如何加载dex文件的。

加载好的dex文件并不能立刻被执行,需要先调用方法defineClass来定义类,才能使用,该方法函数位于(vm\native\ dalvik_system_DexFile.c)中

static void Dalvik_dalvik_system_DexFile_defineClass(const u4* args, JValue* pResult)

 

 

 

 

 

  评论这张
 
阅读(1141)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017