1, environmental
MacOS 10.15.7
Xcode 11.3
LLVM 8.0.0 (download address: releases.llvm.org/download.ht…
2. Download LLVM source code locally and generate Xcode project
(1) download llvm8.0.0
Visit releases.llvm.org/download.ht… To find the source code for 8.0.0:
I’m using Xcode11.3 here, so download LLVM8.0.0. If you’re using Xcode12, you can download LLVM10.0.0. Different versions of Xcode will have different LLVM versions. Can (en.wikipedia.org/wiki/Xcode) here to check the corresponding relationship.
(2) Compile and generate the Xcode project
Unzip LLVM8.0.0 to any of your directories, create an xcode_build_8.0 folder in the same directory, open terminal CD to xcode_build_8.0, and run cmake to generate an Xcode project:
cmake -G Xcode CMAKE_BUILD_TYPE="Debug" .. /llvmCopy the code
Double-click the llVm. xcodeProj file to open the project and select as shown in the following figure:
Find ALL_BUILD and compile (shortcut key: comd+B), compile the entire LLVM project, it will take a long time:
After the compilation is complete, you can view the compiled file in the Debug path:
3. Write a pass
(1) Find the test case in LLVM project Pass project Hello:
The code in the hello.cpp file is as follows:
#include "llvm/IR/IRBuilder.h"#include "llvm/IR/IntrinsicInst.h#include "llvm/ADT/Statistic.h"#include "llvm/IR/Function.h"#include "llvm/Pass.h"#include "llvm/Support/raw_ostream.h"#include "llvm/Analysis/LoopInfo.h"#include "llvm/Analysis/LoopPass.h"#include "llvm/PassAnalysisSupport.h" using namespace llvm; #define DEBUG_TYPE "hello"STATISTIC(HelloCounter, "Counts number of functions greeted"); // The pass function will automatically generate main when there is no main method in the c file and call all functions in the current module from main. // The idea is to see if main is present, terminate the operation if main is present, create a main, create BB, create Inst, and complete the call. namespace { class SimpleInvoker : public ModulePass { public: static char ID; SimpleInvoker() : ModulePass(ID) {} bool runOnModule(Module &M) override{ Function *F = M.getFunction("main"); if (F) { errs() << "Main Function Found! So return.\n"; return true; } errs() << "Main Function Not Found! So create.\n"; FunctionType *FT = FunctionType::get(Type::getInt32Ty(M.getContext()), false); F = Function::Create(FT, GlobalValue::LinkageTypes::ExternalLinkage, "main", &M); BasicBlock *EntryBB = BasicBlock::Create(M.getContext(), "EntryBlock", F); IRBuilder<> IRB(EntryBB); for (Function &FF:M) { if(FF.getName() == "main") continue; if(FF.empty()) continue; IRB.CreateCall(&FF); } IRB.CreateRet(ConstantInt::get(Type::getInt32Ty(M.getContext()), 0)); return true; } virtual StringRef getPassName() const override { return "Simple Invoker"; }}; Pass *createSimpleInvoker() { return new SimpleInvoker(); } } char SimpleInvoker::ID = 0; static RegisterPass<SimpleInvoker> Y("simpleInvoker", "SimpleInvoker Pass");Copy the code
(2) select LLVMHello in Xcode and compile to generate LLVMHello. Dylib file:
So that’s the pass that we wrote. The pass function automatically generates main and calls all functions in the current module from main when there is no main method in the c file.
4. Test the pass function
(1) Create the test.c file
There is no main function in this file, only f1() and f2(), and the code looks like this:
void f1(){
printf("f1--printf\n");
}
int f2(){
printf("f2---printf\n");
return 0;
}
Copy the code
(2) Compile test.c with clang in Xcode to generate test. BC intermediate code file
/path/to/clang -emit-llvm -c ./test.c -o ./test.bc
Copy the code
(3) Use opt to load llVMhello. dylib to process test. BC intermediate code file, and get test1.bc file
/ path/to/xcode_build_8. 0 / Debug/bin/opt - load/path/to/xcode_build_8. 0 / Debug/lib/LLVMHello dylib - simpleInvoker. / test. The BC -o ./test1.bcCopy the code
This opt is an executable file generated after your LLVM project is compiled.
The intermediate code for test.bc is processed, traversed to see if main is included, but if it is not, a main function is inserted and the methods f1() and f2() are called, resulting in the test1.bc file.
(4) use lli to execute test1.bc file
The/path/to/xcode_build_8. 0 / Debug/bin/lli. / test1. BCCopy the code
This lli is an executable file generated after your LLVM project is compiled.
Terminal output:
f1--printf
f2---printf
Copy the code
The main() function was added correctly, and the methods F1 () and f2() were successfully called.
Part of the content of this paper is referenced from:
www.leadroyal.cn/?p=719