smali to java_Smali —— 数学运算,条件判断,循环
通过上一篇 Smali 语法解析——Hello World 的学习,了解了 Smali
文件的基本格式。这一篇从最基本的数学运算,条件判断,循环等开始,更加详细的了解 Smali 语法。
数学运算
加法
先看源文件:
public class BaseSmali {private float add() {int a = 1;float b = 1.5f;return a + b;}
}
通过 javac
dx
和 baksmali
工具生成对应的 smali 文件,具体方法在 上一篇 中有所介绍。我们看一下生成的 smali 文件:
.class public LBaseSmali;
.super Ljava/lang/Object;
.source "BaseSmali.java"# direct methods
.method public constructor <init>()V.registers 1.prologue.line 1invoke-direct {p0}, Ljava/lang/Object;-><init>()Vreturn-void
.end method.method private add()F.registers 3 // 使用 3 个寄存器.prologue.line 5const/4 v0, 0x1 // 将 0x1 放入 v0.line 6const/high16 v1, 0x3fc00000 # 1.5f 将 1.5f 放入 v1.line 7int-to-float v0, v0 // 将 v0 中的 int 值强转为 float 再存入 v0add-float/2addr v0, v1 // 将 v0 和 v1 中的值相加再存入 v0return v0 // 返回 v0 中的值
.end method
代码逻辑很简单,可以看到 int
值和 float
值相加的过程中会先将 int
值强转为 float
,再进行加法。这里用到了数据定义,强转,加法三种 smali 语法。
数据定义指令
Dalvik 虚拟机中每个寄存器都是 32 位的。int
等 4字节表示的数据类型一个寄存器就可以表示,而 double
等 64 位的数据类型则需要两个寄存器来表示。数据定义指令用到的基本字节码是 const
,一般带 -wide
后缀表示的是 64 位数据,不带 -wide
后缀则是 32 位数据。上面的例子中定义了 两种基本数据类型。 const/4 v0, 0x1
表示将数值 0x1 扩展为 32 位之后赋给寄存器 v0。const/high16 v1, 0x3fc00000
,表示将 0x3fc00000
右边零扩展至 32 位赋给寄存器 v1。0x3fc00000
是 1.5f
在内存中的表示,如果你了解 float
数值在内存中的表示方法的话,就会理解这里为什么要右边零扩展了。不理解的话可以阅读我的文章,[先挖一个坑吧,还没有写]() 。下面介绍一些常见的数据定义指令(来自官网):
语法参数说明const/4 vA, #+BA:
目标寄存器(8 位) B:
有符号整数(8 位)将给定的字面值(符号扩展为 32 位)移到指定的寄存器中。const/16 vAA, #+BBBBA:
目标寄存器(8 位) B:
有符号整数(16 位)将给定的字面值(符号扩展为 32 位)移到指定的寄存器中。const vAA, #+BBBBBBBBA:
目标寄存器(8 位) B:
任意 32 位常量将给定的字面值移到指定的寄存器中。const/high16 vAA, #+BBBB0000A:
目标寄存器(8 位) B:
有符号整数(16 位)将给定的字面值(右零扩展为 32 位)移到指定的寄存器中。const-wide/16 vAA, #+BBBBA:
目标寄存器(8 位) B:
有符号整数(16 位)将给定的字面值(符号扩展为 64 位)移到指定的寄存器对中。const-wide/32 vAA, #+BBBBBBBBA:
目标寄存器(8 位) B:
有符号整数(32 位)将给定的字面值(符号扩展为 64 位)移到指定的寄存器对中。const-wide vAA, #+BBBBBBBBBBBBBBBBA:
目标寄存器(8 位) B:
任意双字宽度(64 位)常量将给定的字面值移到指定的寄存器对中。const-wide/high16 vAA, #+BBBB000000000000A:
目标寄存器(8 位) B:
有符号整数(16 位)将给定的字面值(右零扩展为 64 位)移到指定的寄存器对中。const-string vAA, string@BBBBA:
目标寄存器(8 位) B:
字符串索引将通过给定的索引获取的字符串引用移到指定的寄存器中。const-string/jumbo vAA, string@BBBBBBBBA:
目标寄存器(8 位) B:
字符串索引将通过给定的索引获取的字符串引用移到指定的寄存器中。const-class vAA, type@BBBBA:
目标寄存器(8 位) B:
类型索引将通过给定的索引获取的类引用移到指定的寄存器中。如果指定的类型是原始类型,则将存储对原始类型的退化类的引用。
强转指令
强转的语法比较简单,直接看官网截图:
除了常见的基本类型之间的强制转换,还有 neg
求补,not
求反,也同样适用这一语法。
加法指令
add-float/2addr v0, v1 // 将 v0 和 v1 中的值相加再存入 v0
加法指令还有一种三个参数的写法,如下所示:
add-float v0, v1, v2 // 将 v1 和 v2 中的值相加再存入 v0
这里的 float
可以替换为其他基本数据类型, add
也可以替换为其他数学运算操作。同样,还是用过官网截图来了解一下支持的运算语法:
一个加法延伸出来不少知识,看到这里,不知道你有没有一个疑问,想想最初的 java 源代码:
private float add() {int a = 1;float b = 1.5f;return a + b;
}
代码中定义了两个变量 a
和 b
,可是 smali 中的这两个变量呢?虚拟机中的编译器,不论是 JVM 还是 DVM,都会竭尽所能的在编译阶段对代码进行优化以提升运行速度。a
和 b
这两个变量在 add()
方法中并不是必须存在的,所以 DVM 不会浪费时间和空间再去申明这两个变量。如果变量 b
也是 int
类型的话,DVM 甚至连加法都会省略,直接返回 a+b
的数值,大家可以动手试一下。那么,如果在学习过程中想了解每一句代码的 smali 指令该怎么办呢?使用 IDEA
的 java2smali
插件,就不会存在这些优化了。
减法
源代码:
private double sub(){int a = 1;double b = 2.5;return a-b;}
Smali 代码:
.method private sub()D.registers 5.prologue.line 11const/4 v0, 0x1.line 12const-wide/high16 v2, 0x4004000000000000L # 2.5.line 13int-to-double v0, v0sub-double/2addr v0, v2return-wide v0
.end method
减法指令用 sub
表示。
另外这里要注意的是 const-wide
和 return-wide
,添加了 -wide
后缀的操作符表示的是 64
位数据类型。上面例子中定义了 double
类型常量,返回值也是 double
类型。
乘法
源代码:
private double mul(){float a = 1.5f;double b = 2;return a * b;}
Smali 代码:
.method private mul()D.registers 5.prologue.line 17const/high16 v0, 0x3fc00000 # 1.5f.line 18const-wide/high16 v2, 0x4000000000000000L # 2.0.line 19float-to-double v0, v0mul-double/2addr v0, v2return-wide v0
.end method
乘法指令用 mul
表示
除法
源代码:
private int div() {int a = 3;int b = 2;int c = a / b;return c;}
Smali 代码:
.method private div()I.registers 2.prologue.line 23.line 25const/4 v0, 0x1.line 26return v0
.end method
显然,编译器对这段代码进行了优化,提前计算了 3/2
,在 div()
方法中直接返回结果。我们在通过 java2smali
插件看一下未经优化的 Smali 代码:
.method private div()I.registers 4.prologue.line 28const/4 v0, 0x3.line 29.local v0, "a":Iconst/4 v1, 0x2.line 30.local v1, "b":Idiv-int v2, v0, v1.line 31.local v2, "c":Ireturn v2
.end method
可以看到除法指令用 div
表示
布尔运算
源代码:
private boolean bool(boolean a, boolean b,boolean c) {return a && b || c;}
Smali 代码:
.method private bool(ZZZ)Z.registers 5.prologue.line 35if-eqz p1, :cond_4 // 如果 p1 = 0, 跳至 cond_4 处if-nez p2, :cond_6 // 如果 p2 != 0,跳至 cond_6 处:cond_4if-eqz p3, :cond_8 // 如果 p3 = 0,跳至 cond_8 处:cond_6const/4 v0, 0x1 // 将 0x1 赋给 v0:goto_7return v0 // 返回 v0 的值:cond_8const/4 v0, 0x0 // 将 0x1 赋给 v0goto :goto_7 // 跳至 goto_7 处
.end method
布尔运算在 smali
中被转化为一系列的条件判断加指令跳转。上面例子中使用了两种跳转指令,if
判断之后的条件跳转和 goto
表示的无条件跳转,表示从当前地址跳转到指定的偏移处。条件判断指令在后面会具体罗列。
好像还没提到过参数寄存器,这里用到三个参数寄存器,p1
p2
p3
,再加上一个局部变量寄存器 v0
,看起来只用了四个寄存器,但是 .registers 5
却告诉我们这个方法用了五个寄存器,往上翻翻之前的 Smali 代码,你会发现,都无缘无故 “消失” 了一个寄存器。其实那是 p0
寄存器,函数被调用时会传入一个隐式的对当前对象的引用,存储在 p0
寄存器当中。
其他运算
源代码:
private void other(int a) {int or = a | 1;int and = a & 1;int right = a >> 2;int left = a << 2;int mod = a % 2;}
Smali 代码:
.method private other(I)V.registers 3.prologue.line 39or-int/lit8 v0, p1, 0x1.line 40and-int/lit8 v0, p1, 0x1.line 41shr-int/lit8 v0, p1, 0x2.line 42shl-int/lit8 v0, p1, 0x2.line 43rem-int/lit8 v0, p1, 0x2.line 44return-void
.end method
or
或 ,and
与 , shr
右移 , shl
左移 , rem
取模
条件判断
条件判断在之前的布尔运算中已经演示过,这里罗列一些具体的判断指令:
指令说明if-eq vA, vB, +CCCC如果 vA=vB,跳转指定偏移量if-nevA != vBif-ltvA < vBif-gevA >= vBif-gtvA > vBif-levA <= vBif-eqz vA, +BBBBvA = 0if-nezvA != 0if-ltzvA < 0if-gezvA >= 0if-gtzvA > 0if-lezvA <= 0
循环
源代码:
private void loop(){for (int i=0;i<10;i++){System.out.println(i);}}
Smali 代码:
.method private loop()V.registers 3.prologue.line 47const/4 v0, 0x0 // v0 = 0:goto_1const/16 v1, 0xa // v1 = 10if-ge v0, v1, :cond_d // 如果 v0 >= v1,跳至 cond_d 处.line 48sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream;invoke-virtual {v1, v0}, Ljava/io/PrintStream;->println(I)V.line 47add-int/lit8 v0, v0, 0x1 // v0++goto :goto_1 // 跳转至 goto_1 处.line 50:cond_dreturn-void
.end method
显然,循环也是通过条件判断和指令跳转来完成的。
本节中学习了 Smali 的数学运算,条件判断和循环的语法,也基本涵盖了大部分的 Smali 基本语法。下一篇学习 Smali 中类的用法。传送门 —— Smali 语法解析 —— 类
文中所有示例代码地址: https://github.com/lulululbj/android-reverse
文章同步更新于微信公众号:
秉心说
, 专注 Java 、 Android 原创知识分享,LeetCode 题解,欢迎关注!
smali to java_Smali —— 数学运算,条件判断,循环相关推荐
- Python教程学习简记1--Python数据类型和变量 字符串和编码 list和tuple 条件判断 循环 dict和set
本文主要是学习Python基础: Python数据类型和变量 字符串和编码 list和tuple 条件判断 循环 dict和set 本文根据廖雪峰的官方网站-Python教程,认真学习,一步一步实操并 ...
- python基础课程2(看代码看注释)--条件判断|循环|函数|生成器|类
##人生苦短,我用python ##课程内容 #条件判断 #循环 #类:简单介绍类的用法##条件判断 #if condiction:# dosomething #else: # dosomething ...
- Ansible 条件判断 循环 handlers 任务失败 文件管理的使用
文章目录 Ansible 条件判断 循环 handlers 任务失败 文件管理的使用 1.条件判断 1.1测试多个条件 1.2循环和有条件任务 2. handlers 3. 任务失败 3.1忽略任务失 ...
- VB.net:VB.net编程语言学习之操作符(变量/常量/数据类型/声明)逻辑控制语句(条件判断/循环语句)的简介、案例应用之详细攻略
VB.net:VB.net编程语言学习之操作符(变量/常量/数据类型/声明)&逻辑控制语句(条件判断/循环语句)的简介.案例应用之详细攻略 目录 VB.net编程语言学习之操作符/变量/常量/ ...
- Vue 模板语法 插值操作 绑定属性 计算属性 事件监听 条件判断 循环遍历 阶段案例
1 插值操作 1.1 Mustache语法 也就是双大括号 {{ }} <div id="app"> <!-- mustche语法中,不仅可以直接写变量,也可以写 ...
- Vue 事件绑定 事件修饰符 条件判断 循环遍历
事件绑定 v-on:事件 简写:@事件 <div id="app"><h2>{{counter}} </h2><button v-on:c ...
- java判断直到_3. JavaSE-位运算及判断循环程序结构的讲解
逻辑运算符用于连接两个boolean类型的值: & 与 |或 ^异或 ||短路或 &&短路与 !非(一元运算符) 位运算的运算符: &g ...
- Vue——基础(对象、属性样式操作、条件、循环、事件、绑定)
目录 vue对象 vue操作属性 vue操作样式 三元运算 条件渲染 循环语句 click事件 双向绑定数据 vue对象 1.创建: new Vue({ - }) 2.属性: 属性 描述 el 需要管 ...
- Sass学习笔记 -- 初步了解函数、运算、条件判断及循环
函数 sass定义了很多函数可供使用,当然你也可以自己定义函数,以@fuction开始.sass的官方函数链接为:sass fuction,实际项目中我们使用最多的应该是颜色函数,而颜色函数中又以li ...
最新文章
- NGINX、PHP-FPM开机自动启动
- 小学生python-小学生学python(五)
- python指定版本 安装模块包
- Nginx之让用户通过用户名密码认证访问web站点
- 多人编辑同一个md_多人协同编辑一份Word文档的正确姿势是这样的
- Laravel 怎么在 blade 视图中将带 HTML 字符原样输出
- NYOJ 496 巡回赛 拓扑排序
- Leetcode题库 6.Z字形变换(C实现)
- Symbian签名和Uid相关内容的整理(一)
- MacOS安装zsh插件zsh-autosuggestion(自动命令补全和建议)
- MySQL 创建触发器
- 省份,城市,地区------三级联动菜单//要加注释
- Cisco 3550配置DHCP实例
- 禁止minigui 3.0的屏幕保护
- 十天学会php之第九天
- 【总结】1334- JS中Object的keys是无序的吗
- 【Python】Pandas GroupBy 深度总结
- python web py入门(3)-模板
- ajax鼠标悬停,mouseout后触发jQuery Ajax鼠标悬停事件
- [附源码]java毕业设计医疗预约系统
热门文章
- 2022-2028年中国液体燃料行业市场研究及前瞻分析报告
- Codeforces 300E(数学)
- Codeforces Round 367 Div. 2
- bzoj 1040: [ZJOI2008]骑士 树形dp
- java arcengine_在Java程序中调用ArcEngine
- OpenCV+python:圆检测
- compser可以检查php扩展吗,composer扩展
- ip设置 kali 重置_在 Windows 系统中如何重置 TCP/IP 协议堆栈修复网络连接问题
- python规则网格插值_Python中规则网格上的插值
- matlab数据求加速度,通过从移动设备获取加速度数据对进行计步