介绍
对于dalviks字节码寄存器都是32位的,它能够表示任何类型,2个寄存器用于表示64位的类型(Long and Double)。
作用
声明于方法内部(必须)
1 | .method public getName()V |
.registers和locals基本区别
在一个方法(method)中有两中方式指定有多少个可用的寄存器。指令.registers指令指定了在这个方法中有多少个可用的寄存器,
指令.locals指明了在这个方法中非参(non-parameter)寄存器的数量。然而寄存器的总数也包括保存方法参数的寄存器。
参数是如何传递的?
1.如果是非静态方法
例如,你写了一个非静态方法LMyObject;->callMe(II)V
。这个方法有2个int参数,但在这两个整型参数前面还有一个隐藏的参数LMyObject
;也就是当前对象的引用,所以这个方法总共有3个参数。
假如在一个方法中包含了五个寄存器(V0-V4),如下:
1 | .method public callMe(II)V |
那么只需用.register指令指定5个,或者使用.locals指令指定2个(2个local寄存器+3个参数寄存器)。如下:
1 | .method public callMe(II)V |
该方法被调用的时候,调用方法的对象(即this引用)会保存在V2中,第一个参数在V3中,第二个参数在v4中。
2.如果是静态方法
那么参数少了对象引用,除此之外和非静态原理相同,registers为4 locals依然是2
关于寄存器命名规则
v命名法
上面的例子中我们使用的是v命名法,也就是在本地寄存器后面依次添加参数寄存器,
但是这种命名方式存在一种问题:假如我后期想要修改方法体的内容,涉及到增加或者删除寄存器,由于v命名法需要排序的局限性,那么会造成大量代码的改动,有没有一种办法让我们只改动registers或者locals的值就可以了呢, 答案是:有的
除v命名法之外,还有一种命名法叫做p命名法
p命名法
p命名法只能给方法参数命名,不能给本地变量命名
假如有一个非静态方法如下:
1 | .method public print(Ljava/lang/String;Ljava/lang/String;I)V |
以下是p命名法参数对应表:
p0 | this |
---|---|
p1 | 第一个参数Ljava/lang/String; |
p2 | 第二个参数Ljava/lang/String; |
p3 | 第三个参数I |
如前面提到的,long和double类型都是64位,需要2个寄存器。当你引用参数的时候一定要记住,例如:你有一个非静态方法
1 | LMyObject;->MyMethod(IJZ)V |
方法的参数为int、long、bool。所以这个方法的所有参数需要5个寄存器。
p0 | this |
---|---|
p1 | I |
p2, p3 | J |
p4 | Z |
另外当你调用方法后,你必须在寄存器列表,调用指令中指明,两个寄存器保存了double-wide宽度的参数。
注意:在默认的baksmali中,参数寄存器将使用P命名方式,如果出于某种原因你要禁用P命名方式,而要强制使用V命名方式,应当使用-p/–no-parameter-registers选项。
总结
- locals和registers都可以表示寄存器数量,locals指定本地局部变量寄存器个数,registers是locals和参数寄存器数量的总数,两者使用任选其一
- 同时,寄存器命名一共分两种,一种是v命名法,另一种是p命名法
v0 | the first local register | |
---|---|---|
v1 | the second local register | |
v2 | p0 | the first parameter register |
v3 | p1 | the second parameter register |
v4 | p2 | the third parameter register |