feature: dyld && LD 链接器

This commit is contained in:
杭城小刘
2024-06-29 16:00:34 +08:00
parent 1a8659e143
commit 13f7457be9
367 changed files with 12893 additions and 3049 deletions

View File

@@ -10,7 +10,7 @@ LLVM 不是 low level virtual machine 的缩写,就是项目名称。
## 结构
![](https://github.com/FantasticLBP/knowledge-kit/raw/master/assets/LLVM-segment.png)
![](./../assets/LLVM-segment.png)
LLVM 由三部分构成:
@@ -22,7 +22,7 @@ LLVM 由三部分构成:
![](https://github.com/FantasticLBP/knowledge-kit/raw/master/assets/LLVM-Structure.png)
![](./../assets/LLVM-Structure.png)
正是由于这样的设计,使得 LLVM 具备很多有点:
@@ -42,7 +42,7 @@ LLVM 现在被作为实现各种静态和运行时编译语言的通用基础结
广义上来讲LLVM 说的是一种架构。狭义上来讲LLVM 强调的是偏后端部分,如下图的除了 clang 编译前端外的部分,包括优化器和编译后端,统称为 LLVM 后端。
<img src="https://github.com/FantasticLBP/knowledge-kit/raw/master/assets/LLVMFullStructure.png" style="zoom:45%">
<img src="./../assets/LLVMFullStructure.png" style="zoom:45%">
@@ -64,7 +64,7 @@ Clang 相较于 GCC具备下面优点
- 设计清晰简单,容易理解,易于扩展增强
![](https://github.com/FantasticLBP/knowledge-kit/raw/master/assets/LLVM-phase.png)
![](./../assets/LLVM-phase.png)
@@ -92,7 +92,7 @@ clang -ccc-print-phases main.m
展示如下:
<img src="https://github.com/FantasticLBP/knowledge-kit/raw/master/assets/LLVMDisplayPhases.png" style="zoom:45%">
<img src="./../assets/LLVMDisplayPhases.png" style="zoom:45%">
@@ -104,7 +104,7 @@ clang -ccc-print-phases main.m
查看 preprocessor (预处理)的结果:`clang -E main.m`。预处理主要做的事情就是头文件导入( include、import、宏定义替换等。展示如下
<img src="https://github.com/FantasticLBP/knowledge-kit/raw/master/assets/LLVMPreProcessorPhase.png" style="zoom:35%">
<img src="./../assets/LLVMPreProcessorPhase.png" style="zoom:35%">
@@ -112,7 +112,7 @@ clang -ccc-print-phases main.m
词法分析阶段,主要生成 Token。使用指令 `clang -fmodules -E -Xclang -dump-tokens main.m` 查看具体做了什么
<img src="https://github.com/FantasticLBP/knowledge-kit/raw/master/assets/LLVMAnalysize.png" style="zoom:35%">
<img src="./../assets/LLVMAnalysize.png" style="zoom:35%">
@@ -120,7 +120,7 @@ clang -ccc-print-phases main.m
语法分析阶段生成语法树ASTAbstract Syntax Tree。使用指令 `clang -fmodules -fsyntax-only -Xclang -ast-dump main.m` 查看
<img src="https://github.com/FantasticLBP/knowledge-kit/raw/master/assets/LLVMASTAnalysis.png" style="zoom:35%">
<img src="./../assets/LLVMASTAnalysis.png" style="zoom:35%">
对 main.m 的代码进行改造
@@ -142,7 +142,7 @@ void test(int a, int b) {
再次查看 AST 可以加深理解
<img src="https://github.com/FantasticLBP/knowledge-kit/raw/master/assets/LLVMASTAnalysis2.png" style="zoom:35%">
<img src="./../assets/LLVMASTAnalysis2.png" style="zoom:35%">
其中:
@@ -154,7 +154,7 @@ void test(int a, int b) {
也就是先运算蓝色框内的值,然后用结果和红色框内的进行相减。所以这是很标准的树形结构。
<img src="https://github.com/FantasticLBP/knowledge-kit/raw/master/assets/LLVMASTTreeDemo.png" style="zoom:10%">
<img src="./../assets/LLVMASTTreeDemo.png" style="zoom:10%">
@@ -171,7 +171,7 @@ LLVM IR 有3种表示格式
- text便于阅读的文本格式类似于汇编语言推展名为 `.ll`。使用指令 `clang -S -emit-llvm main.m` 进行转换
<img src="https://github.com/FantasticLBP/knowledge-kit/raw/master/assets/LLVMIRType1.png" style="zoom:30%">
<img src="./../assets/LLVMIRType1.png" style="zoom:30%">
学过 arm64 汇编的话看这段 IR 很眼熟,汇编里 `load` 相关的指令都是从内存中装载数据,比如 `ldr`、`ldur` 、`ldp`。`store` 相关的指令是往内存中写入数据,比如 `str`、 `stur`、 `stp`
@@ -304,9 +304,9 @@ Tipsninja 如果安装失败,可以直接从 [github]( https://github.com/n
因为要编写 Clang 插件,是 c++ 代码,所以需要借助 IDE 的能力,我们选用 Xcode 进行编译。如下图所示,代表编译成功
<img src="https://github.com/FantasticLBP/knowledge-kit/raw/master/assets/LLVMComplieXcode1.png" style="zoom:20%">
<img src="./../assets/LLVMComplieXcode1.png" style="zoom:20%">
<img src="https://github.com/FantasticLBP/knowledge-kit/raw/master/assets/LLVMComplieXcode2.png" style="zoom:20%">
<img src="./../assets/LLVMComplieXcode2.png" style="zoom:20%">
@@ -334,11 +334,11 @@ Tipsninja 如果安装失败,可以直接从 [github]( https://github.com/n
- 先创建一个插件文件夹 `code-style-validate-plugin`
<img src="https://github.com/FantasticLBP/knowledge-kit/raw/master/assets/LLVMAddConfiguration1.png" style="zoom:20%">
<img src="./../assets/LLVMAddConfiguration1.png" style="zoom:20%">
- 编辑 `CMakeLists.txt` 文件,在最后添加 `add_clang_subdirectory(code-style-validate-plugin)`
<img src="https://github.com/FantasticLBP/knowledge-kit/raw/master/assets/LLVMAddConfiguration2.png" style="zoom:20%">
<img src="./../assets/LLVMAddConfiguration2.png" style="zoom:20%">
@@ -367,17 +367,17 @@ Xcode 打开项目,选择自动创建 Schemes
<img src="https://github.com/FantasticLBP/knowledge-kit/raw/master/assets/XcodeOpenLLVMProject.png" style="zoom:30%">
<img src="./../assets/XcodeOpenLLVMProject.png" style="zoom:30%">
选择 Target 为 `CodeStyleValidatePlugin`,源代码所在文件夹为 `Sources/Loadable modules`,然后选中 CodeStyleValidatePlugin.cpp` 文件进行编写逻辑
<img src="https://github.com/FantasticLBP/knowledge-kit/raw/master/assets/ClangPluginSourceCode.png" style="zoom:20%">
<img src="./../assets/ClangPluginSourceCode.png" style="zoom:20%">
初步编写后 Command + B 进行编译,在 Products 下可以看到编译产物:`CodeStyleValidatePlugin.dylib` 动态库。
<img src="https://github.com/FantasticLBP/knowledge-kit/raw/master/assets/ClangCompileProducts.png" style="zoom:20%">
<img src="./../assets/ClangCompileProducts.png" style="zoom:20%">
@@ -387,7 +387,7 @@ Xcode 打开项目,选择自动创建 Schemes
此步骤的目的是:在 testLLVM 项目中,加载 `CodeStyleValidatePlugin.dylib` 插件可以成功。因为默认的 Xcode 使用的 clang/clang++ 编译器和编译 `CodeStyleValidatePlugin.dylib` 动态库不是一个版本。不做修改的话Xcode 加载 `CodeStyleValidatePlugin.dylib` 会报错。所以需要先编译出同一个 LLVM 版本的 clang/clang++。
<img src="https://github.com/FantasticLBP/knowledge-kit/raw/master/assets/XcodeCompileClang.png" style="zoom:20%">
<img src="./../assets/XcodeCompileClang.png" style="zoom:20%">
@@ -406,7 +406,7 @@ Xcode 打开项目,选择自动创建 Schemes
- `-Xclang`
- 插件名称
<img src="https://github.com/FantasticLBP/knowledge-kit/raw/master/assets/XcodeLoadPlugin.png" style="zoom:20%">
<img src="./../assets/XcodeLoadPlugin.png" style="zoom:20%">
@@ -414,7 +414,7 @@ Xcode 打开项目,选择自动创建 Schemes
在新创建的 TestLLVM Xcode 项目中加载创建的 `CodeStyleValidatePlugin.dylib` 会报错。原因是:由于 Clang 插件需要使用对应的版本去加载,如果版本不一致则会导致编译错误。如下所示:
<img src="https://github.com/FantasticLBP/knowledge-kit/raw/master/assets/XcodeLoadClangPluginError.png" style="zoom:20%">
<img src="./../assets/XcodeLoadClangPluginError.png" style="zoom:20%">
@@ -426,17 +426,17 @@ Xcode 打开项目,选择自动创建 Schemes
如下所示:
<img src="https://github.com/FantasticLBP/knowledge-kit/raw/master/assets/XcodeSpecifyClangPath.png" style="zoom:20%">
<img src="./../assets/XcodeSpecifyClangPath.png" style="zoom:20%">
继续编译还是会报错,报错如下:
<img src="https://github.com/FantasticLBP/knowledge-kit/raw/master/assets/XcodeLoadClangPluginError2.png" style="zoom:20%">
<img src="./../assets/XcodeLoadClangPluginError2.png" style="zoom:20%">
解决方案为:在 `Build Settings` 栏目中搜索 `index`,将 `Enable Index-Wihle-Building Functionality`` Default` 改为 `NO`
<img src="https://github.com/FantasticLBP/knowledge-kit/raw/master/assets/XcodeLoadClangThenBuildErrorFix.png" style="zoom:20%">
<img src="./../assets/XcodeLoadClangThenBuildErrorFix.png" style="zoom:20%">
@@ -448,7 +448,7 @@ Tips 由于重新修改了插件的源码,所以每次 Build 构建完 FANP
编译成功,可以看到在日志中输出了我们编写的日志信息。
<img src="https://github.com/FantasticLBP/knowledge-kit/raw/master/assets/XcodeLoadClangPluginTest.png" style="zoom:20%">
<img src="./../assets/XcodeLoadClangPluginTest.png" style="zoom:20%">
@@ -481,7 +481,7 @@ NS_ASSUME_NONNULL_END
利用 Clang 查看 AST 指令为 `clang -fmodules -fsyntax-only -Xclang -ast-dump workaholic_person.m`
<img src="https://github.com/FantasticLBP/knowledge-kit/raw/master/assets/ClassNameViaClangAST.png" style="zoom:20%">
<img src="./../assets/ClassNameViaClangAST.png" style="zoom:20%">
核心思路为:我们要分析类名不符合规范的情况,要精确报错,首先要识别到类名,利用 AST 的能力可以办到(类名在 AST 的 `ObjCInterfaceDecl` 节点上)。然后获取到类名的行号信息,精确报错。
@@ -771,7 +771,7 @@ X("CodeStyleValidatePlugin", "This plugin is designed for scanning code styles,
- 可以对 Category 名做检测,如果带下划线,则报错提示并给出修改意见
- 编写的 `CodeStyleValidatePlugin` Demo 中对不符合规范的做了 `DiagnosticsEngine::Warning` 级别的警告。如果遇到1个警告则不影响继续编译。如果是 `DiagnosticsEngine::Error` 级别的编译报错遇到1个则终止编译请注意该区别按需编写自己的插件逻辑。
<img src="https://github.com/FantasticLBP/knowledge-kit/raw/master/assets/LLVMClangPluginUseInXcode.png" style="zoom:25%">
<img src="./../assets/LLVMClangPluginUseInXcode.png" style="zoom:25%">
@@ -819,7 +819,7 @@ X("CodeStyleValidatePlugin", "This plugin is designed for scanning code styles,
- 使用 LLVM 编写 Clang 插件,解析 AST 拿到所有的 `ObjCInterfaceDecl` 信息,然后结合 `ObjCMethodDecl` 信息便可获取 Category 中的 所有方法,再判断方法是否同名
<img src="https://github.com/FantasticLBP/knowledge-kit/raw/master/assets/ClangASTCategoryMethod.png" style="zoom:20%">
<img src="./../assets/ClangASTCategoryMethod.png" style="zoom:20%">