I'm trying to compile a function ("fun") to LLVM IR and create a Module using the ParseIR function. The program segfaults at the call to ParseIR. I'm using LLVM 3.5 and the code is below.
#include <cstdio>
#include <iostream>
#include <sstream>
#include <string>
#include "llvm/ADT/StringRef.h"
#include "llvm/Bitcode/ReaderWriter.h"
#include "llvm/ExecutionEngine/ExecutionEngine.h"
#include "llvm/ExecutionEngine/MCJIT.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IRReader/IRReader.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_os_ostream.h"
using std::cout;
using std::endl;
using std::ostringstream;
using std::string;
using llvm::getGlobalContext;
using llvm::LLVMContext;
using llvm::MemoryBuffer;
using llvm::Module;
using llvm::ParseIR;
using llvm::SMDiagnostic;
using llvm::StringRef;
int main() {
string fun = "int fun(int x) {return x;}\n";
string cmd = "echo '" + fun + "' |"
+ " clang++ -cc1 -xc++ -O0 -std=c++1y -fno-use-cxa-atexit"
+ " -I/usr/local/lib/clang/3.5.0/include/"
+ " -I/usr/include/c++/4.9/"
+ " -I/usr/include/x86_64-linux-gnu/c++/4.9/bits/"
+ " -I/usr/include/x86_64-linux-gnu -I/usr/include/"
+ " -I/usr/include/x86_64-linux-gnu/c++/4.9/"
+ " -I/usr/lib/gcc/x86_64-linux-gnu/4.9/include/"
+ " -I/usr/include/c++/4.9/backward/"
+ " -I/usr/lib/gcc/x86_64-linux-gnu/4.9/include-fixed/"
+ " -stdlib=libstdc++ -S -emit-llvm"
+ " -o /dev/stdout 2> /dev/stdout";
FILE *file = popen(cmd.c_str(), "r");
ostringstream llvm;
char line[1024];
while (fgets(line, 1024, file))
llvm << line;
pclose(file);
LLVMInitializeNativeTarget();
LLVMInitializeNativeAsmPrinter();
LLVMContext &ctx = getGlobalContext();
SMDiagnostic *err;
StringRef ref = StringRef(llvm.str().c_str());
MemoryBuffer *buff = MemoryBuffer::getMemBuffer(ref);
cout << "***** C++ *****\n" << fun << "\n"
<< "***** LLVM *****\n" << llvm.str() << endl;
//segfault
Module *mod = ParseIR(buff, *err, ctx);
return 0;
}
I compiled and ran the above code using the following command:
g++ -std=c++14 fun.cpp -o fun `llvm-config --cxxflags --ldflags --libs --system-libs`
./fun
***** C++ *****
int fun(int x) {return x;}
***** LLVM *****
; ModuleID = '-'
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"
; Function Attrs: nounwind
define i32 #_Z3funi(i32 %x) #0 {
%1 = alloca i32, align 4
store i32 %x, i32* %1, align 4
%2 = load i32* %1, align 4
ret i32 %2
}
attributes #0 = { nounwind "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
!llvm.ident = !{!0}
!0 = metadata !{metadata !"clang version 3.5.1 (branches/release_35 225591)"}
Segmentation fault (core dumped)
You do not initialize your SMDiagnostic* but dereference it in the call to ParseIR. That is why your program seg faults. See the comments in the code for a fix.
LLVMInitializeNativeTarget();
LLVMInitializeNativeAsmPrinter();
LLVMContext &ctx = getGlobalContext();
SMDiagnostic err; // create an SMDiagnostic instance
MemoryBuffer* buff = MemoryBuffer::getMemBuffer(llvm.str());
cout << "***** C++ *****\n" << fun << "\n"
<< "***** LLVM *****\n" << llvm.str() << endl;
Module *mod = ParseIR(buff, err, ctx); // use err directly
Related
I have a problem with openssl and the EVP-functions:
When I execute the following code
#include <openssl/evp.h>
#include <openssl/engine.h>
#include <array>
#include <iostream>
void hash(ENGINE* eng) {
EVP_MD_CTX *_mdctx(EVP_MD_CTX_create());
int ret = EVP_DigestInit_ex(_mdctx, EVP_sha512(), eng);
EVP_MD_CTX_destroy(_mdctx);
if(1 == ret) {
std::cout << "Finished successfully (with eng=" << eng << ")" << std::endl;
return;
} else {
std::array<char, 256> err_str;
ERR_error_string_n(ERR_get_error(), err_str.data(), err_str.size());
std::cout << "Error at Digest (engine: " << ENGINE_get_id(eng) << "): " << err_str.data() << std::endl;
}
}
int main(void) {
ENGINE_load_builtin_engines();
hash(nullptr);
for(ENGINE *eng = ENGINE_get_first(); eng != nullptr; eng = ENGINE_get_next(eng)) {
hash(eng);
}
}
I get the following output:
Finished successfully (with eng=0)
Error at Digest (engine: rdrand): error:260BA093:engine routines:ENGINE_get_digest:unimplemented digest
Error at Digest (engine: dynamic): error:06080086:digital envelope routines:EVP_DigestInit_ex:initialization error
I understand, that rdrand doesn't support digest, but why do I get an initialization error, when I use the dynamic engine? In particular why does it work, when I call EVP_DigestInit_ex with eng=nullptr?
The code can be compiled with g++ example.cpp -std=c++17 -Wall -Wextra -Werror -pedantic -O2 -lssl -lcrypto. I am using g++, version 6.3.0 and openssl 1.1.0f.
I've written a standard Analysis pass in LLVM, by extending the FunctionPass class. Everything seems to make sense.
Now what I'd like to do is write a couple of intermodular passes, that is, passes that allows me to analyze more than one module at a time. The purpose of one such pass is to construct a call graph of the entire application. The purpose of the other such pass is that I have an idea for an optimization involving function calls and their parameters.
I know about interprocedural passes in LLVM, via extending the ModulePass class, but that only allows analysis within a single module.
I know about link time optimization (LTO) in LLVM, but (a) I'm not quite clear if this is what I want and (b) I've found no examples or documentation on how to actually write an LTO pass.
How can I write an intermodular pass, i.e., a pass that has access to all the modules in an application, in LLVM?
I found one way to achieve my goal: write a simple program that uses llvm::parseBitcodeFile() to read in a bitcode file and create a Module object that can be traversed and analyzed. It's not ideal, because it's not a Pass that can be run within the LLVM framework. However, it is a way to achieve my goal of analyzing multiple modules at once.
For future readers, here's what I did.
Create a simple tool to read in a bitcode file and produce a Module
//ReadBitcode.cpp
#include <iostream>
#include "llvm/IR/Module.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/Bitcode/ReaderWriter.h"
using namespace llvm;
int main(int argc, char *argv[])
{
if (argc != 2)
{
std::cerr << "Usage: " << argv[0] << " bitcode_filename" << std::endl;
return 1;
}
StringRef filename = argv[1];
LLVMContext context;
ErrorOr<std::unique_ptr<MemoryBuffer>> fileOrErr = MemoryBuffer::getFileOrSTDIN(filename);
if (std::error_code ec = fileOrErr.getError())
{
std::cerr << "Error opening input file: " + ec.message() << std::endl;
return 2;
}
ErrorOr<llvm::Module *> moduleOrErr = parseBitcodeFile(fileOrErr.get()->getMemBufferRef(), context);
if (std::error_code ec = fileOrErr.getError())
{
std::cerr << "Error reading Module: " + ec.message() << std::endl;
return 3;
}
Module *m = moduleOrErr.get();
std::cout << "Successfully read Module:" << std::endl;
std::cout << " Name: " << m->getName().str() << std::endl;
std::cout << " Target triple: " << m->getTargetTriple() << std::endl;
for (auto iter1 = m->getFunctionList().begin(); iter1 != m->getFunctionList().end(); iter1++)
{
Function &f = *iter1;
std::cout << " Function: " << f.getName().str() << std::endl;
for (auto iter2 = f.getBasicBlockList().begin(); iter2 != f.getBasicBlockList().end();
iter2++)
{
BasicBlock &bb = *iter2;
std::cout << " BasicBlock: " << bb.getName().str() << std::endl;
for (auto iter3 = bb.begin(); iter3 != bb.end(); iter3++)
{
Instruction &i = *iter3;
std::cout << " Instruction: " << i.getOpcodeName() << std::endl;
}
}
}
return 0;
}
Compile the tool
$ clang++ ReadBitcode.cpp -o reader `llvm-config --cxxflags --libs --ldflags --system-libs`
Create a bitcode file to analyze
$ cat foo.c
int my_fun(int arg1){
int x = arg1;
return x+1;
}
int main(){
int a = 11;
int b = 22;
int c = 33;
int d = 44;
if (a > 10){
b = c;
} else {
b = my_fun(d);
}
return b;
}
$ clang -emit-llvm -o foo.bc -c foo.c
Run the reader tool on the bitcode
$ ./reader foo.bc
Successfully read Module:
Name: foo.bc
Target triple: x86_64-pc-linux-gnu
Function: my_fun
BasicBlock:
Instruction: alloca
Instruction: alloca
Instruction: store
Instruction: load
Instruction: store
Instruction: load
Instruction: add
Instruction: ret
Function: main
BasicBlock:
Instruction: alloca
Instruction: alloca
Instruction: alloca
Instruction: alloca
Instruction: alloca
Instruction: store
Instruction: store
Instruction: store
Instruction: store
Instruction: store
Instruction: load
Instruction: icmp
Instruction: br
BasicBlock:
Instruction: load
Instruction: store
Instruction: br
BasicBlock:
Instruction: load
Instruction: call
Instruction: store
Instruction: br
BasicBlock:
Instruction: load
Instruction: ret
This can be done using a module pass. Below is my code, and if you need help running it you can look here.
bar.c
int your_fun(int arg2) {
int x = arg2;
return x+2;
}
Skeleton.cpp
#include "llvm/Pass.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
using namespace llvm;
namespace {
struct SkeletonPass : public ModulePass {
static char ID;
SkeletonPass() : ModulePass(ID) {}
virtual bool runOnModule(Module &M) {
for (auto& F : M) {
errs() << "\tFunction: " << F.getName() << "\n";
for (auto& BB : F) {
errs() << "\t\tBasic Block: " << BB.getName() << "\n";
for (auto& I : BB) {
errs() << "\t\t\tInstruction: " << I.getOpcodeName() << "\n";
}
}
}
return false;
}
};
}
char SkeletonPass::ID = 0;
// Automatically enable the pass.
// http://adriansampson.net/blog/clangpass.html
static void registerSkeletonPass(const PassManagerBuilder &,
legacy::PassManagerBase &PM) {
PM.add(new SkeletonPass());
}
static RegisterStandardPasses RegisterMyPass(PassManagerBuilder::EP_ModuleOptimizerEarly,
registerSkeletonPass);
static RegisterStandardPasses RegisterMyPass1(PassManagerBuilder::EP_EnabledOnOptLevel0,
registerSkeletonPass);
Output:
| => clang -Xclang -load -Xclang build/skeleton/libSkeletonPass.so foo.c bar.c
Module: foo.c!
Function: my_fun!
Basicblock: entry!
Instruction: alloca
Instruction: alloca
Instruction: store
Instruction: load
Instruction: store
Instruction: load
Instruction: add
Instruction: ret
Function: main!
Basicblock: entry!
Instruction: alloca
Instruction: alloca
Instruction: alloca
Instruction: alloca
Instruction: alloca
Instruction: store
Instruction: store
Instruction: store
Instruction: store
Instruction: store
Instruction: load
Instruction: icmp
Instruction: br
Basicblock: if.then!
Instruction: load
Instruction: store
Instruction: br
Basicblock: if.else!
Instruction: load
Instruction: call
Instruction: store
Instruction: br
Basicblock: if.end!
Instruction: load
Instruction: ret
Module: bar.c!
Function: your_fun!
Basicblock: entry!
Instruction: alloca
Instruction: alloca
Instruction: store
Instruction: load
Instruction: store
Instruction: load
Instruction: add
Instruction: ret
Output: If you include header file linking to bar.c
Module: foo.c!
Function: your_fun!
Basicblock: entry!
Instruction: alloca
Instruction: alloca
Instruction: store
Instruction: load
Instruction: store
Instruction: load
Instruction: add
Instruction: ret
Function: my_fun!
Basicblock: entry!
Instruction: alloca
Instruction: alloca
Instruction: store
Instruction: load
Instruction: store
Instruction: load
Instruction: add
Instruction: ret
Function: main!
Basicblock: entry!
Instruction: alloca
Instruction: alloca
Instruction: alloca
Instruction: alloca
Instruction: alloca
Instruction: store
Instruction: store
Instruction: store
Instruction: store
Instruction: store
Instruction: load
Instruction: icmp
Instruction: br
Basicblock: if.then!
Instruction: load
Instruction: store
Instruction: br
Basicblock: if.else!
Instruction: load
Instruction: call
Instruction: store
Instruction: load
Instruction: call
Instruction: store
Instruction: br
Basicblock: if.end!
Instruction: load
Instruction: ret
In LTO all the modules are combined and you can see the whole program IR in one module.
You need to write a module pass like any module pass and add it to the list of LTO passes in populateLTOPassManager function in PassManagerBuilder.cpp. Here is the doc for PassManagerBuilder:
http://llvm.org/docs/doxygen/html/classllvm_1_1PassManagerBuilder.html
When you do this, your pass will be executed with other LTO passes.
Currently I test a shared library vendor provided in linux ,
the following is the simple source :
#include <iostream>
using namespace std;
extern int test1();
extern int test2();
int main()
{
cout << "hello world" << endl ;
return 0 ;
cout << "Test 1" << endl;
test1();
cout << "Test 2" << endl;
test2();
return 0;
}
I have compile and link like :
g++ -g -Wall -fPIC -D_DEBUG -o test -I./include32 src/xxx.cpp src/yyy.cpp src/test.cpp
-L./lib32 -lshare1 -lshared2
I have the following output while run :
hello world
***glibc detected *** ./test: double free or corrution (!prev) 0x00000000077ec30 ***
What I don't get is , since I only do print "hello world" and then return 0 ,
that mean I don't call any function in libshared1.so and libshared2.so ,
why error like glibc detected happen ? does it mean that shared library has
problem to be loaded to memory ? since the main function never call test1() , test2()
which really call functions in libshared1.so and libshared2.so !!
And suggestions , comments are most appreciated !!
Edit :
#include <iostream>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
using namespace std;
int main()
{
cout << "hello world 3 " << endl ;
void *handle2;
handle2 = dlopen ("/usr/local/lib/xxx.so", RTLD_LAZY);
if (!handle2) {
fprintf (stderr, "%s\n", dlerror());
exit(1);
}
cout << "hello world 1 " << endl ;
void *handle3;
handle3 = dlopen ("/usr/local/lib/yyy.so", RTLD_LAZY);
if (!handle3) {
fprintf (stderr, "%s\n", dlerror());
exit(1);
}
cout << "hello world" << endl ;
}
Compile :
g++ -g -Wall -rdynamic -o test src/test.cpp -ldl
Output :
hello world 3
hello world 1
Segmentation fault (core dumped)
The Vendor really provide damaged shared library ?!
For a project I'm writing I need to write a custom Lua module loading system, and I've done it before on my Raspberry Pi, but not on my Mac. The problem is that as soon as I try to access the lua_State in the shared object, the program segfaults.
main.cpp
#include <lua.hpp>
#include <dlfcn.h>
#include <iostream>
typedef void Register(lua_State*);
int main(){
lua_State* L = luaL_newstate();
void* lib = dlopen("module.so", RTLD_NOW);
if(!lib){
std::cerr << "Error opening module \"" << "\": " << dlerror() << std::endl;
return;
}
Register* loadFunc = (Register*)dlsym(lib, "RegisterModule");
if(!loadFunc){
std::cerr << "Error loading symbols from module \"" << "\": " << dlerror() << std::endl;
return;
}
loadFunc(L);
for(;;){}
return 1;
}
module.cpp
#include <lua.hpp>
#include <iostream>
static int Foo(lua_State* L){
std::cout << "Hello World!" << std::endl;
}
extern "C" void RegisterModule(lua_State* L){
lua_pushcfunction(L, Foo);
lua_setglobal(L, "Foo");
}
Makefile
lua = -L /usr/lib/lua5.2 -I /usr/include/lua5.2 -llua
luaHeaders = -I /usr/include/lua5.2
all: main module.so
rm -f main.o
main: main.o
clang++ main.o -o main $(lua) -ldl
main.o: main.cpp
clang++ -c main.cpp $(luaHeaders)
module.so: module.cpp
clang++ -fPIC -shared module.cpp -o module.so $(lua)
My setup is:
Mac OS X 10.9 Mavericks, and Elementary OS Luna
Lua 5.2
Clang
Output from the debugger (lldb)
Process 19943 stopped
* thread #2: tid = 0x23ec1c, 0x0000000100295c31 myModule.so`luaH_newkey + 913, stop reason = EXC_BAD_ACCESS (code=2, address=0x100073db0)
frame #0: 0x0000000100295c31 myModule.so`luaH_newkey + 913
myModule.so`luaH_newkey + 913:
-> 0x100295c31: movq %rax, 16(%r12)
0x100295c36: movl 8(%rbx), %eax
0x100295c39: movl %eax, 24(%r12)
0x100295c3e: testb $64, 8(%rbx)
I have the following code snippet that compiles
QByteArray block;
QDataStream out(&block, QIODevice::WriteOnly);
for (QStringList::Iterator it = commandList.begin(); it != commandList.end(); ++it) {
out << "Command: " << *it << endl;
}
but always gives me this warning:
test.cpp:87: warning: the address of 'QTextStream& endl(QTextStream&)' will always evaluate as 'true' [-Waddress]
What does it mean and how do I fix it? Since a newline character is printing I assume this is not a namespace issue...
When you are using a binary data stream, it is not a good practice to start inserting new lines. That is one of the main points over a simple QTextStream.
This code works fine for me without any warning with gcc version 4.8.1 20130725 (prerelease) (GCC)
main.cpp
#include <QByteArray>
#include <QDataStream>
#include <QIODevice>
#include <QStringList>
int main()
{
QStringList commandList = QStringList() << "foo" << "bar" << "baz";
QByteArray block;
QDataStream out(&block, QIODevice::WriteOnly);
for (QStringList::Iterator it = commandList.begin(); it != commandList.end(); ++it)
out << "Command: " << *it;
}
Building
g++ -std=c++11 -Wpedantic -Wall -I/usr/include/qt -I/usr/include/qt/QtCore -lQt5Core -fPIC main.cpp