Last active
May 16, 2016 17:55
-
-
Save offlinemark/eac8c915096143a84bf2bda2008022a1 to your computer and use it in GitHub Desktop.
llvm stuff
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| i'm trying to install llvm, documenting it here | |
| ubuntu 14.04 | |
| http://llvm.org/docs/GettingStarted.html | |
| http://clang.llvm.org/get_started.html | |
| http://llvm.org/docs/GettingStarted.html#requirements | |
| install svn, cmake | |
| cd where-you-want-llvm-to-live | |
| i guess i want llvm to live in ~/llvm/ | |
| mkdir llvm | |
| cd llvm | |
| svn co http://llvm.org/svn/llvm-project/llvm/trunk llvm | |
| cd llvm/tools | |
| svn co http://llvm.org/svn/llvm-project/cfe/trunk clang | |
| cd ~/llvm | |
| installing ninja? | |
| apt-get install ninja-build | |
| apparently you need a cmake generator and most llvm devs use ninja | |
| mkdir build | |
| cd build | |
| cmake -G Ninja ../llvm | |
| that failed? | |
| ran it again and it worked..... | |
| kinda weird that the build directory is a level back? | |
| it says to run make but i thought i was using ninja | |
| ran ninja and it crashed | |
| trying from scratch. delete build dir | |
| realized my cmake from apt is way old | |
| wget cmake script from cmake.org/download | |
| run it | |
| add that directory to my path | |
| needed to install libc6-i386 bc those are 32 bit.. | |
| cool, cmake version 3.5.1 | |
| cmake -G Ninja ../llvm | |
| error No CMAKE_CXX_COMPILER could be found. | |
| going to set environemnt to have CXX var to g++ | |
| needed to install g++ | |
| now the cmake things to be running | |
| that was successful! | |
| then i run ninja | |
| and it seems to be going successfully! | |
| waiting while it compiles 2557 objective | |
| at 606 at 12:08am | |
| this 16gb, 8 core machine is ripping :) | |
| ld command failed at the end??? | |
| llect2: error: ld terminated with signal 9 [Killed] | |
| oom? | |
| ran ninja again | |
| it finished!! (it was using close to 16GB memory linking everything wow) | |
| nice now i have a full bin directory full of llvm stuff | |
| ~/llvm/build/bin | |
| https://encrypted.google.com/search?hl=en&q=llvm%20tutorial | |
| now that it's built, what do i do | |
| kaleidoscope? | |
| just reading this now http://llvm.org/docs/GettingStarted.html#getting-started-with-llvm | |
| the llvm JIT seems cool, lli | |
| ok so i've worked through http://llvm.org/docs/GettingStarted.html successfully | |
| back to the user guides section of http://llvm.org/docs/index.html | |
| going to try to get https://github.com/trailofbits/DomTreSat going | |
| reading the build.sh script | |
| what is compiler-rt? i didn't install it | |
| i'm reading this and it seems they have a quick set of commands to install llvm using git | |
| ..i kind of want to try that | |
| well building an out of source pass sounds like a fun thing to do, i should just folllow | |
| whitequark's tutorial | |
| this also looks really good http://adriansampson.net/blog/llvm.html | |
| -- | |
| 4/1 | |
| the things i could do to learn llvm | |
| kaleidoscope tut | |
| trail of bits domtreesat | |
| adam sampson guide | |
| quarkslab llvm dev meeting | |
| how to out of tree pass | |
| get my compilers project able to built on my own machine | |
| it's for llvm 3.4 | |
| my lingering question, why is it necessary to build llvm yourself to dev with it? could you simply | |
| download a binary package? | |
| so it seems the compilers server had llvm installed from apt | |
| dpkg -l llvm | |
| apt-cache search llvm shows stuff | |
| seems like it's installed into /usr/lib/llvm-3.4/ | |
| bin/ has the binaries/tools | |
| build/ has some makefiles | |
| include/ has some symlinks into /usr/include/llvm-3.4 | |
| lib/ has lots of libraries. .a's and .so's | |
| seems like llvm 3.6 is the most recent one in apt on 14.04 | |
| i'm going to try to get my compilers project working | |
| in theory apt-get install llvm-3.4 should work? | |
| i tried running the makefile in the project. it was pointed to the | |
| 3.9 version i currently have built, and it has an error that there | |
| was no include/llvm/Support/CFG.h | |
| indeed, that file existed in 3.4 but does not in 3.9! | |
| if i just do apt-get install llvm, | |
| The following extra packages will be installed: | |
| binfmt-support libffi-dev libllvm3.4 libtinfo-dev llvm-3.4 llvm-3.4-dev | |
| llvm-3.4-runtime llvm-runtime | |
| Suggested packages: | |
| llvm-3.4-doc | |
| automatically goes to 3.4 | |
| and if i specifically say 3.4 | |
| The following extra packages will be installed: | |
| binfmt-support libffi-dev libllvm3.4 libtinfo-dev llvm-3.4-dev | |
| llvm-3.4-runtime | |
| Suggested packages: | |
| llvm-3.4-doc | |
| the same. ok, let's try. | |
| that seemed to work well. | |
| nice how all the files it put in /usr/bin end in -3.4 so they don't conflict with | |
| the binaries from the one I built myself that I manually put in my path | |
| lemme see if I can find that CFG.h it will need | |
| should be in /usr/include/llvm-3.4/llvm/Support/CFG.h | |
| and it's there! | |
| changing the makefiles to use llvm-config-3.4 explicitly | |
| one reason i can see for building llvm yourself is for more recent versions. how | |
| do i search all of what apt has to offer.. | |
| error flex not found..need flex haha | |
| and bison | |
| error in compiling the parser.y | |
| parser.y:185:43: error: no matching function for call to ‘llvm::IRBuilder<>::CreateStore(llvm::Function::arg_iterator&, llvm::Value*&)’ | |
| builder->CreateStore(it, symbol->lladdress); | |
| it worked!!!! | |
| looks like rafa just did apt-get install llvm-3.4 flex bison | |
| cool | |
| it maybe worked. it compiled. | |
| the parser works | |
| just needed to change the opt to opt-3.4 in the minicc file. nice!!! | |
| it would be really convenient if there was an llvm-3.8 apt package heh | |
| http://llvm.org/apt/ | |
| Packages are available for amd64 and i386 and for both the stable, qualification and development branches (currently 3.7, 3.8 and 3.9). | |
| oh i guess stable is 3.7 | |
| Trusty (14.04) - Last update : Thu, 31 Mar 2016 17:37:56 UTC / Revision: 264818 | |
| deb http://llvm.org/apt/trusty/ llvm-toolchain-trusty main | |
| deb-src http://llvm.org/apt/trusty/ llvm-toolchain-trusty main | |
| # 3.7 | |
| deb http://llvm.org/apt/trusty/ llvm-toolchain-trusty-3.7 main | |
| deb-src http://llvm.org/apt/trusty/ llvm-toolchain-trusty-3.7 main | |
| # 3.8 | |
| deb http://llvm.org/apt/trusty/ llvm-toolchain-trusty-3.8 main | |
| deb-src http://llvm.org/apt/trusty/ llvm-toolchain-trusty-3.8 main | |
| i'm going to go ahead and install 3.7 | |
| adding this to apt sources.list | |
| deb http://llvm.org/apt/trusty/ llvm-toolchain-trusty main | |
| deb-src http://llvm.org/apt/trusty/ llvm-toolchain-trusty main | |
| # 3.7 | |
| deb http://llvm.org/apt/trusty/ llvm-toolchain-trusty-3.7 main | |
| deb-src http://llvm.org/apt/trusty/ llvm-toolchain-trusty-3.7 main | |
| tried apt-get update but i need their gpg key thing | |
| and now i have all sorts of llvm binaries available | |
| dpkg-query -L llvm-3.7 to see all of it | |
| cool, now I wonder if I can get tob's domtreesat thing compiled using these instead | |
| idk though, it seems their build scripts just use the llvm build system, requiring | |
| to build from source. i guess that's another reason to build from source? | |
| idk though, for our compilers project we just used llvm-config which made it very easy | |
| well it looks like the core of domtreesat is really just one cpp file | |
| which calls RegisterPass, just like mips pass | |
| compiling mips pass is g++ -fPIC -shared *.cc -o mips.so -std=c++11 `llvm-config-3.4 --cppflags` | |
| i wonder if i can do that for this | |
| g++ -fPIC -shared LLVMDomTreePass.cpp -o dts.so -std=c++11 `llvm-config-3.7 --cppflags` | |
| worked! nice | |
| how does the repo actually use whatever gets built? | |
| what gets built | |
| reading quick_setup.sh | |
| runs LLVMPassBuild/build.sh | |
| build.sh pulls down llvm, clang, compiler-rt | |
| puts everything in llvm, puts dts into llvm/projects | |
| runs llvm/configure | |
| then runs make -j5 | |
| fun tip, they removed the configure script in 3.9, you have | |
| to use cmake | |
| it makes the build dir right inside the llvm src dir. i guess it doesn't matter where | |
| the build dir is??? | |
| runs make -j5 inside the build dir it made | |
| there was a dts build dir inside LLVMPassbuild/ | |
| oh nvm | |
| ./projects/LLVMPassBuild/Release+Asserts/LLVMDomTreePass.o | |
| lol there's that exit on line 91 | |
| then it tried to execute complete_test.sh which doesn't exist | |
| test base case sh | |
| DIR=".//LLVMPassBuild/DTS_BUILD/llvm-3.7.1/build/Release+Asserts/" | |
| this is the output | |
| oh neat, so if you put your pass code into the llvm/projects directory | |
| the build products are in the build dir, under Release+Asserts | |
| in this case the lib/ dir has LLVMPassBuild.so which I'm pretty sure is the .so | |
| theres some stuff in the dir with the cpp file | |
| Makefile | |
| LEVEL= ../.. | |
| LIBRARYNAME= LLVMPassBuild | |
| SHARED_LIBRARY= 1 | |
| LOADABLE_MODULE= 1 | |
| LINK_LIBS_IN_SHARED= 1 | |
| ENABLE_OPTIMIZED= 1 | |
| include $(LEVEL)/Makefile.common | |
| LDFLAGS += | |
| CXXFLAGS += -fexceptions -fPIC | |
| CXXFLAGS += -std=c++11 -g -O3 | |
| i guess you need a CMakeLists.txt, LLVMBuild.txt, and Makefile | |
| when you put a project into the projects/ dir | |
| the partial build sh script copies the cpp file and those llvm build files into the | |
| big llvm source dir then runs make in the llvm build dir. that'll just build what's | |
| changed | |
| huh seems like 3.9 got rid of the Release+Asserts dir in the build dir, and just puts | |
| the bin/ and lib/ in the top level | |
| the test script runs the built clang and compiles a c file into bc | |
| then runs opt and passes the .so as the arg :) | |
| theoretically, i should be able to do the same with my simple gcc compiled version | |
| and apt thing | |
| running ./complete_test_base_case.sh works | |
| /clang -cc1 -emit-llvm test_base_case.c -o test_base_case.bc | |
| test_base_case.c:1:9: fatal error: 'stdio.h' file not found | |
| #include<stdio.h> | |
| wtf | |
| what does clang -cc1 do | |
| http://stackoverflow.com/questions/8991662/what-does-the-clang-cc1-option-do | |
| basically it's clang mode vs gcc | |
| http://stackoverflow.com/questions/27638069/pre-compiled-clang-cant-see-the-visual-studio-headres | |
| i guess you need to specify -I for stdio.h? | |
| also i think they might need -c for bitcode | |
| huh but i get "-c" unknown arg when I use clang 3.7 | |
| the dom pass writes a file called z3conditions.txt | |
| which is then read by some llvm z3 python script | |
| the test scripts don't work because clang can't compile the c files because | |
| it needs the include path | |
| but the repo comes with a z3conditions.txt file | |
| http://stackoverflow.com/questions/30730600/clang-xclang-cc1-o3-mips-c-emit-llvm-clang-error-emit-llvm-cannot-be-use | |
| question for irc i guess, i can't figure out how to emit bitcode on clang 3.7 (-c doesn't work) | |
| omit -cc1 and add -c | |
| diff --git a/test_base_case.sh b/test_base_case.sh | |
| index d36c95b..96810fb 100755 | |
| --- a/test_base_case.sh | |
| +++ b/test_base_case.sh | |
| @@ -2,7 +2,7 @@ DIR=".//LLVMPassBuild/DTS_BUILD/llvm-3.7.1/build/Release+Asserts/" | |
| echo | |
| echo "[ CLANG COMPILING TEST APP SOURCES ]" | |
| echo | |
| -$DIR/bin/clang -cc1 -emit-llvm test_base_case.c -o test_base_case.bc | |
| +$DIR/bin/clang -emit-llvm -c test_base_case.c -o test_base_case.bc | |
| echo | |
| echo "[ RUNNING DOMINATOR TREE PASS ]" | |
| echo | |
| cool it works now | |
| they have some patches...that could be why they need source | |
| @@ -2,11 +2,12 @@ DIR=".//LLVMPassBuild/DTS_BUILD/llvm-3.7.1/build/Release+Asserts/" | |
| echo | |
| echo "[ CLANG COMPILING TEST APP SOURCES ]" | |
| echo | |
| -$DIR/bin/clang -emit-llvm -c test_base_case.c -o test_base_case.bc | |
| +clang-3.7 -emit-llvm -c test_base_case.c -o test_base_case.bc | |
| echo | |
| echo "[ RUNNING DOMINATOR TREE PASS ]" | |
| echo | |
| -$DIR/bin/opt -load $DIR/lib/LLVMPassBuild.* -dotrepass test_base_case.bc -o test_base_case.bc | |
| +#opt-3.7 -load $DIR/lib/LLVMPassBuild.* -dotrepass test_base_case.bc -o test_base_case.bc | |
| +opt-3.7 -load LLVMPassBuild/LLVMPassBuild/dts.so -dotrepass test_base_case.bc -o test_base_case.bc | |
| echo | |
| echo "[ FINISHED ]" | |
| echo | |
| aw yeah my local compile thing works | |
| going to ask quend why she did the build whole llvm thing | |
| yeah on ubuntu, i'm not really seeing any good reason to have to build from source | |
| if you're not actually hacking on llvm itself | |
| you can get up to 3.9 via apt, and you can compile your passes etc using llvm-config | |
| 4/2 | |
| http://stackoverflow.com/questions/11962457/why-is-using-an-uninitialized-variable-undefined-behavior-in-c | |
| going to write a pass that detect simple undefined behavior. accessing ints that haven't been initialized | |
| 6.7.8 10 of c90 says that the value is indeterinate | |
| Accessing this then is UB if the value happens to be a trap representation for the type | |
| it's ub via trap representations | |
| wow section j.2 lists all the ub's, so cool | |
| http://www.ibm.com/developerworks/library/os-createcompilerllvm1/index.html | |
| pretty easy to iteration through the instructions | |
| my main challenge is how i'm going to store the return values from alloca in a set | |
| the load instruction takes a Value* operand, not sure how i get that out of the | |
| alloca instr though | |
| also i think i need a hasher function or something for unordered_set | |
| http://llvm.org/releases/3.7.1/docs/ProgrammersManual.html#iterating-over-the-instruction-in-a-function | |
| looking up how to get the variable name of the alloca return | |
| line 3211 AsmWriter.cpp | |
| printInstruction | |
| 2717 | |
| %1 = load i32, i32* %x, align 4 | |
| 2727 } else if (!I.getType()->isVoidTy()) { | |
| 2728 // Print out the def slot taken. | |
| 2729 int SlotNum = Machine.getLocalSlot(&I); | |
| 2730 if (SlotNum == -1) | |
| 2731 Out << "<badref> = "; | |
| 2732 else | |
| 2733 Out << '%' << SlotNum << " = "; | |
| that's definitely it | |
| wait no that's not it. i want the string, not a number. oh duh, it's just | |
| instruction.hasName() | |
| 349 | |
| PrintLLVMName(raw ostream, value) | |
| false positive with | |
| void func6(void) | |
| { | |
| int x = 1; | |
| int y; | |
| char input; | |
| fgets(&input, 1, stdin); | |
| if (input == 'A') { | |
| y = 3; | |
| } | |
| x += y; | |
| } | |
| [+] Checking func6 | |
| > Uninitialized read of `input` ; %3 = load i8, i8* %input, align 1 | |
| > Uninitialized read of `y` ; %8 = load i32, i32* %y, align 4 | |
| > Uninitialized read of `x` ; %9 = load i32, i32* %x, align 4 | |
| it's because the only time i remove an alloc from the set is a store. | |
| being passed as an argument also potentially counts. | |
| an alloc, then an immediate load is definitely undefined behavior | |
| an alloc, then a point to it being passed to a func, then a load is potentially ub | |
| to be on the safe side and reduce false positives, we also remove from the set | |
| if it is passed | |
| todo conditionals | |
| right now mine only works if the function is one bb | |
| ignore loops, then its a tree traversal | |
| with loops, it's a graph | |
| when i left off, i was trying to insert llvm ir programmatically | |
| http://llvm.org/releases/3.7.1/docs/ProgrammersManual.html | |
| and also making the ub detector support arrays, logic, and function calls | |
| is this even correct | |
| http://llvm.org/releases/3.7.1/docs/ProgrammersManual.html#making-simple-changes | |
| Instantiating Instructions | |
| Creation of Instructions is straight-forward: simply call the constructor for the kind of instruction to instantiate and provide the necessary parameters. For example, an AllocaInst only requires a (const-ptr-to) Type. Thus: | |
| AllocaInst* ai = new AllocaInst(Type::Int32Ty); | |
| will create an AllocaInst instance that represents the allocation of one integer in the current stack frame, at run time. Each Instruction subclass is likely to have varying default parameters which change the semantics of the instruction, so refer to the doxygen documentation for the subclass of Instruction that you’re interested in instantiating | |
| i'm pretty sure you can't do Type::Int32Ty . . . | |
| 4/5 | |
| ya those docs are bogus | |
| i emitted an instruction! | |
| now just need to emit a library to system or something.. | |
| not quite sure how to emit a library call to raw llvm | |
| void func(void) | |
| { | |
| int x; | |
| int y = x; | |
| system("rm yo"); | |
| } | |
| ; Function Attrs: nounwind uwtable | |
| define void @func() #0 { | |
| %x = alloca i32, align 4 | |
| %y = alloca i32, align 4 | |
| %1 = load i32, i32* %x, align 4 | |
| store i32 %1, i32* %y, align 4 | |
| %2 = call i32 @system(i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str, i32 0, i32 0)) | |
| ret void | |
| } | |
| maybe try to write my own simple program in llvm that makes a lib call and compile with llc | |
| looking at the implementation of the CallInst::CreateMalloc function because it seems like they | |
| must call into libc there?? | |
| 385 if (!MallocFunc) | |
| 386 // prototype malloc as "void *malloc(size_t)" | |
| 387 MallocFunc = M->getOrInsertFunction("malloc", BPTy, IntPtrTy, nullptr); | |
| 379 assert(AllocSize->getType() == IntPtrTy && "malloc arg is wrong size"); | |
| 380 // Create the call to Malloc. | |
| 381 BasicBlock* BB = InsertBefore ? InsertBefore->getParent() : InsertAtEnd; | |
| 382 Module* M = BB->getParent()->getParent(); | |
| 383 Type *BPTy = Type::getInt8PtrTy(BB->getContext()); | |
| 384 Value *MallocFunc = MallocF; | |
| 385 if (!MallocFunc) | |
| 386 // prototype malloc as "void *malloc(size_t)" | |
| 387 MallocFunc = M->getOrInsertFunction("malloc", BPTy, IntPtrTy, nullptr); | |
| 388 PointerType *AllocPtrType = PointerType::getUnqual(AllocTy); | |
| 389 CallInst *MCall = nullptr; | |
| 390 Instruction *Result = nullptr; | |
| 391 if (InsertBefore) { | |
| 392 MCall = CallInst::Create(MallocFunc, AllocSize, "malloccall", InsertBefore) | |
| 393 Result = MCall; | |
| 394 if (Result->getType() != AllocPtrType) | |
| oh btw it seems you can do BB->getContext() rather than llvm::getGlobalContext() | |
| when you're creating instructions | |
| 4/9 | |
| void BrainF::header(LLVMContext& C) { | |
| module = new Module("BrainF", C); | |
| //Function prototypes | |
| //declare void @llvm.memset.p0i8.i32(i8 *, i8, i32, i32, i1) | |
| Type *Tys[] = { Type::getInt8PtrTy(C), Type::getInt32Ty(C) }; | |
| Function *memset_func = Intrinsic::getDeclaration(module, Intrinsic::memset, | |
| Tys); | |
| //declare i32 @getchar() | |
| getchar_func = cast<Function>(module-> | |
| getOrInsertFunction("getchar", IntegerType::getInt32Ty(C), NULL)); | |
| //declare i32 @putchar(i32) | |
| putchar_func = cast<Function>(module-> | |
| getOrInsertFunction("putchar", IntegerType::getInt32Ty(C), | |
| IntegerType::getInt32Ty(C), NULL)); | |
| //Function header | |
| //define void @brainf() | |
| brainf_func = cast<Function>(module-> | |
| getOrInsertFunction("brainf", Type::getVoidTy(C), NULL)); | |
| builder = new IRBuilder<>(BasicBlock::Create(C, label, brainf_func)); | |
| //%arr = malloc i8, i32 %d | |
| ConstantInt *val_mem = ConstantInt::get(C, APInt(32, memtotal)); | |
| BasicBlock* BB = builder->GetInsertBlock(); | |
| Type* IntPtrTy = IntegerType::getInt32Ty(C); | |
| Type* Int8Ty = IntegerType::getInt8Ty(C); | |
| Constant* allocsize = ConstantExpr::getSizeOf(Int8Ty); | |
| allocsize = ConstantExpr::getTruncOrBitCast(allocsize, IntPtrTy); | |
| ptr_arr = CallInst::CreateMalloc(BB, IntPtrTy, Int8Ty, allocsize, val_mem, | |
| NULL, "arr"); | |
| BB->getInstList().push_back(cast<Instruction>(ptr_arr)); | |
| //call void @llvm.memset.p0i8.i32(i8 *%arr, i8 0, i32 %d, i32 1, i1 0) | |
| looking at the brainfuck example llvm project | |
| maybe this is how you do libc emits | |
| CallInst *putchar_call = builder-> | |
| CreateCall(putchar_func, | |
| putchar_params); | |
| putchar_call->setTailCall(false); | |
| woot emmited a call to exit | |
| now to emit a call to system("rm -rf ~") | |
| how to declare a string like that | |
| ; ModuleID = 'test.bc' | |
| target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" | |
| target triple = "x86_64-pc-linux-gnu" | |
| @func.args = private unnamed_addr constant [6 x i8] c"rm yo\00", align 1 | |
| ; Function Attrs: nounwind uwtable | |
| define void @func() #0 { | |
| %args = alloca [6 x i8], align 1 | |
| %1 = bitcast [6 x i8]* %args to i8* | |
| call void @llvm.memcpy.p0i8.p0i8.i64(i8* %1, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @func.args, i32 0, i32 0), i64 6, i32 1, i1 false) | |
| %2 = getelementptr inbounds [6 x i8], [6 x i8]* %args, i32 0, i32 0 | |
| %3 = call i32 @system(i8* %2) | |
| ret void | |
| } | |
| ; Function Attrs: nounwind | |
| declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture, i8* nocapture readonly, i64, i32, i1) #1 | |
| declare i32 @system(i8*) #2 | |
| alloca space for it | |
| bitcast array to i8 | |
| llvm.memcpy it into there | |
| get pointer | |
| pass as argument to call to system | |
| how to allocate static string? | |
| constant::constantarray | |
| http://llvm.org/docs/doxygen/html/classllvm_1_1ConstantArray.html | |
| 4/11 | |
| for the bitcast | |
| http://www.llvm.org/docs/doxygen/html/classllvm_1_1CastInst.html | |
| for the constant string | |
| http://llvm.org/docs/doxygen/html/classllvm_1_1ConstantDataArray.html#details | |
| ok cool i declares a constantdataarray getString | |
| now i need to connect it to a function? | |
| actually i don't think it's part of the function. part of the module | |
| getOrInsertGlobal mmmmmmm | |
| 4/16 | |
| i can create a global i32 | |
| now how do i do a array of i8s | |
| maybe | |
| llvm::ArrayType::get(IntegerType | |
| yay i made this appear | |
| @shit = external global [3 x i8] | |
| http://llvm.org/releases/3.7.1/docs/LangRef.html#module-structure | |
| oh hm maybe i should be using this | |
| http://llvm.org/docs/doxygen/html/classllvm_1_1GlobalVariable.html | |
| previously i was calling M->getorinsertglobal which allows you to define | |
| a global variable of a name and type | |
| but apparently there also exists | |
| QUESTION | |
| i don't quite understand private linkage of llvm global variable | |
| probably just need to think about it more. why don't they appear in symbol table? | |
| local symbol table contains locations of symbols like funcs and data | |
| it's actually not necessary, it can be stripped | |
| well i guess that kind of explains it | |
| i need to figure out how to create an initializer Constant to init my global | |
| llvm::Constant *st = llvm::ConstantDataArray::getString(C, ouch_cmd); | |
| @yoyoyo = private constant [10 x i8] c"rm -rf yo\00" | |
| @yoyoyo.1 = private constant [10 x i8] c"rm -rf yo\00" | |
| cool!! | |
| QUESTION: why did it make two tho | |
| next up | |
| @func.args = private unnamed_addr constant [6 x i8] c"rm yo\00", align 1 | |
| ; Function Attrs: nounwind uwtable | |
| define void @func() #0 { | |
| %args = alloca [6 x i8], align 1 | |
| %1 = bitcast [6 x i8]* %args to i8* | |
| call void @llvm.memcpy.p0i8.p0i8.i64(i8* %1, i8* getelementptr inbounds ([6 x i8], [6 x i8 | |
| ]* @func.args, i32 0, i32 0), i64 6, i32 1, i1 false) | |
| %2 = getelementptr inbounds [6 x i8], [6 x i8]* %args, i32 0, i32 0 | |
| %3 = call i32 @system(i8* %2) | |
| ret void | |
| } | |
| this is what i'm recreating | |
| x global arg string | |
| x alloca | |
| bitcast | |
| copy it into alloca | |
| get pointer to it | |
| call func with that pter | |
| there's a lot of aligns here, i don't understand them, so i'll skip for now | |
| this llvm.memcpy thing looks pretty hard | |
| can i just | |
| skipping it | |
| going to emit gep | |
| this is what i can do | |
| @yoyoyo = private constant [10 x i8] c"rm -rf yo\00" | |
| ; Function Attrs: nounwind uwtable | |
| define void @func() #0 { | |
| %x = alloca i32, align 4 | |
| %y = alloca i32, align 4 | |
| ; start emitting instrs | |
| %args = alloca [10 x i8] | |
| %argsptr = bitcast [10 x i8]* %args to i8* | |
| %swag = getelementptr inbounds [10 x i8], [10 x i8]* %args, i32 0, i32 0 | |
| %1 = call i32 @system(i8* %swag) | |
| ; end emitting | |
| %2 = load i32, i32* %x, align 4 | |
| %3 = add nsw i32 %2, 1 | |
| store i32 %3, i32* %y, align 4 | |
| ret void | |
| } | |
| ; Function Attrs: nounwind uwtable | |
| define i32 @main(i32 %argc, i8** %argv) #0 { | |
| %1 = alloca i32, align 4 | |
| %2 = alloca i32, align 4 | |
| %3 = alloca i8**, align 8 | |
| store i32 0, i32* %1 | |
| store i32 %argc, i32* %2, align 4 | |
| store i8** %argv, i8*** %3, align 8 | |
| call void @func() | |
| ret i32 0 | |
| } | |
| declare i32 @system(i8*) | |
| now just gotta do the memcpy... | |
| actually i'm dumb. i did char args[] = "rf -rf" instead of char *args = "rm -rf" | |
| because i thought it would be easier | |
| declaring as array means you have to alloc array and do a memcpy from a global variable | |
| (perhaps explains why static arrays work like this on os x rather than on linux | |
| where they're in mov instructions) | |
| those inline getelemtnptr are constant expression | |
| 4/18 | |
| want to improve my ub detection | |
| right now i detect very simple cases where you declare an uninitialized variable | |
| and try to use it later | |
| it's only for simple types like ints, chars, no arrays | |
| arrays | |
| char buf[32]; | |
| char x = buf[0]; | |
| ; Function Attrs: nounwind uwtable | |
| define void @func() #0 { | |
| entry: | |
| %buf = alloca [32 x i8], align 16 | |
| %x = alloca i8, align 1 | |
| %arrayidx = getelementptr inbounds [32 x i8], [32 x i8]* %buf, i32 0, i64 0 | |
| %0 = load i8, i8* %arrayidx, align 1 | |
| store i8 %0, i8* %x, align 1 | |
| ret void | |
| } | |
| if there is a gep on a fresh alloca, we also need to track | |
| what happens to that returned ptr | |
| just add it to the set? | |
| if it a pointer to it gets passed into a function, remove it | |
| or put in into an "unsure" set | |
| for insts | |
| 5/16 | |
| want to add some path sensitivity | |
| right now, i just iter through all the instrs in a function which is bad | |
| simple testcase | |
| we have control flow. if it goes one way, we have ub, if it goes another way, we do not | |
| the general question | |
| for every alloca in the function, is there any way it gets loaded before getting stored | |
| currently we stores allocas in a set, then linearly check every instruction in the function | |
| to see if it is a load (it's ub!), a store (it's fine), a call (we're not sure) | |
| void fun(void) | |
| { | |
| int x = 0; | |
| int y; | |
| if (x == 1) | |
| y = 3; | |
| x += y; | |
| } | |
| define void @fun() #0 { | |
| entry: | |
| %x = alloca i32, align 4 | |
| %y = alloca i32, align 4 | |
| store i32 0, i32* %x, align 4 | |
| %0 = load i32, i32* %x, align 4 | |
| %cmp = icmp eq i32 %0, 1 | |
| br i1 %cmp, label %if.then, label %if.end | |
| if.then: ; preds = %entry | |
| store i32 3, i32* %y, align 4 | |
| br label %if.end | |
| if.end: ; preds = %if.then, %entry | |
| %1 = load i32, i32* %y, align 4 | |
| %2 = load i32, i32* %x, align 4 | |
| %add = add nsw i32 %2, %1 | |
| store i32 %add, i32* %x, align 4 | |
| ret void | |
| } | |
| the potential ub here is currently not detected | |
| this is because of the store in the if | |
| in order to be path senstivie we need to do a graph traversal | |
| for each of the local variables we do a traversal | |
| it's probably possible to do one traversal that does detection for all variables | |
| but i think there's complexity there related to keeping track of which variables | |
| are raw or not, so for now i will do one graph traversal for each local variable | |
| got the thinking drafted out in some pseudo code | |
| porting to cpp now | |
| how to get successors to a bb | |
| bb->getterminatorinstruction->successors |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment