smali語(yǔ)言還是相對(duì)純機(jī)器碼來(lái)說(shuō),比較容易理解的
--但最好是結(jié)合工具一起學(xué)--
--還可以參考其他的整理文章--
先來(lái)一個(gè)最簡(jiǎn)單的模型類

對(duì)應(yīng)的smali

(表格只是簡(jiǎn)單做一個(gè)映射關(guān)系的整理)
| java | smali | description |
|---|---|---|
| package | .class | 包名 |
| extends | .super | 父類名 |
| class | .source | 類名 |
| params | .field | 定義字段 |
| int | I | int類型 |
| Integer | Ljava/lang/Integer | Integer類型 |
| 引用類型 | Lxx/xx/xx | 該引用類型的完整包名 |
| boolean | Z | 布爾值 |
| byte | B | 字節(jié) |
| short | S | 短整型 |
| char | C | 字符 |
| long | J | 長(zhǎng)整型 |
| float | F | 浮點(diǎn)數(shù) |
| double | D | 浮點(diǎn)數(shù) |
| void | V | 無(wú) |
| 數(shù)組類型 | [ | 數(shù)組 |
| function | .method | 定義方法 |
| constructor | 構(gòu)造器方法 | |
| .prologue | 開始了 | |
| .registers | 申請(qǐng)寄存器的個(gè)數(shù),貌似不用關(guān)心這個(gè) | |
| .line x | 對(duì)應(yīng)源java文件行數(shù) |


func1括號(hào)里有Lxx/xx/xx說(shuō)明有形參,形參類型是String,也有返回值,返回值類型也是String
.param 指名 形參名 value
.prologue以下開始正式的代碼邏輯
.line 38 ,源碼38行的代碼
return-object 返回該對(duì)象的引用,其實(shí)就是把p0里的值返回來(lái)。
func2無(wú)形參,返回值類型String
const-string 聲明了一個(gè)String 類型的變量 ,值是 "abcdefg"
.local 說(shuō)是 指定了使用的局部變量的個(gè)數(shù),我這里簡(jiǎn)單的認(rèn)為,就是把v0給了一個(gè)局部變量 func2string


沒(méi)想到這么長(zhǎng)。
這里有點(diǎn)繞,根據(jù)


當(dāng)vB為0的時(shí)候

則直接翻譯smali為
L93-int類型形參num,放到寄存器p1
L96~L97-源碼47行,如果p1的值小于等于0,跳到cond_3
L99~L102-源碼49行,結(jié)束local寄存器p1,跳到goto_2,
返回p1的值
L104~L109-源碼48行,重開寄存器p1,cond_3 入口
如果p1的值 不等于0,跳到cond_7
否則(也就是p1等于0)把 0x0這個(gè)值給p1,然后跳到goto_2
L113~L115 -也就是源碼49行,cond_7入口,
neg-int對(duì)第一個(gè)p1進(jìn)行求補(bǔ),然后把值給第二個(gè)p1
L117~L118 -goto_2入口,end_method
是不是感覺(jué)和java代碼func3看起來(lái)不一樣?
我給自己的解釋是類似java內(nèi)存模型發(fā)生了重排序的優(yōu)化,也不知道對(duì)不對(duì),有大神知道的話評(píng)論區(qū)求解答。
不過(guò)回過(guò)頭來(lái)再看這個(gè)smali,
順序上雖然和源碼順序并不一致,但是按照直接翻譯的意思去寫java代碼
if( p1 <= 0){
if(p1 != 0)return -p1
else return 0
} else return p1
結(jié)果是一樣的。
再來(lái)一個(gè)


有了func3的翻譯經(jīng)驗(yàn)
func4就很好翻譯了
if-eqz p1,也就是形參num p1等于0的話,直接到cond_3,賦值0,最后返回。
其余的直接返回p1
if(p1 == 0)return 0
else return p1
這個(gè)優(yōu)化感覺(jué)更能說(shuō)服自己了,==操作比!=操作更簡(jiǎn)單
來(lái)一個(gè)switch跳轉(zhuǎn)



L145~L146-源碼59行,拿p1做switch(packed-switch關(guān)鍵字)偏移區(qū)pswitch_data_a
要看到底部
L174~L179-實(shí)際上只有兩個(gè)case需要做判斷 pswitch-6和pswitch-8(也就是兩個(gè)偏移區(qū))
L156~L163-pswitch_6,把0x0給v0,跳到goto_5
L165~L172-pswitch_8,把0x1給v0,跳到goto_5
L151~L154-goto_5入口把int型的本地(.local關(guān)鍵字)參數(shù)result指向寄存器v0,返回v0
其余的 把0x29a給v0
int result;
switch(p1){
case pswitch_6:
result = 0;
break;
case pswitch_8:
result = 1;
break;
default:
result = 0x29a;
break;
}
return result;
相當(dāng)于幫我優(yōu)化了case -1,因?yàn)閏ase -1和default都是同樣的處理方法
常用的加log打印信息的方法



那加入在有些情況下,調(diào)用Log.d,該類并沒(méi)有引入
android.util.Log包怎么辦?


放一個(gè)四哥的自定義代碼添加方案
以上筆記,僅供參考。