在 Linux
和 Android
上使用 LLVM
进行代码混淆已经非常方便了,网上也有很多相关的文章(比如 【LeadroyaL】 这位大佬的一系列关于 LLVM
的文章),但是在 Windows
上目前还没有找到一种优雅的方式使用 LLVM
进行代码混淆,本文的目的就是为了这个不足,让 LLVM
在 Windows
上也能优雅的动态加载外部插件进行代码混淆。
Microsoft Visual Studio Professional 2019
(简称 VS2019Pro
或者 VS
) 作为 Windows
上主要的开发工具,我们需要提前安装一份,当然,如果你不是使用 VS2019Pro
开发,那这个步骤也是可以省略的,可以不用安装 VS2019Pro
,现在安装 VS2019Pro
是为了演示在 VS2019Pro
中使用 LLVM Pass
插件。本文所使用的 VS2019Pro
版本是 16.3.6
(对应的 LLVM
版本是 8.0.1
),安装 VS2019Pro
的过程如下所示:
打开 VS2019Pro
的安装程序,在 【工作负载】
页面默认会选中 【使用 C++ 的桌面开发】
,保持默认即可:
切换到 【单个组件】
页面,在搜索框中输入 clang
,把搜索出来的两项打上勾。
【安装位置】
可以自己选择,不过 【下载缓存】
最好指向自己安装包解压出来的位置,可以避免浪费磁盘空间。
【语言包】
可以自由选择,然后就可以正常安装 VS2019Pro
。
本文提供的 VS2019Pro
安装包:【VS2019Pro_WithLLVM8.0.1.7z】 ,原文链接 。
要想在 Windows
上编译并使用 LLVM
,首先必须要有编译 LLVM
的工具,通常情况下,我们都会选择 VS
作为 Windows
平台上的编译工具,但是由于 VS
编译出来的 LLVM
不支持动态加载插件(可以在编译日志中看到这样的输出信息: LLVMHello ignored -- Loadable modules not supported on this platform.
),因此,我们不使用 VS
作为编译 LLVM
的工具。在本文中,我们选用的编译工具是 【MSYS2】 ,本文所使用的 MSYS2
版本是 【msys2-x86_64-20220319.exe】 (该版本的 MSYS2
对应的 GCC
版本是 11.2.0
,当然,使用基于 GCC-10.3.0
版本的 MSYS2
也是可以的)。
安装过程中,到达 66%
的时候会出现卡住的现象(会停留在 Updating trust database...
的时候),需要等久一点:
安装好 MSYS2
之后,打开 MSYS2 MSYS
快捷方式,如下所示:
并在 MSYS2
中安装对应的编译工具 -- GCC
和 G++
等,安装命令如下所示:
---- 分割线 ---- ---- 分割线 ----
至此,整套 MSYS2
的编译工具链都已经安装完成。
本文提供的 MSYS2
安装包:【msys2-x86_64-20220319_GCC_11.2.0.exe.7z】 ,以及安装好 GCC
编译工具链的压缩包(开箱即用):【MSYS2-GCC11.2.0_x86_x64.7z】 (不建议使用),建议自行安装 MSYS2
以及 GCC 编译工具链,开箱即用版本的 MSYS2 在编译程序的时候需要自己手动指定 lib 库的位置,特别麻烦。
除了准备 Vs2019Pro
和 MSYS2
之外,还需要安装 CMake
,以此来编译 LLVM
。CMake
的安装流程比较简单,直接在官网上 【https://cmake.org/download/】 下载安装即可(本教程中安装的是 CMake 3.18.2
版本)。
安装 CMake
的过程中需要注意的点:就是在安装的时候记得勾上 Add CMake to the system PATH for all users
或者 Add CMake to the system PATH for current user
。这样可以在 cmd
中直接使用 CMake
。
本文提供的 CMake
安装包:【cmake-3.18.2-win64-x64.msi.7z】 。
使用 VS2019Pro
编译出来的 LLVM
,我们称之为静态库版本,因为编译出来的 clang.exe
是可以单独使用的,没有外部依赖,而本文所要编译的 LLVM
是属于动态库版本,因此,编译出来的 clang.exe
不能单独使用,需要有相应的依赖库才能使用。
本文提供的 LLVM
源码安装包:【src_llvm8_patched_for_win10.7z】 ,该压缩包中的 LLVM
源码已经被 Patched
,可以直接在 Windows
上使用 MSYS2
中的 GCC
编译。
本文所使用的 LLVM
版本是 LLVM-8.0.0
(当然,如果使用 LLVM-12.0.0.0
也是可以的,但是需要更新 VS2019
的版本,比如使用 VS2019Pro v16.11.5
这个版本,这个版本的对应的 LLVM
就是 12.0.0
),LLVM-8.0.0
的源码下载地址可以从这里下载:【LLVM-8.0.0 下载地址】 ,当然,也可以使用 wget
下载:
这里的代码,并不需要下载全部,因为即使下载了,在 Windows
上也编译不了,现在我们只需要下载在 Windows
上可以编译的几个部分(必要的部分)就可以了,也就是 cfe-8.0.0.src.tar.xz
、llvm-8.0.0.src.tar.xz
和 lld-8.0.0.src.tar.xz
,如下图所示:
下载好这些源码之后,解压出来,并对它们进行重命名,方便后续管理,重命名规则如下所示:
重命名之后,本小节的任务就完成了,如下所示:
原始的 LLVM
源码在 Windows
上并不能直接编译,如果直接编译,会出现很多问题。现在需要对这些代码就行修改,使得修改后的代码可以在 Windows
上编译,所需要修改的地方有 5
个文件,如下所示:
在这个文件中需要注释掉第 3729
行开始的 4
行代码,如下所示:
这几行代码会在编译 Release
模式的 Pass
的时候,无法获取到 BasicBlock
的名字,但有时候我们需要保留 BasicBlock
的名字,所以把这几行代码注释掉,但是在 Linux
和 MacOS
上不会出现这个问题。
在这个文件中,只需要把第 30
行的 add_subdirectory(Testing)
这行注释掉即可,如下所示:
在这个文件中,需要在文件的第 8
行代码处手动添加几个头文件,被添加的头文件为:stdio.h
、stdlib.h
和 string
,如下所示:
把这个文件中出现的两处 for_each(parallel::par
都修改为 for_each(parallel::seq
,第一处在该文件的第 1071
行,第二处在该文件的第 1577
行,如下图所示:
把这个文件中在 71
行出现的 llvm::parallel::par
修改为 llvm::parallel::seq
,如下所示:
编译 LLVM
可以按照需要编译不同的版本,即 x64
版本和 x32
版本,但是一般情况下,只需要 x64
版本即可。
修改好 LLVM
源码之后,就可以开始编译步骤了,有了前面的基础,编译步骤就变得很简单了,首先打开 cmd
(记得是打开 Windows
上纯正的 cmd
命令行程序,而不是 PowerShell
等变种工具,因为我们还需要修改被打开的 cmd
的环境变量),打开 cmd
之后,进入到 LLVM
源码的 同级
目录中(示例中是: E:\LLVM\llvm8
),并把前面安装的 MSYS2
编译工具所在的路径添加在 cmd
的环境变量中(笔者前面安装的 MSYS2
路径是:C:\MyProgramFiles\MSYS2
),现在假设我们先编译一份 x32
版本的 LLVM
,在源码的同级目录下执行如下命令:
配置完成之后,就可以执行编译命令了,假设我们现在的编译目录是 build_dyn_x32
,执行编译命令 cmake --build ./build_dyn_x32 -j 4
之后,系统就开始帮我们编译 LLVM
了,如下所示:
经过一段时间的等待(笔者的机器比较老,编译过程花费了两个小时左右),就可以看到编译完成的日志了,如下所示:
当然,上一小节演示的是编译 32
位的 LLVM
,而我们一般也会需要编译 64
位版本的 LLVM
,编译命令和 32
位基本一样,区别只有如下两点:
对于 VS2019Pro
版本是 16.3.6
的情况下,VS2019Pro
会使用 LLVM8
的 x64
版本来编译程序,不管 VS2019Pro
编译的目标程序是 x86
还是 x64
,它都统一使用 LLVM8
的 x64
版本来编译程序。
但是,对于 16.11.5
版本的 VS2019Pro
,它会使用 LLVM12
的 x64
版本来编译 x64
程序,使用 LLVM12
的 x32
版本来编译 x86
程序。
因此,如果想要 Patch 16.3.6
版本的 VS2019Pro
,只需要编译一份基于 x64
的 LLVM8
即可,如果想要 Patch 16.11.5
版本的 VS2019Pro
,则需要编译一份基于 x64
的 LLVM12
和一份基于 x32
的 LLVM12
。
编译好 x32
和 x64
版本的 LLVM
之后,在 LLVM
源码的同级目录下会生成两个版本的 BUILD
目录,如下所示(原文出处 ):
编译完成之后,开始安装 LLVM
到指定目录,我们可以使用 CMake
的参数 -DCMAKE_INSTALL_PREFIX=C:\LLVM8
来指定安装目录,笔者以安装 x64
版本的 LLVM
为例,指定的安装目录是:C:\MyProgramFiles\LLVM\llvm8\llvm8_dyn_x64
,然后执行如下所示命令进行安装:
安装好之后,到安装目录下查看已安装的 LLVM
,发现大小只有 231MB
,体积相对于使用 VS2019Pro
直接编译出来的 LLVM
版本是小很多的,如下所示:
动态编译出来的 LLVM
工具是不能直接使用的,需要给它添加对应的依赖库,或者把依赖库所在的路径添加到系统的环境变量中。
安装好 LLVM
之后,我们可以打开 cmd
进入安装目录,并尝试运行 .\bin\clang.exe --version
查看 clang
能不能正常工作,但是很遗憾,由于缺少必要的 dll
文件,暂时还不能运行,如下所示:
这是因为我们的 LLVM
是使用 MSYS2
里面的 GCC
编译的,并且编译的模式还是 动态编译
,因此,我们编译出来的 LLVM
还会依赖 GCC
的部分库文件,如果我们想要让 LLVM
能正常运行,最简答的方法是直接添加 MSYS2
工具链的路径到环境变量中,如下所示:
当然,也可以把这个 MSYS2
工具链的路径到系统的环境变量中。
另一个解决方案是把这几个缺失的库手动拷贝到 LLVM
安装目录下的 bin
目录中,为了方便,先把这几个缺失的库拷贝到 LLVM
安装目录下的 deps
目录中(自己创建该目录),然后再从这个目录中拷贝到 bin
目录。经过研究发现,x64
版本的 LLVM
缺失的库包括如下 4
个,并且这几个库都在目录 C:\MyProgramFiles\MSYS2\mingw64\bin
中:
把这几个 dll
依赖库拷贝到 LLVM
安装目录下的 bin
目录中之后,再次打开 cmd
,进入安装目录之后,直接运行 .\bin\clang.exe --version
,此时已经可以正常运行,如下所示:
注意: 如果是 x32
版本的 LLVM
,所需要的依赖库要从目录 C:\MyProgramFiles\MSYS2\mingw32\bin
中查找,并且依赖库的名称和 x64
版本的不完全一样, x32
版本的 LLVM
所需要的依赖库如下所示:
添加完以上几个 dll
动态库文件之后,我们已经可以正常的使用 LLVM
来编译自己的程序了,但是如果想要使用 LLVM
加载外部 Pass
插件,则还会出现问题,会出现 符号缺失
或者 找不到符号
等类似的错误,为了解决这类错误,我们还需要手动添加一些静态库 .a
文件(LLVM
编译目录下生成的静态库文件)到 LLVM
的安装目录中。
从下图中我们可以看到,LLVM
的编译目录下的 lib
目录中总共有 108
个静态库文件,而 LLVM
的安装目录下的 lib
目录中总共只有 41
个静态库文件,而我们如果想要让 LLVM
能正常加载外部 Pass
插件,我们还需要把这些静态库文件从编译目录拷贝到安装目录下:
直接把所有的静态库文件从编译目录拷贝到安装目录下对应的文件夹中即可,如下所示:
至此,LLVM
的 Patch
工作已经全部完成,此时 LLVM
安装目录下就是一份完整的 LLVM
编译工具链。
到了这个步骤,使用 LLVM
的方法就和 Linux
中使用的方法一致了,也可以让 LLVM
编译和加载任意的 Pass
插件,下面我们就以一个简单的 mydemo Pass
插件为例进行说明:
我们的 mydemo Pass
插件包含 4
个文件:
本文提供的 mydemo
插件源码:【mydemo.7z】 。
mydemo.cpp
文件的核心代码如下所示:
mydemo.h
头文件:
CMakeLists.txt
是 CMake
的配置文件,主要用于配置 LLVM
相关的一些变量信息,如下所示:
如果编写的插件比较复杂,则在 CMakeLists.txt
文件中需要再补充缺失的依赖库(使用 target_link_libraries
函数添加),下面列举一些常见的依赖库:
一般来说,在 Windows
上添加以上几个依赖库之后,都能够正常编译大部分的插件,包括: OLLVM
、Hikari
和 Armariris
等。
cmake_build.bat
文件需要把 MSYS2
编译工具链的路径添加到环境变量中,并指定 LLVM_HOME
环境变量到 LLVM
的安装目录下:
编译的时候,修改好编译脚本 cmake_build.bat
文件中的 MSYS2
文件路径和 LLVM_HOME
文件路径即可,然后双击运行该脚本即可编译成功,如下所示:
编译好 LLVM
的 Pass
插件之后,我们就可以使用这个插件了,现在我们以 test_mydemo
为例,这个测试例子包含两个文件:
本文提供的 test_mydemo
示例源码:【test_mydemo.7z】 。
test_mydemo.c
文件的代码如下所示:
build.bat
脚本如下所示:
在编译脚本 build.bat
中,除了设置 MSYS2
和 LLVM_HOME
这两个环境变量之外,还需要指定 LLVM Pass
插件的位置(示例中使用变量 DEMO_PASS
保存),然后再编译命令中添加 -Xclang -load -Xclang /path/to/libpass.dll
参数来指定插件所在的位置,用这样的方式编译可执行文件,在编译过程中就会自动加载 LLVM Pass
插件,如下所示:
学会了在命令行中直接使用 Pass
插件之后,在 VS2019Pro
中使用 Pass
插件的方法就很简单了,只需要 4
个步骤就可以了:
在 16.3.6
版本的 VS2019Pro
中自带的 LLVM
版本是 8.0.1
,因此,我们使用自己编译的 LLVM-8.0.0
版本可以直接替换它的编译工具链。打开 VS2019Pro
的安装目录(笔者的安装目录是:C:\MyProgramFiles\VS\VS2019Pro
),然后进入 VC\Tools
子目录,就可以看到 VS2019Pro
自带的两套编译工具链:一套是 VC
的,另一套是 LLVM
的,如下图所示:
然后把该目录下的 Llvm
目录重命名一下(方便后续恢复),比如,把它重命名为 Llvm_org
,然后再把我们自己编译的 LLVM
(在 LLVM
安装目录下)拷贝过去,如下所示:
最后把拷贝过来的 llvm8_dyn_x64
目录重命名为 Llvm
即可,至此,Patch VS2019Pro
中自带的 LLVM
已经完成。
在 Patch
完 VS2019Pro
中自带的 LLVM
编译工具链之后,我们现在可以新建一个 VS2019
的 demo
项目,然后打开项目属性,修改项目的【平台工具集】
为 LLVM
,如下所示:
修改完 VS2019
项目的【平台工具集】
之后,可以在项目名称上明显的看到项目名称后面跟了一个括号(LLVM - clang-cl
),表明当前正在使用的是 LLVM
编译工具链,如下图所示:
此时,已经可以使用 LLVM
工具集编译项目了,只是还没有启用 Pass
插件而已,点击清理解决方案,然后再点击运行,如下图所示:
有了前面的步骤,要在 VS2019Pro
项目中使用 Pass
插件,只需要在项目属性中添加如下参数即可:
如下图所示:
一切准备就绪,现在只需要点击【重新生成解决方案】
即可看到 libmydemo.dll
插件的输出信息了,如下所示:
当然,也可以先清理一下解决方案,然后直接运行项目,效果是一样的,如下所示:
至此,在 VS2019Pro
项目中使用 Pass
插件的方法已经全部完成。
本文介绍了在 Windows
使用 LLVM
动态加载外部插件的方法,其实和 Linux
上的方法差不多,只是在 Windows
相对麻烦一些,不能使用 VS
编译工具来编译 LLVM
,转而使用 MSYS2
中的 GCC
工具链编译,使得编译出来的 LLVM
属于动态库版本,体积相对较小,编译出来 LLVM
之后,再使用 LLVM
编译插件和使用插件都不会存在什么问题。
本文是作者原创作品,转载请注明出处,谢谢!
原文链接:https://bbs.pediy.com/thread-272346.htm
pacman
-
S
-
-
needed base
-
devel mingw
-
w64
-
x86_64
-
toolchain mingw
-
w64
-
i686
-
toolchain cmake
pacman
-
S
-
-
needed base
-
devel mingw
-
w64
-
x86_64
-
toolchain mingw
-
w64
-
i686
-
toolchain cmake
https:
/
/
releases.llvm.org
/
8.0
.
0
/
cfe
-
8.0
.
0.src
.tar.xz
https:
/
/
releases.llvm.org
/
8.0
.
0
/
libcxx
-
8.0
.
0.src
.tar.xz
https:
/
/
releases.llvm.org
/
8.0
.
0
/
clang
-
tools
-
extra
-
8.0
.
0.src
.tar.xz
https:
/
/
releases.llvm.org
/
8.0
.
0
/
compiler
-
rt
-
8.0
.
0.src
.tar.xz
https:
/
/
releases.llvm.org
/
8.0
.
0
/
libcxx
-
8.0
.
0.src
.tar.xz
https:
/
/
releases.llvm.org
/
8.0
.
0
/
libcxxabi
-
8.0
.
0.src
.tar.xz
https:
/
/
releases.llvm.org
/
8.0
.
0
/
lld
-
8.0
.
0.src
.tar.xz
https:
/
/
releases.llvm.org
/
8.0
.
0
/
lldb
-
8.0
.
0.src
.tar.xz
https:
/
/
releases.llvm.org
/
8.0
.
0
/
llvm
-
8.0
.
0.src
.tar.xz
https:
/
/
releases.llvm.org
/
8.0
.
0
/
cfe
-
8.0
.
0.src
.tar.xz
https:
/
/
releases.llvm.org
/
8.0
.
0
/
libcxx
-
8.0
.
0.src
.tar.xz
https:
/
/
releases.llvm.org
/
8.0
.
0
/
clang
-
tools
-
extra
-
8.0
.
0.src
.tar.xz
https:
/
/
releases.llvm.org
/
8.0
.
0
/
compiler
-
rt
-
8.0
.
0.src
.tar.xz
https:
/
/
releases.llvm.org
/
8.0
.
0
/
libcxx
-
8.0
.
0.src
.tar.xz
https:
/
/
releases.llvm.org
/
8.0
.
0
/
libcxxabi
-
8.0
.
0.src
.tar.xz
https:
/
/
releases.llvm.org
/
8.0
.
0
/
lld
-
8.0
.
0.src
.tar.xz
https:
/
/
releases.llvm.org
/
8.0
.
0
/
lldb
-
8.0
.
0.src
.tar.xz
https:
/
/
releases.llvm.org
/
8.0
.
0
/
llvm
-
8.0
.
0.src
.tar.xz
:: 设置 MSYS2 的 gcc x32 环境变量到 cmd 中
set
PATH
=
%
PATH
%
;C:\MyProgramFiles\MSYS2\mingw32\
bin
:: 然后执行 gcc
-
-
version 查看 gcc 版本,并确保该命令能正常输出 gcc 的版本号
gcc
-
-
version
:: 接下来执行 LLVM 的 config 命令,使之生成 LLVM 的 Makefile 文件
:: 这里要注意两个参数:【
-
DBUILD_SHARED_LIBS
=
ON】 和 【
-
DLLVM_ENABLE_DUMP
=
ON】
cmake
-
G
"MinGW Makefiles"
-
S .
/
src
/
llvm
-
B .
/
build_dyn_x32
-
DCMAKE_BUILD_TYPE
=
Release
-
DLLVM_ENABLE_PROJECTS
=
"clang;lld;"
-
DLLVM_TARGETS_TO_BUILD
=
"X86"
-
DBUILD_SHARED_LIBS
=
ON
-
DLLVM_INCLUDE_TESTS
=
OFF
-
DLLVM_BUILD_TESTS
=
OFF
-
DLLVM_INCLUDE_BENCHMARKS
=
OFF
-
DLLVM_BUILD_BENCHMARKS
=
OFF
-
DLLVM_ENABLE_DUMP
=
ON
:: 最后执行编译命令
:: 根据自己机器的核心数量,设置
-
j 后面的参数,
4
表示使用
4
个线程进行并行编译
cmake
-
-
build .
/
build_dyn_x32
-
j
4
:: 设置 MSYS2 的 gcc x32 环境变量到 cmd 中
set
PATH
=
%
PATH
%
;C:\MyProgramFiles\MSYS2\mingw32\
bin
:: 然后执行 gcc
-
-
version 查看 gcc 版本,并确保该命令能正常输出 gcc 的版本号
gcc
-
-
version
:: 接下来执行 LLVM 的 config 命令,使之生成 LLVM 的 Makefile 文件
:: 这里要注意两个参数:【
-
DBUILD_SHARED_LIBS
=
ON】 和 【
-
DLLVM_ENABLE_DUMP
=
ON】
cmake
-
G
"MinGW Makefiles"
-
S .
/
src
/
llvm
-
B .
/
build_dyn_x32
-
DCMAKE_BUILD_TYPE
=
Release
-
DLLVM_ENABLE_PROJECTS
=
"clang;lld;"
-
DLLVM_TARGETS_TO_BUILD
=
"X86"
-
DBUILD_SHARED_LIBS
=
ON
-
DLLVM_INCLUDE_TESTS
=
OFF
-
DLLVM_BUILD_TESTS
=
OFF
-
DLLVM_INCLUDE_BENCHMARKS
=
OFF
-
DLLVM_BUILD_BENCHMARKS
=
OFF
-
DLLVM_ENABLE_DUMP
=
ON
:: 最后执行编译命令
:: 根据自己机器的核心数量,设置
-
j 后面的参数,
4
表示使用
4
个线程进行并行编译
cmake
-
-
build .
/
build_dyn_x32
-
j
4
cd
/
d E:\LLVM\llvm8
set
PATH
=
%
PATH
%
;C:\MyProgramFiles\MSYS2\mingw64\
bin
cmake
-
DCMAKE_INSTALL_PREFIX
=
C:\MyProgramFiles\LLVM\llvm8\llvm8_dyn_x64
-
P .\build_dyn_x64\cmake_install.cmake
cd
/
d E:\LLVM\llvm8
set
PATH
=
%
PATH
%
;C:\MyProgramFiles\MSYS2\mingw64\
bin
cmake
-
DCMAKE_INSTALL_PREFIX
=
C:\MyProgramFiles\LLVM\llvm8\llvm8_dyn_x64
-
P .\build_dyn_x64\cmake_install.cmake
namespace
{
/
/
定义我们的 Pass 类
class
MyDemoPass : public ModulePass
{
public:
static char
ID
;
/
/
Nessessary attribute
MyDemoPass();
/
/
Nessessary function
~MyDemoPass();
/
/
Optional function
virtual StringRef getPassName() const override;
/
/
Optional function
virtual
bool
doInitialization(Module &M) override;
/
/
Optional function
virtual
bool
doFinalization(Module &M) override;
/
/
Optional function
virtual
bool
runOnModule(Module &M) override;
/
/
Nessessary function
};
char MyDemoPass::
ID
=
1
;
/
/
Nessessary initialization, however, the value can be an arbitary integer
/
/
...
}
/
/
...
/
/
Pass 的入口函数
bool
MyDemoPass::runOnModule(Module &M)
{
string funcName
=
"";
string modName
=
"";
modName
=
M.getName().
str
();
MyPrint(
"Running core function [runOnModule] of the pass [MyDemoPass] for module ["
+
modName
+
"]!"
);
/
/
Print
the function's name
for
(Function &F : M)
{
funcName
=
F.getName().
str
();
MyPrint(
"Got a function ["
+
funcName
+
"]!"
);
}
return
false;
}
/
/
...
/
/
注册 Pass 代码:
/
/
Register module
pass
void RegisterMyModulePass(const PassManagerBuilder &PMB, legacy::PassManagerBase &PM)
{
PM.add(new MyDemoPass());
}
/
/
For loading ModulePass at different optimization level
/
/
[
1
]. Trigger at flag: `
-
O1`
or
`
-
O2`
or
`
-
O3`
/
/
static RegisterStandardPasses RegisterMyPassVar1 (PassManagerBuilder::EP_ModuleOptimizerEarly, RegisterMyModulePass);
/
/
[
2
]. Trigger at flag: `
-
O1`
or
`
-
O2`
or
`
-
O3`
/
/
static RegisterStandardPasses RegisterMyPassVar2 (PassManagerBuilder::EP_OptimizerLast, RegisterMyModulePass);
/
/
[
3
]. Trigger at flag: `
-
O0`
or
`default`
static RegisterStandardPasses RegisterMyPassVar3(PassManagerBuilder::EP_EnabledOnOptLevel0, RegisterMyModulePass);
/
/
[
4
]. Trigger at flag: `
-
O1`
or
`
-
O2`
or
`
-
O3`
static RegisterStandardPasses RegisterMyPassVar4 (PassManagerBuilder::EP_ModuleOptimizerEarly, RegisterMyModulePass);
namespace
{
/
/
定义我们的 Pass 类
class
MyDemoPass : public ModulePass
{
public:
static char
ID
;
/
/
Nessessary attribute
MyDemoPass();
/
/
Nessessary function
~MyDemoPass();
/
/
Optional function
virtual StringRef getPassName() const override;
/
/
Optional function
virtual
bool
doInitialization(Module &M) override;
/
/
Optional function
virtual
bool
doFinalization(Module &M) override;
/
/
Optional function
virtual
bool
runOnModule(Module &M) override;
/
/
Nessessary function
};
char MyDemoPass::
ID
=
1
;
/
/
Nessessary initialization, however, the value can be an arbitary integer
/
/
...
}
/
/
...
/
/
Pass 的入口函数
bool
MyDemoPass::runOnModule(Module &M)
{
string funcName
=
"";
string modName
=
"";
modName
=
M.getName().
str
();
MyPrint(
"Running core function [runOnModule] of the pass [MyDemoPass] for module ["
+
modName
+
"]!"
);
/
/
Print
the function's name
for
(Function &F : M)
{
funcName
=
F.getName().
str
();
MyPrint(
"Got a function ["
+
funcName
+
"]!"
);
}
return
false;
}
/
/
...
/
/
注册 Pass 代码:
/
/
Register module
pass
void RegisterMyModulePass(const PassManagerBuilder &PMB, legacy::PassManagerBase &PM)
{
PM.add(new MyDemoPass());
}
/
/
For loading ModulePass at different optimization level
/
/
[
1
]. Trigger at flag: `
-
O1`
or
`
-
O2`
or
`
-
O3`
/
/
static RegisterStandardPasses RegisterMyPassVar1 (PassManagerBuilder::EP_ModuleOptimizerEarly, RegisterMyModulePass);
/
/
[
2
]. Trigger at flag: `
-
O1`
or
`
-
O2`
or
`
-
O3`
/
/
static RegisterStandardPasses RegisterMyPassVar2 (PassManagerBuilder::EP_OptimizerLast, RegisterMyModulePass);
/
/
[
3
]. Trigger at flag: `
-
O0`
or
`default`
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
最后于 2022-8-22 15:49
被NewMai编辑
,原因: 更新 MSYS2 相关操作,建议自行安装 MSYS2 和 GCC 编译工具链