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