LLVM編譯流程

  • LLVM概述

    LLVM是構架編譯器(compiler)的框架系統,以C++編寫而成,用於優化以任意程序語言編寫的程序的編譯時間(compile-time)連接時間(link-time)運行時間(run-time) 以及空閒時間(idle-time),對開發者保持開放,併兼容已有腳本。
  • 傳統編譯器設計

    圖片1.png
    編譯器不一樣於解釋器,解釋器能夠將高級語言邊轉譯邊執行。可是編譯器須要將全部的源代碼編譯成機器代碼以後,而後才能執行,因此如圖無論傳統的仍是LLVM都必定是源代碼輸入,輸出是機器代碼(也就是0101組合),中間還分前端優化器後端
    • 編譯器前端(Frontend)
      編譯器前端的任務是解析源代碼。它會進行:詞法分析語法分析語義分析, 檢查源代碼是否存在錯誤,而後構建抽象語法樹(Abstract Syntax Tree,AST) ,LLVM的前端還會生成中間代碼(intermediate representation , IR)。
    • 優化器(Optimizer)
      優化器負責進行各類優化。改善代碼的運行時間,例如消除冗餘計算等。
    • 後端(Backend) /代碼生成器(CodeGenerator)
      將代碼映射到目標指令集。生成機器語言,而且進行機器相關的代碼優化
    • iOS的編譯器架構
    圖片2.png Objective C/C/C++使用的編譯器前端是Clang, SwiftSwift,後端都是LLVM
  • LLVM的設計

    Image From LLVM(課件).png
    當編譯器決定支持多種源語言或多種硬件架構時,LLVM最重要的地方就來了。 其餘的編譯器如GCC,它方法很是成功,但因爲它是做爲總體應用程序設計的, 所以它們的用途受到了很大的限制。
    LLVM設計的最重要方面是,使用通用的代碼表示形式(IR),它是用來在編譯器中標識代碼的形式(其實就是一種中間代碼)。因此LLVM能夠爲任何變成語言獨立編寫前端,而且能夠爲任意硬件架構獨立編寫後端。
  • Clang

    ClangLLVM項目中的一個子項目。它是基於LLVM架構的輕量級編譯器,誕生之初是爲了替代GCC,提供更快的編譯速度。它是負責編譯C、C++、Objecte-C語言的編譯器,它屬於整個LLVM架構中的,編譯器前端。
  • 編譯流程

    首先簡單寫一個demo以下:
    #import <stdio.h>
     //#define C 30
    
     //typedef int TD_INT_64;
    
     int test(int a,int b){
         return a + b + 3;
     }
    
     int main(int argc, const char * argv[]) {
         int a = test(1, 2);
         printf("%d",a);
         return 0;
     }
    複製代碼
    • 經過命令打印查看源碼的編譯階段
      命令:clang -ccc-print-phases main.m image.png 能夠發現主要分6個步驟
      • 0:輸入文件:找到源文件。
      • 1:預處理階段:這個過程處理包括宏的替換,頭文件的導入。
      • 2:編譯階段:進行詞法分析、語法分析、檢測語法是否正確,最終生成IR。
      • 3:後端:這裏LLVM會經過一個一個的Pass去優化,每一個Pass作一些事情,最終生成彙編代碼。
      • 4:生成目標文件。
      • 5:連接:連接須要的動態庫和靜態庫,生成可執行文件。
      • 6:經過不一樣的架構,生成對應的可執行文件。
    • 預處理階段
      命令:clang -E main.m
      image.png image.png 宏在預處理階段會被替換掉,typedef不會被替換掉,因此通常爲了安全可使用,作代碼混淆
    • 編譯階段
      • 詞法分析
        預處理完成後就會進行詞法分析.這裏會把代碼切成一個個Token,好比大小括 號,等於號還有字符串等
        命令: clang -fmodules -fsyntax-only -Xclang -dump-tokens main.m image.png 注:若是頭文件找不到能夠指定sdk
        clang -isysroot (本身SDK路徑) -fmodules -fsyntax-only -Xclang -dump-tokens main.m
        clang -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator14.1.sdk/ -fmodules -fsyntax-only -Xclang -dump-tokens main.m
      • 語法分析
        詞法分析完成以後就是語法分析,它的任務是驗證語法是否正確。在詞法分析的基礎上將單詞序列組合成各種語法短語,如「程序」,「語句」,「表達式」等等,而後將全部節點組成抽象語法樹(Abstract Syntax Tree, AST)。語法分析程序判斷源程序在結構上是否正確。
        命令: clang -fmodules -fsyntax-only -Xclang -ast-dump main.m image.png
        • FunctionDecl 函數
        • ParmVarDecl 參數
        • CallExpr 調用一個函數
        • BinaryOperator 運算符
      • 生成中間代碼IR
        完成以上步驟後就開始生成中間代碼IR了,代碼生成器(Code Generation)會將語法樹自頂向下遍歷逐步翻譯成LLVM IR。經過下面命令能夠生成.11的文本文件,查看IR代碼。
        命令:clang -S -fobjc-arc -emit-llvm main.m
        Objective C代碼在這一步會進行runtime的橋接:property合成,ARC處理等
        IR的基本語法:
        • @ 全局標識
        • % 局部標識
        • alloca 開闢空間
        • align 內存對齊
        • i32 32個bit, 4個字節
        • store 寫入內存
        • load 讀取數據
        • call 調用函數
        • ret 返回
        image.png IR優化:
        LLVM的優化級別分別是-O0 -O1 -O2 -O3 -Os(第一個是大寫英文字母O)
        優化命令:clang -Os -S -fobjc-arc -emit-llvm main.m -o main.ll 通常設置是在target - Build Setting - Optimization Level(優化器等級)中設置 image.png Debug狀況下默認是不優化,Release狀況下默認Fastest、Smallest
        優化後的代碼image.png
      • bitCode
        xcode7之後開啓bitcode蘋果會作進一步的優化。生成.be的中間代碼。 咱們經過優化後的IR代碼生成.be代碼
        命令:clang -emit-llvm -c main.ll -o main.bc
      • 生成彙編代碼
        最終經過.be或者.ll代碼生成彙編代碼
        命令:
        clang -S -fobjc-arc main.bc -o main.s
        clang -S -fobjc-arc main.ll -o main.s
        image.png 固然生成的彙編代碼也能夠進行優化(注意若是生成IR代碼已經作過優化了此時在優化不會再起做用)
        命令:clang -Os -S -fobjc-arc main.m -o main.s
      • 生成目標文件(彙編器)
        目標文件的生成,是彙編器以彙編代碼做爲輸入,將彙編代碼轉換爲機器代碼, 最後輸出目標文件(object file)
        命令: clang -fmodules -c main.s -o main.o image.png能夠發現是個Mach-O文件
        經過nm命令,查看下main.o中的符號
        命令: xcrun nm -nm main.o image.png發現找不到_printf這個方法,應爲_printf是從外部的庫引入
      • 生成可執行文件(連接)
        鏈接器把編譯產生的.o文件和(.dylib .a)文件,生成一個mach-o文件。
        命令:clang main.o -o main image.png 發現此時是一個可執行的Mach-O文件
        再查看連接以後的符號
        image.png應爲OC的特性運行時,動態庫實在運行時須要使用的時候再加載到內存的,因此編一階段找不到對應的方法
  • LLVM編譯流程圖

    未命名文件(33).jpg
相關文章
相關標籤/搜索