• 沒有找到結果。

第二章、 背景知識

2.4. 編譯細節

編譯過程包括語彙分析、語法分析、語意分析、中介語言產生以及目的碼最佳 化及產生,大致流程如圖9。

圖 9、程式編譯流程[28]

2.4.1. 語彙分析

如圖 9 所示,原始碼 (source code) 先透過掃描器 (Scanner) 進行語彙分析 (lexical analysis),並運用類似有限狀態機(Finite State Machine) 的演算法,將原 始碼的字元順序切割成記號 (Token)。詞法分析產生的記號一般可被分類為幾 類:關鍵字、識別字、字面量(literal,包含數字、字串等) 和特殊符號(如加 號、等號)。

2.4.2. 語法分析

語法分析(Grammar Parser) 將對記號行分析,進而產生語法樹(Syntax Tree)。分 析過程採用上下文無關語法(Context-free Grammar) 的分析方法。語法樹是以運

16

算式(Expression) 為節點的樹,例如 C 語言的一個語句就是一個運算式,而複 雜的語句就是很多運算式的組合。

2.4.3. 語意分析

語意分析(Semantic Analysis) 由語意分析器(Semantic Analyzer) 完成,與法分析 僅是完成對運算式與法層面的分析,但並不了解其真正的意義。如C 語言中兩 個指標做除法是無意義的,但是這個語句在語法上是合法的。編譯器所能夠分 析的語意是靜態語意(Static Semantic),是指在編譯階段(Compile time)可以確定 的語意,相對應的是動態語意 (Dynamic Semantic) 就是只有在運行階段

在編譯器中往往有多層次的最佳化過程,原始碼最佳化器(Source Code

Optimizer) 會在原始法的層級進行最佳化,如 Copy Propagation 會將除去純粹 的傳遞數值變數,取而代之的是原本的數值; Code Folding 將具有確定性的運算 式計算出確切的值並且取代原本的運算式; Dead Code Elimination 移除對程式執 行結果並無任何影響的程式碼,等最佳化方法。

前一段所描述的最佳化方法在語法樹上應用相較困難,所以原始碼最佳化 器往往會將整個語法樹轉換成中介碼 (IR, Intermediate Representation),他是語 法樹的順序表示,通常與機器和執行環境無關 (Target-Independent)。中介碼有

17

很多類型,常見的有:三位址碼 (Three-address Code) 和虛擬碼 (Pseudo Code)。

2.4.5. 目的碼的產生與最佳化

原始碼最佳化產生器所產生的中介碼標示著之後的過程都屬於編譯器後端。編 譯器後端主要包括程式碼產生器(Code Generator)、目的碼最佳化器 (Target Code Optimizer)。程式碼產生器將中介碼轉換成目的碼的整個過程,非常的倚 賴目的機器,因為不同的機器有著不同長度的暫存器、整數資料類型等。最後 目的碼最佳化器對目的碼進行最佳化,如選擇適當的定址方式、使用位移來替 代乘法運算等等。

18

本論文選擇使用前端Clang[33]加上後端底層虛擬機( Low Level Virtual Machine, LLVM) [34]的組合來實作緩解措施,而非目前主流 Linux 所使用的 GCC。雖 然其三段式架構前端(Frontend)、最佳化器(Optimizer)、後端(Backend) 與 GCC 並相差無幾,但 LLVM 的設計也包含了最佳化階段的整合,你不只可以將自己 的Pass 加入編譯,也可以同時使用 LLVM 所提供的 Pass,與 GCC 不同的是 LLVM 同時也是一個編譯器開發框架 (Framework)。Clang 加上 LLVM 的組合 也於2010 年達到了 Self-hosting。同時 LLVM 也是眾多編譯器安全解決方法實 作的首選[35][36][37]。

3.2. 緩解時機的選擇

從第二章的介紹可以知道,一般來說可以很簡單的將編譯拆分成三個部分:前 端、IR 層及後端,想要在前端的部分修改程式原始碼來達到安全的目的,只能 透過類似FORTITY_SOURCE 的作法實作在巨集展開階段,或者是使用語法樹 來做分析。但是如前一章節所述,語法樹其實不容易被用於分析,所以才會使 用IR 來進行最佳化的操作,但礙於在 IR 層並不能肆意的執行插入任意組合語

相關文件