我对 Dalvik 字节码的格式有点陌生,我想知道这些 *-bearing 寄存器是什么意思,例如对象承载、异常承载等。
同时,生成的字节码是使用类型,而不是寄存器?例如,
throws Landroid/database/SQLException
是生成的,但是Landroid/database/SQLException
是一个类型,那么为什么指令摘要说异常承载寄存器throw vAA
在哪里?vAA
我错过了什么吗?
这只是指指令保存的数据类型。vm 必须能够静态地确定该寄存器在该点包含该类型的数据。换句话说,对于所有传入的代码路径,该寄存器已设置为该类型的数据。
如果您想更详细地研究寄存器类型信息是如何传播的,您可以使用 -r 选项使用 baksmali 反编译您的应用程序,该选项将在每条指令之前/之后输出注释,其中包含与寄存器相关的寄存器类型信息那条指令。此信息应与 vm 在字节码验证器中内部构建的寄存器类型信息相匹配。
例如,假设您有一个仅包含以下内容的方法:
const-string v0, "Hello World!"
throw v0
这是不允许的,因为在 throw 指令处,p0 寄存器不包含对从 Throwable 扩展的对象的引用(即它不是“带有异常的寄存器”)。
如果你在 baksmali 中使用 -r,你会看到:
#v0=(Uninit);
const-string v0, "Hello World!"
#v0=(Reference,Ljava/lang/String;);
#v0=(Reference,Ljava/lang/String;);
throw v0
这清楚地表明 v0 在 throw 指令处不包含异常。
此外,不允许这样的事情:
#v0=(Uninit);
new-instance v0, Ljava/lang/Exception;
#v0=(UninitRef,Ljava/lang/Exception;);
#v0=(UninitRef,Ljava/lang/Exception;);
invoke-direct {v0}, Ljava/lang/Exception;-><init>()V
#v0=(Reference,Ljava/lang/Exception;);
#p0=(Integer);
if-eqz p0, :cond_9
#v0=(Reference,Ljava/lang/Exception;);
const-string v0, "Hello World!"
#v0=(Reference,Ljava/lang/String;);
:cond_9
#v0=(Reference,Ljava/lang/Object;);
throw v0
因为在抛出点,v0 可能包含异常或字符串。在这种情况下,它将 v0 的“类型”报告为Ljava/lang/Object;
,因为这是两种类型的公共父类。