反編譯原理 5 控制流分析

2021-09-11 05:47:21 字數 4311 閱讀 7145

控制流結構恢復、變數和型別恢復是反編譯器中端向後端轉化最關鍵的兩個步驟,本文討論控制流結構恢復。

主要是概述鯨書「高階編譯器的設計與實現」第7章控制流分析,並且增加了一些內容,所涉及的相關**書籍自行查詢學習,還可以從維基百科了解學習。

可以從**"notes on graph algorithms used in optimizing compilers"了解學習

controlflowgraph(控制流程圖),basicblock(基本塊)、predecessor(前驅)、successor(後繼)、entry(入口)、exit(出口)等概念,大部分的編譯器控制流分析相關書籍**都有介紹這些內容,還有應該熟悉了解圖論中的有向圖的相關知識。

bfs(廣度優先搜尋)和dfs(深度優先搜尋)是圖論中的兩個概念,重點關注深度優先搜尋,深度優先搜尋有前序遍歷、中序遍歷、後序遍歷三種遍歷方法,前序遍歷和後序遍歷在控制流分析時是非常關鍵的兩種遍歷。大部分資料結構書籍中的圖論都有介紹這些內容。

如果從流圖的入口(entry)結點到結點d的每一條可能的路徑都經過結點n,稱n是d的必經結點,或者說d支配n;如果從流圖的結點d到出口(exit)結點的每一條可能的路徑都經過結點n,稱n是d的後必經結點,或者說d後支配n。一種有效的表示支配結點資訊的方法是用支配樹(dominator tree)表示,構建支配樹有靜態和動態兩種方法。

1.4.2 dynamic

主要有以下三種方法:

編譯器和反編譯器在控制流分析時,需要處理迴圈結構,迴圈結構最普遍的是流圖中的scc(強連通分量),大部分資料結構書籍中的圖論都有介紹scc(強連通分量)。

可歸約性是流圖的乙個非常重要的性質,假設對流圖進行若干變換,該變換將子圖蛻化為單個結點,歸約成更簡單的若干子圖,如果一系列的轉化最終能夠把流圖歸約成單個結點,則稱這個流圖是可歸約的。某些控制流模式會使得流圖不可約,大概有以下幾種方法處理不可約流圖:

由於歷史原因,區間分析region analysis也稱為interval analysis。區間分析將流圖劃分成各種型別的區域,使每乙個區域蛻化成乙個抽象節點,最終得到層次化、巢狀的抽象流圖,該流圖產生一棵控制樹。

區間分析或結構化分析只能處理sese(single-entry-single-exit)區間型別的流圖,pst/rpst就是構建只包含sese(single-entry-single-exit)區域型別的控制樹的一種方法

反編譯器進行控制流結構恢復時,所使用的演算法很多來自於編譯器的控制流分析。

反編譯器的控制流程圖比編譯器控制控制流程圖結點數量更多,分析時需要更多的時間和記憶體。早期llvm版本構建支配樹使用靜態方法lengauer-tarjan演算法,最新llvm版本構建支配樹已使用動態方法depth-based search演算法。

反編譯的不可歸約流圖比編譯器的不可約流圖數量和型別更多。

反編譯器的控制流分析有迭代控制流分析、區間分析和結構化分析三種方法。

2.4 iterative analysis

迭代分析主要有以下三種方法:

2.5 region analysis

區間分析比迭代分析更有效。

2.6 structural analysis

結構化分析是反編譯器控制流分析最主要的分析方法。

2.7 pst/rpst analysis

llvm的region analysis,也是sese(single-entry-single-exit)region analysis,原始碼注釋了說明其最基本的思路來自於pst/rpstllvm原始碼目錄lib/transform/scalar下的structurizecfg原始檔是演算法的具體實現,好像是來自早期llvm原始碼目錄lib/target/amdgpu下的amdgpumachinecfgstructurizer原始檔。

最新llvm原始碼目錄lib/target/amdgpu下的amdgpumachinecfgstructurizer原始檔演算法在編譯器後端實現,變得更加複雜。演算法大概思路是把if基本塊和else基本塊都轉化成if_then_else基本塊。

2.8 enhanced region structural analysis

