有關LLVM(https://github.com/yejinlei/about-compiler)

一、Clang

clang分三個實體概念:

  • clang驅動:利用現有OS、編譯環境以及參數選項來驅動整個編譯過程的工具。
  • clang編譯器:利用clang前端組件及庫打造的編譯器,其入口為cc1_main; 參數為clang -cc1 或者 -Xclang;

  • clang前端組件及庫:包括Support、Basic、Diagnostics、Preprocessor、Lexer、Sema、CodeGen等;

二、clang前端組件及庫

三、clang編譯器架構

3.1 編譯器選項(clang -cc1 -help,CC1Options.td中定義)

選項 說明 FrontendAction子類 ASTConsumer子類 備註

  • -init-only | | InitOnlyAction | | 只做前端初始化

  • -Eonly | 預處理 | PreprocessOnlyAction | | 只做預處理,不輸出

  • -E | 預處理 | PrintPreprocessedAction | | 子選項還包括-P、-C、-dM、-dD具體查看PreprocessorOutputOptions類

  • -dump-tokens | 列印token | DumpTokensAction | | 輸出tokens

  • -dump-raw-tokens | 列印tokens | DumpRawTokensAction | | 輸出原始tokens,包括空格符

  • -rewrite-test | 測試宏定義處理 | RewriteTestAction | | 類似-rewrite-macros,僅測試用

-rewrite-macros | 處理並擴展宏定義 | RewriteMacrosAction | |

  • -emit-html | 生成高亮的代碼網頁 | HTMLPrintAction | HTMLPrinter |

  • -print-decl-contexts | 列印聲明 | DeclContextPrintAction | DeclContextPrinter |

  • -ast-list | 列印ast節點 | ASTDeclListAction | ASTDeclNodeLister | clang -S -D_WIN32 -Xclang -ast-list hello.c

  • -ast-dump | 列印ast詳細信息 | ASTDumpAction | ASTPrinter |

  • -ast-view | 生成ast dot | ASTViewAction | ASTViewer |

  • -analyze | 運行靜態分析引擎 | AnalysisAction | AnalysisConsumer | clang -cc1 -analyzer-checker-help顯示所有checkers;

    ,具體請看《clang靜態分析器》
  • -emit-llvm | 生成.ll IR彙編文件 | EmitLLVMAction | BackendConsumer | clang -S -D_WIN32 -Xclang -emit-llvm hello.c -o hello.ll
  • -emit-llvm-bc | 生成.bc IR二進位文件 | EmitBCAction | BackendConsumer | clang -S -D_WIN32 -Xclang -emit-llvm-bc hello.c -o hello.bc

備註:

1. FrontendAction及其子類主要是前端功能的集合,不同的子類包含的功能不同;

2. ASTConsumer及其子類主要是後端功能的集合,不同的子類包含的功能不同;

3. 編譯器選項表格中基本上按功能從小到大排列;

3.2 clang架構圖

3.3 clang流程分析

備註:

通過clang編譯器選項,來選擇創建不同的FrontendAction,具體在createFrontendBaseAction函數中,創建不同的FrontendAction對象

  1. FrontendAction::CreateASTConsumer用於創建不同ASTConsumer對象,因此需實現該函數;
  2. FrontendAction::ExecuteAction用於銜接後端,例如ASTFrontendAction::ExecuteAction調用ParseAST解析語法樹並傳遞給後端,而DumpRawTokensAction只列印tokens;
  3. 需要抽象語法樹的後端,需要調用ParseAST函數;

3.4 clang靜態分析器

按功能區分的選項(clang -cc1 -analyzer-checker-help,Checkers.td中定義)

選項 | 說明 | 備註 -analyzer-checker=debug | |

  1. Clang Static Analyzer就是利用不同的checker來檢測源碼不同類型的bug的。

  2. 靜態分析器會默認使用6類checkers(default checker):

    • Core Checkers:提供一些一般性的檢查,比如是否被0除、是否使用空指針和使用未初始化參數等。
    • C++ Checkers:提供C++檢查。
    • Dead Code Checkers:檢查沒有使用的代碼。
    • OS X Checkers:檢查Objective-C和Apples SDKs的使用情況。
    • Security Checkers:檢查不安全API的使用和基於CERT Secure Coding Standards的檢查。
    • Unix Checkers:檢查Unix和POSIX API的使用情況。
  3. 主要流程

  4. CheckerManager
  5. CheckerContext上下文

    1. addTransition方法,改變狀態
    2. generateSink
  6. ProgramPoint程序關鍵點(等同checker類成員函數、回調函數)

    • [check::PreStmt] - 在statement xxx發生之前調用這個checker
    • [check::PostStmt] - 在statement xxx發生之後調用這個checker
    • [check::PreCall] - 在函數調用之前調用這個checker
    • [check::EndFunction] - 在函數結束時調用這個checker
    • [check::BranchCondition] - 在分支出現時調用這個checker
    • [check::DeadSymbols] - 當參數超出生命周期時調用這個checker
    • checker的回調函數要麼修改程序狀態,要麼報告bug

7. ProgramState表示程序所在狀態

    • Clang Static Analyzer就像其他靜態分析工具一樣,並不會執行源代碼,而是象徵性的執行代碼(symbolic excution),並且會執行代碼中的每一個分支(Path Sensitive)。
    • 在「執行」過程中,Analyzer會實時的根據運行情況追蹤和改變程序狀態(Program State)。
    • 註冊狀態宏:REGISTERTRAITWITHPROGRAMSTATE、REGISTERMAPWITHPROGRAMSTATE、REGISTERSETWITHPROGRAMSTATE、REGISTERLISTWITHPROGRAMSTATE
    • CheckerContext類包含了一些操作狀態的函數,例如獲取狀態getState(),更改狀態addTransition(State)、產生sink節點generateSink(),上報BUG EmitReport(BUG)
    • 節點類ExplodedNode、BUG類BugReport、狀態類ProgramState

8. 如何編寫Checker

兩種編寫Checker方式:一、一種直接編譯進clang編譯器中;二、生成共享庫,由clang編譯器動態載入

方式一

    • 在lib/StaticAnalyzer/Checkers目錄下,創建xxxxChecker.cpp
    • xxxxChecker.cpp編寫Checke子類和註冊函數: using namespace clang; using namespace ento;
  1. }

  • namespace { class NewChecker: public Checker< check::PreStmt<CallExpr> > { public: void checkPreStmt(const CallExpr *CE, CheckerContext &Ctx) const {} }}void ento::registerxxxx(CheckerManager &mgr) { mgr.registerChecker<xxxx>();

    • clang/lib/StaticAnalyzer/Checkers/Checkers.td註冊Checker歸屬關係,例如alpha.core.yyyy

    let ParentPackage = CoreAlpha in {...def xxxxChecker : Checker<"yyyy">, //注意yyyy,任意名字 HelpText<"Checker功能表述">, DescFile<"xxxxChecker.cpp">;...} // end "alpha.core"

    方式二

      • 具體參考「SampleAnalyzerPlugin」例子

    四、clang驅動

    4.1 驅動選項(clang -help,Options.td定義)

    • -cc1,clang編譯器
    • -###,列印clang driver Parse階段命令行參數,參考:[Driver Design & Internals](Driver Design & Internals)
    • -ccc-print-phases,列印clang driver Pipeline階段信息

    • -ccc-print-bindings,列印clang driver Bind階段各工具鏈及輸入輸出文件

    • -E,預處理

    • -S,預處理~彙編

    • -c,預處理~生成obj

    • -fcolor-diagnostics,診斷色彩

    • -driver-mode=cl,等同於clang-cl,兼容VC
    • -emit-llvm,生成.ll中間語言文件
    • -fpack-struct=1 or n,壓縮

    • -Wunused-variable,未初始化

      4.2 驅動流程分析


    推薦閱讀:

    llvm memcpy的本質?
    LLVM每日談之七 Clang
    LLVM國內的開發者需要Social一下嗎?
    [Debug] Clang / LLVM 關於continue語句的二三事

    TAG:Clang | LLVM | 编译器 |