smail中的数据类型签名跟java中的是一样的,如下。
B---byteC---charD---doubleF---floatI---intJ---longS---shortV---voidZ---boolean[XXX---arrayLxxx/yyy---object
smail代码例子:
初看smail文件,可能会觉得有一些凌乱。不过只要把几种语法弄懂了,就可以很好地阅读smail文件。
smail比较常用语法 ( 非全部)分为: 赋值,取值,函数调用,if语句,返回值等。
赋值取值:
例子: iget-object v6, p0, Lcom/zbsh/code/clas/ClassSystem$9;->val$vBarCodes:Ljava/util/ArrayList;
分析:
iget个取值操作,i=instance,是用来instance filed(实例变量),object是类的意思。 v6是本地寄存器,p0在这里是代表this(在非static函数正代表this,在static函数中代表第一个参数)。Lcom/zbsh/code/clas/ClassSystem是表示包路径为 Lcom/zbsh/code/clas下的ClassSystem类,->相当于C/C++的箭头操作符,后面是类中的变量或者方法vBarCodes是ClassSystem中的一个变量,Ljava/util/ArrayList是vBarCodes这个变量的类型 (是java中类的签名)
作用:
把ClassSystem中vBarCodes的值存放在寄存器v6中,vBarCodes的类型必须是对象,且是实例变量非静态变量。
其中object可以是替换成基本数据类型:iget-boolean iget-byte iget-char iget-short等等。
同样的:
sget- [type]用来获取static变量。(少了一个p0,因为静态变量是没有this的)
aget-[type]用来获取array类型。
[x]get vx, vy,把寄存器vy中的值赋给vx。
赋值:
同样都有以下几种:
iput-[type]
sput-[type]
aput-[type]
也支持寄存器和寄存器之间的赋值,寄存器和变量之间的赋值。
函数调用:
invoke-direct 调用private函数
invoke-super 调用父类函数
invoke-static 调用静态函数
invoke-virtual 用于调用protected或public函数(相当于C++的虚函数,java的重载函数,只有protect和public能够重载)
还有一种比较特殊的:invoke-xxxxx/range:参数多于5个的时候,要加/rang
例子:
invoke-virtual {v4, v1}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
v4是this,代表 Ljava/lang/String的一个实例,v1是函数的第一个参数,在这里是调用放在V4寄存器中类型为Ljava/lang/String的实例的equal ()方法,并传入参数v1,返回的结果是Z类型,也就是boolean类型。
如果是invoke-static{v4, v1}, 不同遇在于invoke-virtual {v4, v1}的是v4不是this,而是第一个参数。v1是第二个参数,所调用的方法需要两个参数。
返回值:
获取返回值:
move-result vx :把上一个方法返回的值,存在寄存器 vx中。
返回返回值:
return-void 没返回。
return vx 返回寄存器中vx的值 。
if语句:
if-eq vx,vy,target:eq:equal 如果vx==xy 跳转到target目标代码,否则执行顺序执行下一句代码
if-ne vx,vy,target:nq :not equal 如果vx!=xy 跳转到target目标代码,否则执行顺序执行下一句代码
if-eqz vx,target:eqz : equal zero 如果vx==0 跳转到target目标代码,否则执行顺序执行下一句代码
if-nez vx,target:nez :not equal zero 如果vx!=0 跳转到target目标代码,否则执行顺序执行下一句代码