Android-smali语法学习

转载请标明出处:http://blog.csdn.net/goldenfish1919/article/details/40821415

下面内容来自:http://bbs.pediy.com/showthread.php?t=151769

dalvik字节码有两种类型,原始类型和引用类型。

对象和数组是引用类型。其他都是原始类型。

V  void,仅仅能用于返回值类型

Z  boolean

B  byte

S  short

C  char

I  int

J  long(64位)

F  float

D  double(64位)

对象以Lpackage/name/ObjectName;的形式表示。

前面的L表示这是一个对象类型。package/name/是该对象所在的包,ObjectName是对象的名字,“;”表示对象名称的结束。

相当于java中的package.name.ObjectName。比如:Ljava/lang/String;相当于java.lang.String

数组的表示形式

?  [I——表示一个整型一维数组。相当于java中的int[]。

?  对于多维数组。仅仅要添加[即可了。[[I相当于int[][],[[[I相当于int[][][]。注意每一维的最多255个。

?  对象数组的表示:[Ljava/lang/String;表示一个String对象数组。

方法

表示形式:Lpackage/name/ObjectName;->MethodName(III)Z

?  Lpackage/name/ObjectName;表示类型,MethodName是方法名。III为參数(在此是3个整型參数),Z是返回类型(bool型)。

?  方法的參数是一个接一个的,中间没有隔开。

一个更复杂的样例:

method(I[[IILjava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;

在java中则为:

String method(int, int[][], int, String, Object[])

字段

表示形式:

Lpackage/name/ObjectName;->FieldName:Ljava/lang/String;

即包名,字段名和各字段类型。

寄存器

在dalvik字节码中。寄存器都是32位的,可以支持不论什么类型。64位类型(Long和Double型)用2个寄存器表示。

有两种方式指定一个方法中有多少寄存器是可用的。.registers指令指定了方法中寄存器的总数。.locals指令表明了方法中非參寄存器的数量。

方法的传參

?  当一个方法被调用的时候,方法的參数被置于最后N个寄存器中。假设一个方法有2个參数,5个寄存器(v0-v4),那么參数将置于最后2个寄存器——v3和v4。

?  非静态方法中的第一个參数总是调用该方法的对象。

比如。非静态方法LMyObject;->callMe(II)V有2个整型參数。另外另一个隐含的LMyObject;參数,所以总共同拥有3个參数。

假如在该方法中指定了5个寄存器(v0-v4)。以.registers方式指定5个或以.locals方式指定2个(即2个local寄存器+3个參数寄存器)。

当该方法被调用的时候,调用该方法的对象(即this引用)存放在v2中,第一个整型參数存放在v3中,第二个整型參数存放在v4中。

对于静态方法除了没有隐含的this參数外其他都一样。

寄存器的命名方式

有两种方式——V命名方式和P命名方式。P命名方式中的第一个寄存器就是方法中的第一个參数寄存器。

在下表中我们用这两种命名方式来表示上一个样例中有5个寄存器和3个參数的方法。

v0    第一个local register

v1    第二个local register

v2  p0  第一个parameter register

v3  p1  第二个parameter register

v4  p2  第三个parameter register

你能够用不论什么一种方式来引用參数寄存器——他们没有不论什么区别。

注意:baksmali默认对參数寄存器使用P命名方式。假设想使用V命名方式,能够使用-pl—no-parameter-registers选项。

使用P命名方式是为了防止以后假设要在方法中添加寄存器,须要对參数寄存器又一次进行编号的缺点。

Long/Double值

Long和double类型是64位的,须要2个寄存器(切记切记)。

比如,对于非静态方法LMyObject;->MyMethod(IJZ)V,參数各自是LMyObject;,int。long,bool。故该方法须要5个寄存器来存储參数。

p0  this

p1  I

p2,p3  J

p4  Z

补充:

# static fields             定义静态变量的标记

# instance fields        定义实例变量的标记

# direct methods       定义静态方法的标记

# virtual methods      定义非静态方法的标记

构造函数的返回类型为V,名字为<init>。

if-eq p1, v0, :cond_8 表示假设p1和v0相等,则运行cond_8的流程:

:cond_8

invoke-direct {p0}, Lcom/paul/test/a;->d()V

调用com.paul.test.a的d()方法

if-ne p1, v0, :cond_b 表示不相等则运行cond_b的流程:

:cond_b

const/4 v0, 0x0

invoke-virtual {p0, v0}, Lcom/paul/test/a;->setPressed(Z)V

invoke-super {p0, p1, p2}, Landroid/view/View;->onKeyUp(ILandroid/view/KeyEvent;)Z

move-result v0

大概意思就是调用com.paul.test.a的setPressed方法。然后再调用父类View的onKeyUp方法。最后 return v0

举两个样例:

sget-object v5, Lcom/google/youngandroid/runtime;->Lit227:Lgnu/mapping/SimpleSymbol;

获取com.google.youngandroid.runtime中的Lit227字段存入v5寄存器。相当于

gnu.mapping.SimpleSymbol localVariable = com.google.youngandroid.runtime.Lit227;

sput-object v0, Lcom/google/youngandroid/runtime;->Lit78:Lkawa/lang/SyntaxTemplate;

Likewise, this is setting the value of a static field. i.e.

设置com.google.youngandroid.runtime.Lit78的值为v0寄存器中的kawa.lang.SyntaxTemplate类型变量的值。相当于com.google.youngandroid.runtime.Lit78 = kawa.lang.SyntaxTemplate localVariable;

剩下的比較简单你应该能明确了。

以下我们来看一个简单的样例:

public class MainActivity extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		TextView textview1 = (TextView) this.findViewById(R.id.text);
		textview1.setText(R.string.hello_world);
	}
}

生成的smali:

.class public Lcom/example/hello/MainActivity;
.super Landroid/app/Activity;
.source "MainActivity.java"

# direct methods
.method public constructor <init>()V
    .locals 0

    .prologue
    .line 14
    invoke-direct {p0}, Landroid/app/Activity;-><init>()V

    return-void
.end method

# virtual methods
.method protected onCreate(Landroid/os/Bundle;)V
    .locals 2
    .parameter "savedInstanceState"

    .prologue
    .line 18
    invoke-super {p0, p1}, Landroid/app/Activity;->onCreate(Landroid/os/Bundle;)V

    .line 19
    const/high16 v1, 0x7f03

    invoke-virtual {p0, v1}, Lcom/example/hello/MainActivity;->setContentView(I)V

    .line 20
    const/high16 v1, 0x7f0a

    invoke-virtual {p0, v1}, Lcom/example/hello/MainActivity;->findViewById(I)Landroid/view/View;

    move-result-object v0

    check-cast v0, Landroid/widget/TextView;

    .line 21
    .local v0, textview1:Landroid/widget/TextView;
    const v1, 0x7f070002

    invoke-virtual {v0, v1}, Landroid/widget/TextView;->setText(I)V

    .line 22
    return-void
.end method

我们重点来看下onCreate()这个的方法。

.method protected onCreate(Landroid/os/Bundle;)V

.locals 2

.parameter "savedInstanceState"

.prologue

.line 18

invoke-super {p0, p1}, Landroid/app/Activity;->onCreate(Landroid/os/Bundle;)V // 这是调用super也就是Activity.onCreate(Bundle) p0:this,p1:Bundle

.line 19

const/high16 v1, 0x7f03   //把0x7f03这个常量赋值给v1 ,0x7f03就是R.layout.activity_main

invoke-virtual {p0, v1}, Lcom/example/hello/MainActivity;->setContentView(I)V // 调用MainActivity.setContentView(v1),p0:this。v1就是R.layout.activity_main

.line 20

const/high16 v1, 0x7f0a // 把0x7f0a 这个常量赋值给v1 。0x7f0a 就是R.id.text

invoke-virtual {p0, v1}, Lcom/example/hello/MainActivity;->findViewById(I)Landroid/view/View;  // 调用View = MainActivity.findViewById(v1)。p0:this。v1:R.id.text

move-result-object v0  // 把上一个指令的输出结果move到v0,就是给textview1赋值

check-cast v0, Landroid/widget/TextView;// 把v0强转成TextView

.line 21

.local v0, textview1:Landroid/widget/TextView;

const v1, 0x7f070002    // 把int常量0x7f070002放到v1中,就是读出来R.string.hello_world

invoke-virtual {v0, v1}, Landroid/widget/TextView;->setText(I)V  //调用TextView.setText(v1) TextView是v0。參数是v1

.line 22

return-void

.end method

还是挺简单的一个样例。跟class字节码很向。我们看一下相同的代码在class中和smali中有啥不一样的。

public void multiply(int a, int b){
		int result = a * b;
		System.out.println(result);
	}

smali表示:

# virtual methods

.method public multiply(II)V

.locals 2

.parameter "a"

.parameter "b"

.prologue

.line 26

mul-int v0, p1, p2  // p1和p2相乘,结果放到v0中

.line 27

.local v0, result:I

sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream;  // 获取System.out的引用。放到v1中

invoke-virtual {v1, v0}, Ljava/io/PrintStream;->println(I)V  // 调用PrintStream.println(v0)

.line 28

return-void

.end method

class表示:

public void multiply(int, int);

Code:

Stack=2, Locals=4, Args_size=3

0: iload_1                               // 本地变量1压栈

1: iload_2                               // 本地变量2压栈

2: imul                                     // 栈中取上面的2个做乘法

3: istore_3                              // 结果出栈,放到本地变量3中

4: getstatic#5; //Field java/lang/System.out:Ljava/io/PrintStream; // System.out压栈

7: iload_3                              // 本地变量3压栈

8: invokevirtual#6; //Method java/io/PrintStream.println:(I)V   // 调用PrintStream.println

11: return

LineNumberTable:

line 6: 0

line 7: 4

line 8: 11

上面能够非常清晰的看出来,实现相同的功能,基于寄存器要比基于栈的指令数要少。

int result = a * b;在smali中就一条指令,而在class中要4条指令。

关于smali全部指令的格式和含义能够參考:http://pallergabor.uw.hu/androidblog/dalvik_opcodes.html

时间: 2024-08-26 20:43:56

Android-smali语法学习的相关文章

android smail 语法学习之二

下面是if 语句 for 语句在smali中写法: 条件跳转分支: "if-eq vA, vB, :cond_**"   如果vA等于vB则跳转到:cond_**"if-ne vA, vB, :cond_**"   如果vA不等于vB则跳转到:cond_**"if-lt vA, vB, :cond_**"    如果vA小于vB则跳转到:cond_**"if-ge vA, vB, :cond_**"   如果vA大于等于vB则

Android smali 语法

http://nickycc.lofter.com/post/23e2a6_17d6a07 http://blog.csdn.net/l25000/article/details/46842013 https://smalinuxer.github.io/2015/12/07/smali-base-1.html

Android Java语法学习

Activity中有一个名称叫onCreate的方法.该方法是在Activity创建时被系统调用,是一个Activity生命周期的开始. onCreate方法的参数savedInstanceState onCreate方法的完整定义如下: public void onCreate(Bundle savedInstanceState){   ----------------onCreate方法的参数是一个Bundle类型的参数. super.onCreate(savedInstanceState)

Smali语言学习了

   最近一周在研究rom移植,所以就对Smali语言学习了一下,Smali语言其实就是Davlik的寄存器语言:Smali语言就是android的应用程序.apk通过apktool反编译出来的都有一个smali文件夹,里面都是以.smali结尾的文件,文件的展示语言. 如图,下面是HelloWorldApp通过apktool反编译出来的目录: Smali文件夹里面的目录, 先打开一个主类HelloWorldAppActivity.smali文件,先来浏览一下里面的语言,在来说说smali的语法

Smali语法简单介绍

Smali语言其实就是Davlik的寄存器语言: Smali语言就是android的应用程序.apk通过apktool反编译出来的都有一个smali文件夹,里面都是以.smali结尾的文件,文件的展示语言. Smali语法简单介绍如下: Davlik字节码中,寄存器都是32位的,能够支持任何类型,64位类型(Long/Double)用2个寄存器表示: Dalvik字节码有两种类型:原始类型:引用类型(包括对象和数组)   原始类型:v   void  只能用于返回值类型 Z   boolean

android smali代码注入 实战一

有同学在通服里面干活,最近一直忙着4g基站搭建的干活,测试设备(android)测量移动网络数据,没有自动保存记录的功能,只能手动记录各种测试参数,不知道测试软件供应商是怎样想的,竟然不提供的这样的功能! 要我帮忙把测试数据自动导入excel表格中,我硬着头皮去尝试下.网上有smali的语法和注入的介绍,但参考价值不大,分享下自己的smali注入的过程和心得(这里smali语法就不讲了). 案例 1.需求 需要提取数据界面如下: 提取数据字段信息: 地点address 小区识别码 cellId,

Android开发最佳学习路线图(转)

Android开发总体路线图: 基础学习——JavaSE:        很多朋友一上手就开始学习Android,似乎太着急了一些. Android应用程序开发是以Java语言为基础的,所以没有扎实的Java基础知识,只是机械的照抄别人的代码,是没有任何意义的.那么Java学到 什么程度才算是过关呢?以下的JAVA的基础(JavaSE)语法知识必须全面掌握. 经典学习视频教程 Java 概述 标示符.关键字1 标示符.关键字2 运算符 流程控制1 流程控制2 字符串数组 面向对象编程特征1 面向

Android菜鸟如何学习Android系统开发?

如何做好Android学习前的准备? 如果你已经确定了学习Android的目标,那么,应该提前做好哪些工作.先打下哪些基础呢? 首先,你最好先熟悉一门编程语言,现在大学里面和计算机相关的专业甚至理工类专业一般都会开设C语言课程,只是很多同学在大学期间并没有好好学习,如果对它掌握的不太好或者很久没用了,建议先从将其好好复习一下,将其基本的语法再好好回顾一下,最好能搭建一个环境来运行.调试它.如果没有学过,不妨也提前学习一下,可以参考清华大学出版社出版的谭浩强老师的<C语言程序设计>,推荐这本书的

smali语法小结

smali语言是Davlik的寄存器语言,语法上和汇编语言相似,Dalvik VM与JVM的最大的区别之一就是Dalvik VM是基于寄存器的.基于寄存器的意思是,在smali里的所有操作都必须经过寄存器来进行.Link Smali-数据类型 Davlik字节码中,寄存器都是32位的,能够支持任何类型,64位类型(Long/Double)用2个寄存器表示.Dalvik字节码有两种类型:原始类型:引用类型(包括对象和数组)@link. M1.基本数据类型 V void Z boolean B by

apk反汇编之smali语法

类型 Dalvik的字节码中拥有两个主要的类型:基类和引用类型.引用类型 引用类型是对象和数组,其他的一切都是基类   基类被一个简单的字符描述.我没有提出这些缩写词———他们实际以字符串的形式存储于dex文件中 他们被定义与dex格式网页文档中(在AOSP库中的路径是dalvik/docs/dex-format.html) V  空类型---仅仅可以用来作为返回类型 Z  Boolean 布尔型 B  Byte字节型 S  Short短整型(16位) C  Char字符型 I  Int 整形