https://www.imgeek.org/article/825358911
介紹
對於dalviks字節碼寄存器都是32位的,它能夠表示任何類型,2個寄存器用於表示64位的類型(Long and Double)。
作用
聲明於方法內部(必須)
.method public getName()V
.registers 6
return-void
.end method
.registers和locals基本區別
在一個方法(method)中有兩中方式指定有多少個可用的寄存器。指令.registers指令指定了在這個方法中有多少個可用的寄存器,
指令.locals指明了在這個方法中非參(non-parameter)寄存器的數量。然而寄存器的總數也包括保存方法參數的寄存器。
參數是如何傳遞的?
1.如果是非靜態方法
例如,你寫了一個非靜態方法LMyObject;->callMe(II)V。這個方法有2個int參數,但在這兩個整型參數前面還有一個隱藏的參數LMyObject;也就是當前對象的引用,所以這個方法總共有3個參數。 假如在一個方法中包含了五個寄存器(V0-V4),如下:
.method public callMe(II)V
const-string v0,"1"
const-string v1,"1"
return-void
.end method
那么只需用.register指令指定5個,或者使用.locals指令指定2個(2個local寄存器+3個參數寄存器)。如下:
.method public callMe(II)V
.registers 5
const-string v0,"1"
const-string v1,"1"
v3==>p0
V4==>P1
V5==>P2
return-void
.end method
或者
.method public callMe(II)V
.locals 2
const-string v0,"1"
const-string v1,"1"
return-void
.end method
該方法被調用的時候,調用方法的對象(即this引用)會保存在V2中,第一個參數在V3中,第二個參數在v4中。
2.如果是靜態方法
那么參數少了對象引用,除此之外和非靜態原理相同,registers為4 locals依然是2
關於寄存器命名規則
v命名法
上面的例子中我們使用的是v命名法,也就是在本地寄存器后面依次添加參數寄存器,
但是這種命名方式存在一種問題:假如我后期想要修改方法體的內容,涉及到增加或者刪除寄存器,由於v命名法需要排序的局限性,那么會造成大量代碼的改動,有沒有一種辦法讓我們只改動registers或者locals的值就可以了呢, 答案是:有的
除v命名法之外,還有一種命名法叫做p命名法
p命名法
p命名法只能給方法參數命名,不能給本地變量命名
假如有一個非靜態方法如下:
.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個寄存器。當你引用參數的時候一定要記住,例如:你有一個非靜態方法
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
