Ollvm整合到XCode中的幾種方法

我是去年10月左右開始研究Ollvm,現將一部分心得分享出來

基本概念

LLVM Pass按加載方式分類:

  • 靜態Pass,即將Pass邏輯編譯到clang/opt中,通過給clang/opt傳遞適當參數觸發Pass。如果目標語言和編譯環境不支持命令行方式指定Pass則可嘗試此方式。目前大部分開源Ollvm項目都是此種方式,且一定程度修改了LLVM源碼部分
  • 動態Pass,即將Pass邏輯編譯為獨立動態庫,通過給clang/opt傳遞適當參數觸發Pass。如果目標語言和編譯環境不方便使用自定義clang/opt但支持命令行方式指定動態Pass則可嘗試此方式,此方式在Pass開發編譯調試時優勢明顯。

常見問題

  • 動態PassLLVM版本要匹配嗎?是的,至少大版本要匹配否則大概率崩
  • 開發動態PassXCode使用以實現Ollvm混淆的思路可行嗎?可行
  • 直接針對XCodeApple Clang開發動態Pass可行嗎?可行

XCode使用Pass的方式(以下方式筆者均驗證過可行)

  • 靜態Pass方式1,編譯為XCode Toolchain,也是目前大部分開源Ollvm項目所采用的方式。不過編譯時間久一些且Toolchain占用的存儲空間也大一些。
  • 靜態Pass方式2,直接使用clang,在Xcode中指定CC變量為內嵌Passclang。如果isysroot不兼容可能需要在Other C Flags中覆蓋
  • 動態Pass方式3,在Xcode中指定CC變量為開源clang(如brew install llvm@15),且指定Other C Flags指定-fpass-plugin為對應Pass路徑
  • 動態Pass方式4,在Xcode中指定CC變量為編譯腳本,腳本邏輯為"先用clang -emit-llvm參數生成bitcode,然后運行opt執行Pass,最后用clang -c生成原本要生成的obj文件"。此種方式可以直接使用Xcode自帶的Apple clang,能比較好的兼容arm64e架構
  • 動態Pass方式5,直接針對Xcode自帶的Apple clang開發動態Pass,在Xcode中指定Other C Flags指定-fpass-plugin為Pass路徑。此種方式復雜度較高,只適合精通llvm編譯的開發者。此種方式可以直接使用Xcode自帶的Apple clang,能比較好的兼容arm64e架構

針對AppleClang開發動態Pass

現在來看看最難的部分,如果直接使用AppleClang對應版本的開源LLVM開發Pass給AppleClang使用是會崩潰的,因為AppleClang相對于開源LLVM魔改了很多地方。為了讓AppleClang能運行起來一個最簡單的Pass你至少需要如下hacker代碼:

class Ollvm : public PassInfoMixin<Ollvm> {
public:
    PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM) {
        M.dump();
#ifdef APPLE_CLANG
        static PreservedAnalyses (*PreservedAnalyses__all)() = 0;
        static PreservedAnalyses (*PreservedAnalyses__none)() = 0;
        if (PreservedAnalyses__all == 0) {
            const char* image = _dyld_get_image_name(0);
            PreservedAnalyses__all = (__typeof(PreservedAnalyses__all)) DobbySymbolResolver(image, 
                "__ZN4llvm6detail9PassModelINS_6ModuleEN12_GLOBAL__N_114NoOpModulePassENS_17PreservedAnalysesENS_15AnalysisManagerIS2_JEEEJEE3runERS2_RS7_");
            PreservedAnalyses__none = (__typeof(PreservedAnalyses__none))DobbySymbolResolver(image, 
                "__ZN4llvm6detail9PassModelINS_6ModuleENS_25InvalidateAllAnalysesPassENS_17PreservedAnalysesENS_15AnalysisManagerIS2_JEEEJEE3runERS2_RS6_");
        }
        return (opc > 0) ? PreservedAnalyses__all() : PreservedAnalyses__none();
#else
        return (opc > 0) ? PreservedAnalyses::all() : PreservedAnalyses::none();
#endif
    };
    static bool isRequired() { return true; }
};

以上操作僅僅是讓你“入門”,而下一步就是處理AppleClang魔改造成的沖突,包括但不限于拆分靜態庫/自行實現沖突代碼,也是個復雜且麻煩的工程了,有興趣的可以接著研究下去

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。