LLVM GC

Hi,

I've been implementing a compiler that targets LLVM, and was looking
into using the shadow-stack gc strategy. Currently, I build the runtime
with clang (using -emit-llvm), and then link that with the LLVM bitcode
output from my compiler using llvm-ld.

This works fine without the gc strategy annotations and use of the
llvm.gcroot intrinsic, but adding them causes some odd behavior: the
resulting bitcode will generate a large stack trace from lli (appended
at the end of this message), and the resulting native assembly,
generated with llc, will never update my llvm_gc_root_chain global.

Interestingly, if I build my runtime with g++, or clang without
-emit-llvm, and link everything together after generating native
assembly from the output of my compiler, it works. The stack roots get
registered, and the llvm_gc_root_chain global gets updated.

Is linking in the runtime as an LLVM bitcode object something that I
should expect to work, or does it make more sense to build the runtime
for the target, and not try to emit LLVM bitcode programs from my compiler?

Thanks!

--trevor

0 libLLVM-2.8.so 0x0000003cc36eee9f
1 libLLVM-2.8.so 0x0000003cc36ef99a
2 libpthread.so.0 0x0000003cc200f4a0
3 libLLVM-2.8.so 0x0000003cc33360dd
llvm::StructType::StructType(llvm::LLVMContext&, std::vector<llvm::Type
const*, std::allocator<llvm::Type const*> > const&, bool) + 237
4 libLLVM-2.8.so 0x0000003cc3337c95
llvm::StructType::get(llvm::LLVMContext&, std::vector<llvm::Type const*,
std::allocator<llvm::Type const*> > const&, bool) + 533
5 libLLVM-2.8.so 0x0000003cc3242d58
6 libLLVM-2.8.so 0x0000003cc318f09e
7 libLLVM-2.8.so 0x0000003cc3330628
llvm::FPPassManager::runOnFunction(llvm::Function&) + 424
8 libLLVM-2.8.so 0x0000003cc33307cb
llvm::FunctionPassManagerImpl::run(llvm::Function&) + 91
9 libLLVM-2.8.so 0x0000003cc33309bd
llvm::FunctionPassManager::run(llvm::Function&) + 173
10 libLLVM-2.8.so 0x0000003cc33e8647
llvm::JIT::jitTheFunction(llvm::Function*, llvm::MutexGuard const&) + 39
11 libLLVM-2.8.so 0x0000003cc33e8a2f
llvm::JIT::runJITOnFunctionUnlocked(llvm::Function*, llvm::MutexGuard
const&) + 15
12 libLLVM-2.8.so 0x0000003cc33e8cde
llvm::JIT::getPointerToFunction(llvm::Function*) + 606
13 libLLVM-2.8.so 0x0000003cc33ea253
llvm::JIT::runFunction(llvm::Function*, std::vector<llvm::GenericValue,
std::allocator<llvm::GenericValue> > const&) + 67
14 libLLVM-2.8.so 0x0000003cc336ad4a
llvm::ExecutionEngine::runFunctionAsMain(llvm::Function*,
std::vector<std::string, std::allocator<std::string> > const&, char
const* const*) + 1130
15 lli 0x0000000000404cd6 main + 2054
16 libc.so.6 0x0000003cc1c1ec5d __libc_start_main + 253
17 lli 0x0000000000403689
Stack dump:
0. Program arguments: lli test.bc
1. Running pass 'Lower Garbage Collection Instructions' on function '@main'
zsh: segmentation fault (core dumped) ./test

Forgot to CC the list.

From: Samuel Crow <samuraileumas@yahoo.com>
To: Trevor Elliott <trevor@galois.com>
Sent: Fri, January 14, 2011 7:33:15 PM
Subject: Re: [LLVMdev] LLVM GC

Hi Trevor,

Are you linking with LibStdC++ or LibC++? That is a requirement for running
code that has been compiled from C++ to bitcode.

Hope this helps,

--Sam Crow

----- Original Message ----
> From: Trevor Elliott <trevor@galois.com>
> To: llvmdev@cs.uiuc.edu
> Sent: Fri, January 14, 2011 7:17:30 PM
> Subject: [LLVMdev] LLVM GC
>
> Hi,
>
> I've been implementing a compiler that targets LLVM, and was looking
> into using the shadow-stack gc strategy. Currently, I build the runtime
> with clang (using -emit-llvm), and then link that with the LLVM bitcode
> output from my compiler using llvm-ld.
>
> This works fine without the gc strategy annotations and use of the
> llvm.gcroot intrinsic, but adding them causes some odd behavior: the
> resulting bitcode will generate a large stack trace from lli (appended
> at the end of this message), and the resulting native assembly,
> generated with llc, will never update my llvm_gc_root_chain global.
>
> Interestingly, if I build my runtime with g++, or clang without
> -emit-llvm, and link everything together after generating native
> assembly from the output of my compiler, it works. The stack roots get
> registered, and the llvm_gc_root_chain global gets updated.
>
> Is linking in the runtime as an LLVM bitcode object something that I
> should expect to work, or does it make more sense to build the runtime
> for the target, and not try to emit LLVM bitcode programs from my

compiler?

Hi Sam,

I've not actually gotten to the linking process with my runtime, as I've
compiled it with clang -emit-llvm -c, and then archived it with llvm-ar
and llvm-ranlib. I'm also not producing a GC plugin, as I'm using the
builtin "shadow-stack" strategy.

My current build process looks like this:

1. build the compiler
2. build the runtime using clang -emit-llvm -c
3. generate an archive from the runtime .bc files using llvm-ar and
llvm-ranlib
3. compile a program with the compiler, producing a .bc file
4. link the program and runtime together using llvm-ld
5. run the program with lli

This all works fine until step 5 when the stack trace gets generated.
The function that it complains about, @main, is the main function from
my runtime. When disassembled with llvm-dis, it doesn't have a gc
attribute on the declaration. Should it still be getting processed by
the "shadow-stack" strategy?

Thanks!

--trevor

I've figured out why the stack trace comes from @main, and not somewhere
within my compiler's output: the output from the compiler is getting
inlined in the @main function from the runtime, thus pushing its gc
"shadow-stack" attribute out.

--trevor

Hi Everyone,

I've built a minimal test that exposes the problem that I'm encountering
[1]. The Makefile that it includes has two targets of interest,
test-llvm and test.

The test-llvm target will compile a c++ main using "clang -emit-llvm
-c", and link it with an llvm-assembly program that uses the
shadow-stack gc strategy. The asm_main function will allocate 32 bytes
using malloc, and then register that as a gc root, using the llvm.gcroot
intrinsic. It will then print the value of the llvm_gc_root_chain
global, and exit.

The test target will build the c++ main using "clang -c" producing
native code, then use llc and as to produce a native object from the
asm-main.bc bitcode file. It then links everything together using clang
to produce a native executable called test.

The test-llvm target will produce the stack trace that I attached in a
previous message, while the test target produces a program that will
output a non-nil value for the llvm_gc_root_chain when run.
Disassembling test.bc using llvm-dis shows that everything has been
inlined into the @main function, though I'm not sure if this is actually
a problem.

Is there a reason that the test-llvm target isn't working? I was under
the impression that the shadow-stack gc strategy was available when
using lli, though there certainly could be something wrong with the way
I'm putting all of the constituents together.

Thanks,

--trevor

[1] http://www.internetofdeath.com/~moltar/gc.tar.gz