傳統結構化分析的擴充套件,傳統結構化分析只能處理只包含sese(single-entry-single-exit)區域的流圖,擴充套件結構化分析新定義了sess(single-exit-single-successor)區域型別,好像能處理部分流圖是multi-exit區域型別的情況

2.9 normalized region structural analysis

因為區間分析或結構化分析只能處理只包含sese(single-entry-single-exit)區間型別的流程圖,因此需要把原來的控制流圖轉化成只包含sese (single-entry-single-exit)區間型別的流程圖,當前主要有以下兩種方法:

2.10 elimination

反編譯器的控制流分析,是結構化分析,是基於控制樹的控制流消去法,有些類似於資料流分析。

switch regions

switch regions 三種表現形式:位計算,跳轉表,if跳轉或二叉樹if跳轉。

控制流重建時主要考慮跳轉表,需要考慮兩種特殊的情況:case 塊沒有用break語句,直接fallthrough到下乙個case 塊;case 塊沒有用break語句,而是使用return語句。

return/finish regions

某一無環區域有多個return/finish(finish塊通常用於資源釋放),編譯優化後二進位制**可能會共用乙個return/finish塊,結構化分析時需要複製return/finish塊。

other regions

c++異常和c執行庫函式setjump()/longjump()所代表的區域,暫時不考慮。

2.10.3 structuring cyclic regions

有環區域極簡化和合併有兩種情況:第一種,有環區域loop和無環區域seq相互轉化;第二種,有環區域loop三種歸約型別的規則匹配:while、dowhile、for。

對於有環區域loop,需要考慮兩種特殊情況:第一種,前乙個區域是多個return/finish(multi-exit)區域,假設前乙個區域不進行複製return/finish塊,則結構化分析歸約後當前loop區域的if條件語句將帶有多個前乙個區域return/finish塊的前驅if condition條件語句的反轉not(condition)語句;第二種,當前loop迴圈體內部多個return/finish(multi-exit)區域。這兩種型別都會使得控制流重建後不可避免有goto語句,並且可讀性差,大部分的反編譯器是沒有考慮這種情況的,比如hex-rays decompiler就沒有考慮這種情況。

已經公布存在的閉源和開源反編譯器相關的**

主流的重新構建控制流圖的方法都是對控制流程圖進行結構化分析生成控制樹,然後嘗試將函式流程圖的可歸約的一小部分與已知模式匹配,並在不起作用時使用goto語句。

因此,反編譯二進位制程式時控制流結構恢復後goto語句的數量是衡量反編器表現的乙個重要標準。然而,**"no more gotos: decompilation using pattern-independent control-flow structuring and semantics-preserving transformations"開發了一種稱為模式無依賴的控制流結構分析新技術,它重新構建控制流圖時沒有使用任何預定義模式,控制流結構恢復後沒有goto語句。

綜上所述,實現沒有goto語句的c語言反編譯器是可能的,該反編譯器重建流圖的大概操作簡述如下:

編譯原理總結(《編譯與反編譯技術》)

詞法分析 語法將語義分析放到語法分析中 中間語言的表示與語法制導翻譯例項 符號表優化 目標 生成 目標 執行 什麼是編譯程式?把某一種高階語言程式等價的轉換成另一種低階語言程式的程式 編譯過程都包括哪些階段?詞法分析 語法分析 語義分析與中間 生成 中間 優化 目標 生成 畫出編譯程式的結構框圖.符...

控制流分析

控制流分析是資料流分析以及後端優化的基礎,其的目標是建立控制流圖 control flow graph 控制流圖的結點代表乙個基本塊 basic block 邊代表控制流的運動方向。基本塊 其中的 要麼全部執行,要麼全部不執行。基於這原則,有下列3種情況導致 分入不同的basic block中。1....

tcp流控制原理

流控制,又叫做流量控制。接收端在接收傳送端傳送的資料報的時候,如果是高負荷情況下就無法繼續接收資料,只能丟棄,丟棄後傳送端超時重傳,又加重了阻塞。所以,用tcp提供了流量控制機制。接收端向傳送端通知它可以接收資料的大小。於是傳送端就會傳送不抄過這個限度的資料,這個資料叫做視窗大小。tcp中有乙個字段...