diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3a8abca --- /dev/null +++ b/.gitignore @@ -0,0 +1,38 @@ +llvm/ +compiler-rt/ +clang/ +build/ +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json + +test/*.bc \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..e69de29 diff --git a/README.md b/README.md index 04e7d45..d4892ef 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,14 @@ # llvm-pass-practice the road to write llvm pass + + +## notice + +* path should not include Chinese character + +## install llvm +`./install.sh` + +## practices + +* my first pass:show function name \ No newline at end of file diff --git a/install.sh b/install.sh new file mode 100755 index 0000000..2cd2063 --- /dev/null +++ b/install.sh @@ -0,0 +1,26 @@ +#get LLVM +git clone --depth=1 http://llvm.org/git/llvm.git + + +#get clang +git clone --depth=1 http://llvm.org/git/clang.git + + +#get compiler-rt +git clone --depth=1 http://llvm.org/git/compiler-rt.git + + +#Set up clang, compiler-rt +pushd llvm/tools +ln -s ../../clang . +popd + +pushd llvm/projects +ln -s ../../compiler-rt . +popd + +mkdir build +pushd build +cmake -G "Unix Makefiles" ../llvm +make -j4 +popd diff --git a/my first pass/FuncName/CMakeLists.txt b/my first pass/FuncName/CMakeLists.txt new file mode 100644 index 0000000..8344587 --- /dev/null +++ b/my first pass/FuncName/CMakeLists.txt @@ -0,0 +1,6 @@ +add_llvm_library( LLVMFuncName MODULE +FuncName.cpp + +PLUGIN_TOOL +opt +) \ No newline at end of file diff --git a/my first pass/FuncName/FuncName.cpp b/my first pass/FuncName/FuncName.cpp new file mode 100644 index 0000000..952e80d --- /dev/null +++ b/my first pass/FuncName/FuncName.cpp @@ -0,0 +1,19 @@ +#include "llvm/Pass.h" +#include "llvm/IR/Function.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +namespace { + struct FuncName:public FunctionPass { + static char ID; + FuncName():FunctionPass(ID) {} + bool runOnFunction(Function &F) { + errs()<< F.getName() << "\n"; + return false; + } + }; +} + +char FuncName::ID = 0; +static RegisterPass X("funcName","display function name"); \ No newline at end of file diff --git a/my first pass/README.md b/my first pass/README.md new file mode 100644 index 0000000..8406a4e --- /dev/null +++ b/my first pass/README.md @@ -0,0 +1,118 @@ +## setup env +1. add library +add + ``` + add_llvm_library( LLVMFuncName MODULE + YOUR_PASS.cpp + + PLUGIN_TOOL + opt + ) + ``` + into `PASS_DIR_PATH/CMakeLists.txt` + +2. add subdirectory + add `add_subdirectory(PASS_DIR_PATH)` into `lib/Transforms/CMakeLists.txt` + +## coding + +1. the necessary header + ```cpp + #include "llvm/Pass.h" + #include "llvm/IR/Function.h" + #include "llvm/Support/raw_ostream.h" + ``` + +2. add namespace + ```cpp + using namespace llvm; + ``` + +3. write your own pass in an anonymous namespace + ```cpp + namespace { + + } + ``` + +## build + +```sh +⇒ doublemice@DoubleMice-MBP:~/Documents/graduate/llvm-pass-practice|master⚡ pwd +/Users/doublemice/Documents/graduate/llvm-pass-practice +pushd llvm/lib/Transforms +ln ../../../my\ first\ pass/FuncName . +popd +pushd build +make +popd +``` + +## load the pass + +### the output lib +```sh +doublemice@DoubleMice-MBP:~/Documents/graduate/llvm-pass-practice|master⚡ +⇒ ls build/lib/LLVMFuncName.dylib +build/lib/LLVMFuncName.dylib +``` + +as we see,the output dylib name is exact the name we define in `PASS_DIR_PATH/CMakeLists.txt`(see: setup env -> 1) + +### load it with opt +1. prepare a test file in test/FuncName_test.c + ```cpp + #include + void sayHello() { + printf("hello\n"); + } + void sayGoodbye() { + printf("goodbye\n"); + } + int main() { + sayHello(); + sayGoodbye(); + return 0; + } + ``` + +2. compile it into a llvm bitcode + ```sh + $LLVM_BIN/clang -O3 -emit-llvm test/FuncName_test.c -c -o test/FuncName_test.bc + ``` +3. run the pass with opt + ```sh + doublemice@DoubleMice-MBP:~/Documents/graduate/llvm-pass-practice|master⚡ + ⇒ $LLVM_BIN/opt -load build/lib/LLVMFuncName.dylib -funcName < test/FuncName_test.bc > /dev/null + sayHello + sayGoodbye + main + ``` + +## a skeleton +```cpp +#include "llvm/Pass.h" +#include "llvm/IR/Function.h" +#include "llvm/Support/raw_ostream.h" +using namespace llvm; +namespace { + struct Example:public FunctionPass { + static char ID; + Example():FunctionPass(ID) {} + + //tells llvm which other pass we need + void getAnalysisUsage(AnalysisUsage &AU) const { + ... + } + virtual bool runOnFunction(Function &F) { + ... + //true:this pass will change our program + //false:won't change + return false; + } + }; +} + +char Example::ID = 0; +static RegisterPass X("PASS_NAME","PASS_DESCRIPTION") +``` \ No newline at end of file diff --git a/test/FuncName_test.c b/test/FuncName_test.c new file mode 100644 index 0000000..8234795 --- /dev/null +++ b/test/FuncName_test.c @@ -0,0 +1,12 @@ +#include +void sayHello() { + printf("hello\n"); +} +void sayGoodbye() { + printf("goodbye\n"); +} +int main() { + sayHello(); + sayGoodbye(); + return 0; +}