PrisonJoker 2012-03-30
寄存器Registers
描述smali文件中寄存器的具体信息,并概括在dalvik字节码中的信息。
介绍Introduction
在dalvik字节码中,寄存器总是32位,能够保存任何类型的值。2个寄存器用来保存64位的类型(Long和Double)。
说明方法中寄存器的个数
有两种方法指定方法中有多少个寄存器可用。类似.registers的指令,指明了方法中总的寄存器数目;另一中.locals指令,指明了方法中不包括参数(函数入参)在内的寄存器数目。方法中总的寄存器数目包括保存locals(本地变量)所需的和保存函数参数所需的寄存器数目。
方法的参数是怎样传递到方法中的?
当一个方法被调用时,方法的参数被放置在最后几个寄存器中。如果一个方法有2个入参和注册了5个寄存器(v0-v4),参数被放置在最后2个寄存器,v3和v4.
非静态方法的第一个参数总是调用改方法的对象(可以理解为this指针)。
例如,你写了一个静态方法,LMyObject;->callMe(II)V.这个方法有2个整形参数,但是在两个整形参数之前,它还有一个隐藏的参数LMyObject;,因此改方法的参数总数是3.
假设你通过.register5(v0-v4)或者.locals2指令(2个本定寄存器加3个参数寄存器),指定在方法中有5个寄存器可用。当这个方法被调用时,调用改方法的对象将被保存在v2寄存器中,第一个整形参数保存在v3中,第二个整形参数保存在v4中。
静态方法与此类似,只不过没有隐藏的this参数。
寄存器的名称
寄存器有2种命名设计,正常的v命名和为了参数设计的p命名。p命名方案中的p0是指方法中的第一个参数。让我们回到上一个例子当中,方法有3个参数,共5个寄存器。下面的表格表明了v命名方案中每个v参数和相应的p命名方案中的p参数。
v0第一个本地寄存器
v1第二个本地寄存器
v2p0第一个参数寄存器
v3p1第二个参数寄存器
v4p2第三个参数寄存器
引用参数寄存器时,这两种命名方式都可以采用。
引入参数寄存器的动机
作为一个特例,引入p命名方案的参数寄存器,是为了在编辑smali代码时解决一个常见的烦恼。
假设你现在有一个有大量参数的方法,并要向里面添加一些代码,这时你发现你需要一个额外的寄存器。你会认为,这是一个小事,增加.registers指令后面跟的number就好。
不幸的是,事情并不是那么简单,要记住的是方法的参数保存在最后几个寄存器当中。如果你增加寄存器的数量,你就改变了保存方法参数的寄存器。这样你就必须要改变.register指令并且改变每一个参数寄存器的号码。
但是如果在方法中,p命名方法被用来指示参数寄存器,你可以简单的改变方法中参数寄存器的数目,而不用担心改变任何现存的寄存器的号码。
注意:默认的,baksmali对参数寄存器使用p命名方案。如果你想把这部分功能关调,强制要求baksmali使用v命名方案,你可以使用-p/--no-parameter-registersoption.
Long/Doublevalues
正如前面所提到的,long和double类型(缩写是J和D)是64位的值,它们需要2个寄存器。当你要引用函数参数的时候,这一点要记住。例如假设你有一个方法(非静态的)LMyObject;->MyMethod(IJZ)V.方法的参数是LMyObject;,int,long,bool.因此这个方法需要5个寄存器保存参数。
p0this
p1I
p2,p3J
p4Z
并且,在你随后调用这个方法得时候,你必须在调用指令的寄存器列表中,为任何一个double长度的参数指定一个双寄存器。