首先我们要先去编写一个 FuncBlockCount.c文件
#include "llvm/IR/Function.h"
#include "llvm/Pass.h"
#include "llvm/Support/raw_ostream.h"
//引入llvm命名空间,可以让其实用LLVM当中的函数
using namespace llvm;
//创建一个匿名的命名空间
namespace {
//声明Pass
struct FuncBlockCount : public FunctionPass
{
//声明Pass的标识符,会被LLVM用作识别Pass
static char ID;
//对父类进行初始化
FuncBlockCount() : FunctionPass(ID){}
//其实就是FunctionPass的一个虚函数,这里对它进行了实现。一个FunctionPass的子类要想做一些实际的工作,就必须对这个虚函数进行实现。
bool runOnFunction(Function &F) override {
//errs()是一个LLVM提供的C++输出流,我们可以用它来输出到控制台
errs() << "Function "<<F.getName()<<'\n';
//函数返回false说明它没有改动函数F。之后,如果我们真的变换了程序,我们需要返回一个true。
return false;
}
};
}
//初始化Pass ID
char FuncBlockCount::ID = 0;
//需要注册Pass、填写名称和命令行参数
static RegisterPass<FuncBlockCount> X("funcblockcount","Function Block Count",false,false);//,最后两个参数描述了它的行为:如果一个pass不修改CFG,那么第三个参数将被设置为true;如果pass是一个分析传递,例如dominator树(支配树)传递,则true作为第四个参数提供。
然后我们再去使用g++ FuncBlockCount.cpp -fPIC -g -Wall -Wextra -std=c++11 `llvm-config --cxxflags
` -shared -o FuncBlockCount.so 命令去编译,就能编译出.so文件
我们去使用的时候直接输入下面的命令就可以了其中funcblockcount就是我们注册Pass时候的设置的命令行参数
使用opt -load /home/parallels/Desktop/FuncBlockCount/FuncBlockCount.so -funcblockcount sample.ll 命令去运行新的Pass,输出结果如下所示
我们的sample.c文件如下所示
int foo(int n,int m)
{
int sum=0;
int c0;
for(c0=n;c0>0;c0--)
{
int c1=m;
for(;c1>0;c1--)
{
sum+=c0>c1 ? 1:0;
}
}
return sum;
}
然后使用clang -O0 -S -emit-llvm sample.c -o sample.ll 就可以将C语言测试代码编译为LLVM IR的形式
综上所述其实就是opt命令行工具会动态的去加载动态链接库,以运行Pass,之后Pass会遍历每一个函数,输出其函数名,但未对IR做任何改动