在學(xué)習(xí) Andorid 逆向的過程中,發(fā)現(xiàn)無論是哪種編譯器,生成哪個平臺的代碼,其優(yōu)化思路在本質(zhì)上如出一轍,在 Windwos 平臺所使用的技巧,在安卓平臺仍然適用,不外乎乘法除法計算的優(yōu)化,swtich 判定樹的優(yōu)化,對 if 條件句的優(yōu)化,while 循環(huán)的優(yōu)化等等,編寫本文的目的也就是為了對已學(xué)的知識進(jìn)行總結(jié)。
這里強(qiáng)烈推薦老錢和老張寫的《C++反匯編與逆向分析技術(shù)揭秘》,本文大部分知識點(diǎn)都將以此書作為參考,我個人是不太喜歡看直播和視屏教程的,因?yàn)橛行╆P(guān)鍵知識點(diǎn)可能老師一句話就帶過去了,要想回來看還得來回拉進(jìn)度條,但是書不一樣,遇到讀不懂的地方可以停下來仔細(xì)思考,想回頭看也就是翻幾頁的事情,遇到那種寫的特別細(xì)的作者,那讀起來更是一種享受。
本文列舉的代碼和匯編只是為了更好的說明思路,并不代表實(shí)際代碼,好了話不多說,進(jìn)入正題。
優(yōu)化方向
- 編譯速度優(yōu)化
- 執(zhí)行速度優(yōu)化
- 程序體積優(yōu)化
對于 Debug 版程序,編譯器為了滿足單步調(diào)試需求,不會對無意義的代碼進(jìn)行優(yōu)化。無意義的意思是沒有發(fā)生傳遞,沒有賦值到內(nèi)存空間。
一
常見的優(yōu)化類型
常量折疊
更像是預(yù)處理,編譯器會將所有可預(yù)見的值直接寫成立即數(shù)。
int n = 2 + 3 * 6;
// 編譯器在處理這段代碼時會直接將變量賦予立即數(shù)+
// mov n, 20
常量傳播
是常量折疊的“進(jìn)階版”,編譯器會掃描整個代碼段,對所有非變量運(yùn)算直接計算出結(jié)果。
int n = 2 + 3 * 6;
int m = n * 10;
// mov m, 200
減少變量
未使用即是無意義,無意義的代碼都會被優(yōu)化,上述的兩個示例,在實(shí)際編譯中是會直接被優(yōu)化掉的,因?yàn)椴⑽幢挥糜诤瘮?shù)傳參和其他操作。
編譯雖然能通過,但不會產(chǎn)生任何代碼,因?yàn)闆]有傳遞結(jié)果,對后續(xù)的代碼執(zhí)行不會造成任何影響。
int funtion1() {
int n = 2 + 3 * 6;
int m = n * 10;
return 0;
}
// 無意義的變量,這個函數(shù)被編譯為匯編也將只有一句代碼
// mov eax, 0
int funtion2() {
int n = 2 + 3 * 6;
int m = n * 10;
return m;
}
// 有意義的變量,但因?yàn)槌A總鞑ィ仓挥幸痪浯a
// mov eax, 200
## 分支優(yōu)化
對于所有不可達(dá)的分支也會直接被裁剪。
if(false) {
printf("you can't find me");
}
在書中還有更多優(yōu)化示例,這里不做過多列舉,其根本就是以上幾種優(yōu)化方式,無意義的代碼將被刪除,冗余的代碼將會被精簡,照著這種思路想就對了。得益于編譯器的強(qiáng)大,使得再爛的代碼也能保持高效。
二
數(shù)學(xué)計算上對算法的優(yōu)化
我將會穿插使用 x86 和 arm 匯編,主要指令都大差不差,理解意義即可。
加法
加法沒有任何優(yōu)化空間,一個 add 指令所需的 cpu 周期本就很短,除了上述的常量折疊外,一般不會對其進(jìn)行改動。
減法
理論上加法和減法的指令周期是一致的,也不排除有些編譯器會將減數(shù)轉(zhuǎn)成補(bǔ)碼進(jìn)行相加,遇到補(bǔ)碼也能一眼看出來,直接就可以認(rèn)定這條指令為減法。
乘法
-
代碼
+關(guān)注
關(guān)注
30文章
4779瀏覽量
68521 -
編譯器
+關(guān)注
關(guān)注
1文章
1623瀏覽量
49108 -
Andorid
+關(guān)注
關(guān)注
0文章
7瀏覽量
6989
發(fā)布評論請先 登錄
相關(guān)推薦
評論