编写一个 smali 文件 & 简单算术表达式的计算

一、smali 文件的编写

(Ⅰ)smali 文件的编写

编写 “HelloXidian.smali” 文件,代码如下所示:

.class public LHelloXidian;
.super Ljava/lang/Object;
.method public static main([Ljava/lang/String;)V
        .registers 2
		.prologue
		new-instance v0, Ljava/lang/StringBuilder;
		invoke-direct {v0}, Ljava/lang/StringBuilder;-><init>()V
		sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream;
		const-string v0, "Hello Xidian"
		invoke-virtual {v1,v0}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
		return-void
.end method

代码编写过程说明:

首先,声明了 smali 文件的头,每个 smali 文件都会包含它们。.class 表示类名,这里定义了一个 public 的类,类名是 HelloXidian。.super 表示它的 父类,这里是 java.lang.Object。

紧接着,以一个 .method 开始,一个 .end method 结尾,表示它是一个方法,而 public static main 表示它是一个 公有静态 方法,方法名是 main。之后紧跟的 ([LJava/lang/String;)V 表示它需要传递一个 Java.lang.String 类型的数组,并且返回值是 void。
方法内部的代码,.registers 表示 寄存器 的声明,这里声明了 2 个寄存器,供后面使用,.prologue 表示一个开场,之后跟随的才是业务逻辑的代码。

逐行分析:

  1. new-instance v0, Ljava/lang/StringBuilder; 表示构造了一个 java.lang.StringBuilder 类型对象的新实例,并将对象引用赋值给 v0 寄存器。

  2. invoke-direct {v0}, Ljava/lang/StringBuilder;-> < init >(),其中 MethodName 为 < init >,表明调用了一个 Ljava/lang/StringBuilder 的构造方法,不包含参数,并且返回值为 void。

  3. sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream; 表示创建了一个 java.io.PrintStream 对象,并存入 v1 寄存器中。

  4. const-string v0, “Hello Xidian” 表示声明了一个字符串 “Hello Xidian”,并存入 v0 寄存器中。

  5. invoke-virtual {v1,v0}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V 表示调用了 java.io.PrintStream 中的 println() 方法,参数传递的是 v0 寄存器中的值,就是之前存储的 “Hello Xidian”。

  6. 最后,return-void 表示函数返回 void。

(Ⅱ)具体操作过程

  1. 编写并保存 HelloXidian.smali 文件:

在这里插入图片描述
2. 将 smali.jarHelloXidian.smali 放到 Android SDK 的 tools 文件夹中,打开命令提示符窗口,进入到 SDK 下的 tools 文件夹,输入命令: java –jar smali.jar –o classes.dex HelloXidian.smali,在当前目录下生成 classes.dex 文件:

在这里插入图片描述
3. 将 classes.dex 文件打包为 HelloXidian.zip 文件,放到当前目录下。
4. 启动 Android 运行环境

在这里插入图片描述
在命令提示符窗口中执行以下命令:

adb push HelloXidian.zip /data/local
adb shell dalvikvm –cp /data/local/HelloXidian.zip HelloXidian

命令执行后在窗口下输出 “Hello Xidian” 字符串:
在这里插入图片描述
对应的 Java 代码如下所示:

public class HelloXidian
{
	public static void main(String[] args)
	{
		System.out.println("Hello Xidian");
	}
}

(Ⅲ)运行结果

在这里插入图片描述
启动 Android 运行环境,在命令提示符窗口中执行命令,命令执行后在窗口下输出了 “Hello Xidian” 字符串。

二、编写 smali 文件,计算(7+5)*(7-5)并输出结果

(Ⅰ)smali 文件的编写

编写 “calculate.smali” 文件,代码如下所示:

.class public Lcalculate;
.super Ljava/lang/Object;

.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 6
    .prologue
    .line 6
    const/16 v0, 0x18
    .line 7
    sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream;
    const-string v2, "(7 + 5)*(7 - 5) = %d\n"
    const/4 v3, 0x1
    new-array v3, v3, [Ljava/lang/Object;
    const/4 v4, 0x0
    invoke-static {v0}, Ljava/lang/Integer;->valueOf(I)Ljava/lang/Integer;
    move-result-object v0
    aput-object v0, v3, v4
    invoke-virtual {v1, v2, v3}, Ljava/io/PrintStream;->printf(Ljava/lang/String;[Ljava/lang/Object;)Ljava/io/PrintStream;
    .line 9
    return-void
.end method

代码编写过程说明:

首先,声明了 smali 文件的头,每个 smali 文件都会包含它们。.class 表示类名,这里定义了一个 public 的类,类名是 calculate。.super 表示它的父类,这里是 java.lang.Object。

紧接着,以一个 .method 开始,一个 .end method 结尾,表示它是一个方法,public constructor 表示它是一个 公有的构造方法,这里是 Java 类 默认的构造方法,如果我们不声明构造方法,编译器会为我们创建一个无参的构造方法。

而下面的 public static main 表示它是一个公有的静态方法,方法名是 main。([LJava/lang/String;)V 表示它需要传递一个 Java.lang.String 类型的数组,并且返回值是 void。

方法内部的代码,.registers 表示寄存器的声明,这里声明了 6 个寄存器,供后面使用,.prologue 表示一个开场,之后跟随的才是业务逻辑的代码。

逐行分析:

  1. const/16 v0, 0x18 声明了一个常量,将一个 16 位的常量 0x18 赋值给 v0 寄存器。
  2. sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream; 表示创建了一个java.io.PrintStream 对象,并存入 v1 寄存器中。
  3. const-string v2, “(7 + 5)*(7 - 5) = %d\n” 声明了一个字符串常量,将该字符串 “(7 + 5)*(7 - 5) = %d\n” 赋值给 v2 寄存器。
  4. const/4 v3, 0x1 声明了一个常量,将一个 4 位的常量 0x1 赋值给 v3 寄存器。
  5. new-array v3, v3, [Ljava/lang/Object; 构造类型为 java.lang.Object,大小为 v3 寄存器大小,即为 1 的数组,并将数组的引用赋给 v3 寄存器。
  6. const/4 v4, 0x0 声明了一个常量,将一个 4 位的常量 0x0 赋值给 v4 寄存器。
  7. invoke-static {v0}, Ljava/lang/Integer;->valueOf(I)Ljava/lang/Integer; 表示调用了一个java.lang.Integer中的静态方法 valueOf,形参保存在寄存器 v0 中,类型为整型 int,返回值类型为 java.lang.Integer
  8. move-result-object v0 表示将上一个 invoke 类型指令操作的对象结果赋给 v0 寄存器。
  9. aput-object v0, v3, v4 将 v0 的对象引用作为元素存入对象引用数组,数组的引用位于 v3,元素的索引位于 v4,即为 0。此时,结果值 “0x18” 已被存入 v3 指向的内存单元中。
  10. new-instance v0, Ljava/lang/StringBuilder; 表示构造了一个 java.lang.StringBuilder 类型对象的新实例,并将对象引用赋值给 v0 寄存器。
  11. invoke-virtual {v1, v2, v3}, Ljava/io/PrintStream;->printf(Ljava/lang/String;[Ljava/lang/Object;)Ljava/io/PrintStream; 表示调用了 v1 中 java.io.PrintStreamprintf() 方法,参数传递的是 v2、v3 寄存器中的值,就是之前存储的 “(7 + 5)*(7 - 5) = %d\n” 和 “0x18” 。
  12. 最后,return-void 表示函数返回 void。

(Ⅱ)具体操作过程

  1. 编写并保存 calculate.smali 文件:

在这里插入图片描述
2. 将 smali.jarcalculate.smali 放到 Android SDK 的 tools 文件夹中,打开命令提示符窗口,进入到 SDK 下的 tools 文件夹,输入命令: java –jar smali.jar –o classes.dex calculate.smali,在当前目录下生成 classes.dex 文件。

在这里插入图片描述
3. 将 classes.dex 文件打包为 calculate.zip 文件,放到当前目录下。
4. 启动 Android 运行环境:

在这里插入图片描述
在命令提示符窗口中执行以下命令:

adb push calculate.zip /data/local
adb shell dalvikvm –cp /data/local/calculate.zip calculate

命令执行后在窗口下输出了(7+5)*(7-5)= 24 的结果:

在这里插入图片描述
对应的 Java 代码为:

public class calculate
{
	public static void main(String[] args)
	{
		int i;
		i = (7 + 5)*(7 - 5);
		System.out.printf("(7 + 5)*(7 - 5) = %d\n",i);
	}
}

(Ⅲ)运行结果

启动 Android 运行环境,在命令提示符窗口中执行命令,命令执行后在窗口下输出了(7+5)*(7-5)= 24 的结果。

在这里插入图片描述

三、一些问题及解决方法

(1)问题:在进行测试时,未启动安卓虚拟设备,导致命令提示符提示出错:

在这里插入图片描述
解决方法:启动安卓虚拟设备后,再次执行命令,即可成功进行操作。

(2)问题:在执行adb push HelloXidian.zip /data/local
时,提示信息 “read-only file system”。

解决方法:利用 adb remount 命令,将设备改为 可读可写,即可成功执行接下来的 adb 操作。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值