Android学习心得(4) --- MAC下smali文件编写与运行

我在博客上发表一些我的Android学习心得,希望对大家能有帮助。
在前一章我们学习了如何进行Android源代码下载,这一章学习基本的Dalvik指令集编写

Android学习心得(1) --- MAC下Android环境的搭建
Android学习心得(2) --- MAC下Android反编译
Android学习心得(3) --- MAC下Android源代码下载

这一章我们就从一个基本的例子来开始Dalvik指令集的学习

1、编写smali文件

我们编写一个smali文件来学习Dalvik指令集
先学习一下HelloWorld类的框架
.class public LHelloWorld; //public class HelloWorld
.super Ljava/lang/Object; //定义父类java.lang.Object
.method public static main([Ljava/lang/String;)V
//public static void main(String[] args) 静态main()方法
    .registers * //#寄存器数量待定
    .parameter  //高版本的baksmali需要删除,否则编译失败
    .prologue   //指定函数代码起始处
    return-void //函数返回
.end method
这个就是一个smali文件的整体框架
为了更好的理解,我决定从一个基本的java文件反汇编为smali文件
从而更好的理解Dalvik指令与java代码对应关系
首先先在目录下面通过创建Hello.java
//测试Hello.java文件源代码
public class Hello{
  int add(int a, int b) {
      return a+b;
  }
  public static void main(String[] args) {
      Hello hello = new Hello();
      System.out.println(hello.add(1,1));
  }
}
通过javac编译成Hello.class字节码文件(注:我的版本jdk为1.7,使用dx生成Hello.dex文件时候出现错误,强制使用1.6来进行)
在使用dx工具生成Hello.dex文件
使用baksmali.jar反汇编Hello.dex生成Hello.smali

编译图片Android学习心得(4) --- MAC下smali文件编写与运行_第1张图片

下面我们查看baksmaliout中Hello.smali文件
//p命名法:v*表示局部变量寄存器,p*表示参数寄存器
.class public LHello;
.super Ljava/lang/Object;
.source "Hello.java"


# direct methods
.method public constructor <init>()V
    .registers 1

    .prologue
    .line 1
    #调用Object的构造方法,p0相当于"this" 指针
    invoke-direct {p0}, Ljava/lang/Object;-><init>()V

    return-void
.end method

.method public static main([Ljava/lang/String;)V

    #使用了四个寄存器
    .registers 4

    .prologue

    #把1数据存入v2寄存器中
    const/4 v2, 0x1

    new-instance v0, LHello;

    #调用实例的直接方法初始化
    invoke-direct {v0}, LHello;-><init>()V

    #把java.io.PrintStream类的对象out获取并放入v1寄存器中
    sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream;

    #调用add(1,1)方法,
    invoke-virtual {v0, v2, v2}, LHello;->add(II)I

    #并把方法调用返回值放入v0寄存器中
    move-result v0

    #调用PrintStream中println()方法把v0的值输出
    invoke-virtual {v1, v0}, Ljava/io/PrintStream;->println(I)V

    return-void
.end method


# virtual methods
.method add(II)I
    .registers 4

    .prologue

    #将p1,p2参数寄存器中的值相加,保存到v0寄存器中
    add-int v0, p1, p2

    #函数返回v0寄存器中的值
    return v0
.end method
下面我们自己进行编写smali文件来从终端接收两个参数
并相加通过PrintStream.println()函数输出结果

下面给出我写的Hello.smali源代码

.class public LHello;
.super Ljava/lang/Object;
.source "Hello.java"


# direct methods
#初始化函数
.method public constructor <init>()V
    .registers 1
    .prologue

    invoke-direct {p0}, Ljava/lang/Object;-><init>()V
    return-void
.end method

#主函数
.method public static main([Ljava/lang/String;)V
    .registers 4
    .prologue

    const/4 v0, 0x0
    const/4 v1, 0x1

    #接收两个传入的参数放入v0,v1
    aget-object v0, p0, v0
    aget-object v1, p0, v1

    #强制转化成int类型
    invoke-static {v0}, Ljava/lang/Integer;->parseInt(Ljava/lang/String;)I
    move-result v0
    invoke-static {v1}, Ljava/lang/Integer;->parseInt(Ljava/lang/String;)I
    move-result v1

    #两个参数相加,值存在vo
    add-int/2addr v0, v1

    #将v0的值输出
    sget-object v2, Ljava/lang/System;->out:Ljava/io/PrintStream;
    invoke-virtual {v2, v0}, Ljava/io/PrintStream;->println(I)V

    return-void
.end method

2、编译smali文件并测试运行

打开Android模拟器,将打包好的Hello.zip文件传输到模拟器中,可用DBMS查看
将编译出来的classes.dex文件压缩成Hello1.zip文件

终端输入指令
Hello1.zip

最终查看结果,输出结果为5正确!

最后附上工具的百度云连接
baksmali.jar
smali.jar
链接: http://pan.baidu.com/s/1prwRW 密码: bq6w

你可能感兴趣的:(android,编译,Smali)