最近对移动端产生了很浓厚的兴趣,那就开始学习吧!因为还有工作任务,忙里偷闲把丰生强的前3章认真读了一遍。小结内容是说必须熟练掌握这一部分的内容,可通过手动编写Dalvik汇编代码来熟悉一下指令,为后面的分析夯实好基础。
书上的是一个显示HelloWorld的例子,为了练习好基础。准备要用Dalvik汇编写一个简单的程序,功能如下:
按照书上的,把框架搭好如下:
代码:
[Asm] 纯文本查看 复制代码 .class public Ltest;
.super Ljava/lang/Object;
.method public constructor <init>()V
#寄存器数量待定
.registers 1
.parameter
.prologue
return-void
.end method
思路:由于要传2个参数进去计算,并不是像书上的例子一样,只是打印出一行字,所以要弄清楚参数是如何传进去的。写一个简单的程序反编译看看。程序代码:
代码:
[Asm] 纯文本查看 复制代码 public class test2 {
public static void main(String[] args) {
String a = args[0];
}
}
编译成smali代码先看看参数是怎么样传进去的,smali代码如下:
[Asm] 纯文本查看 复制代码 .class public Ltest2;
.super Ljava/lang/Object;
.source "test2.java"
# direct methods
.method public constructor <init>()V
.registers 1
.prologue
.line 1
invoke-direct {p0}, Ljava/lang/Object;-><init>()V
return-void
.end method
.method public static main([Ljava/lang/String;)V
.registers 2
.prologue
.line 4
const/4 v0, 0x0
aget-object v0, p0, v0
.line 6
return-void
.end method
发现除了main函数外还有一个direct method:
[Asm] 纯文本查看 复制代码 .method public constructor <init>()V
表示该类的不带参数缺省的构造方法
看来这就是传参的关键。
[Asm] 纯文本查看 复制代码 const/4 v0, 0x0
aget-object v0, p0, v0
Main函数中用这2句的接受传进来的值。
所以应该先添加这个构造方法:
[Asm] 纯文本查看 复制代码 # direct methods
.method public constructor <init>()V
.registers 1
.prologue
invoke-direct {p0}, Ljava/lang/Object;-><init>()V
return-void
.end method
接着写代码如下:
[Asm] 纯文本查看 复制代码 #V0 V1 清零
const/4 v0, 0x0
const/4 v1, 0x0
#接收传进来的2个参数
aget-object v0, p0, v0
aget-object v1, p0, v1
#把第一个参数转化成int类型 给vo
invoke-static {v0}, Ljava/lang/Integer;->parseInt(Ljava/lang/String;)I
move-result v0
#把第二个参数转化成int类型 给v1
invoke-static {v1}, Ljava/lang/Integer;->parseInt(Ljava/lang/String;)I
move-result v1
#两个参数相加 值存 给vo
add-int/2addr v0, v1
#把vo中的结果转化成String类型 再给v0
invoke-static {v0}, Ljava/lang/String;->valueOf(I)Ljava/lang/String;
move-result-object v0
#构造一个String类型对象的新实例 把值赋给v2
new-instance v2, Ljava/lang/StringBuilder;
#调用实例的直接方法
invoke-direct {v2}, Ljava/lang/StringBuilder;-><init>()V
#定义一个字符串常量
const-string v3, "The Sum is :"
#调用实例方法,把v3与v2里的字符串相加再给v2 invoke-virtual{v2,v3},Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v2
#调用实例方法,把v0与v2里的字符串相加再给v2
invoke-virtual{v2,v0},Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v2
#输出结果
invoke-virtual {v1, v2}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
终于写完了,我们编译好来看看结果。
编译出dex文件:
Push到android里:
执行:
发现报错了。百思不得其解,纠结了好久。代码也检查了好几遍,最后都要崩溃了,还是出错。后来实在忍无可忍,写了个程序反编译出dex文件看看吧。结果发现了原来少了这么一句:
[Asm] 纯文本查看 复制代码 #此句加在输入结果之前,将v2里的东西转化成String类型。
invoke-virtual {v2}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-object v2
重新编译dex-->PUSH-->执行再试试:
好了,当然编写的过程中可能会出现各种各样的错误,需要耐心+毅力。
最后要说一下,.parameter这行我是删了,用了2个版本的
都试了一下,发现没有.parameter,有的话会报错。可能是丰写此书的时候版本还很低吧,这个大家要注意哦。
总的来说,虽然就这么一点代码,也不难。但确实是花了我不少时间,不过同时也学到了不少东西,对smali语句和adb命令,dex、class、smali等几种格式的互相转化也很熟练了。
最后感谢丰大牛,书写得很好,有的细节不够完美,但瑕不掩瑜。路漫漫其修远兮,打牢基础才能走得更远。
|