Global variables on LLVM JIT on ARM (Android)

Hi all,

I’m trying to extend the Dalvik VM to load some LLVM assembly from the SD card, JIT it, and execute it. I’m using AOSP 4.0.4, a Galaxy Nexus, and the version of LLVM that comes in the external project of AOSP (LLVM 2.8, I believe?)

I have the following LLVM assembly:

target datalayout = “e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:32:64-v128:32:128-a0:0:32-n32-S32”
target triple = “armv7–”

@runtime_val = global i32 7, align 4

define i32 @method() {
entry:
%ret = load i32* @runtime_val, align 4
ret i32 %ret
}

When I use getPointerToFunction() after loading this assembly with ParseAssemblyFile(), I get the following stderr output, and then a segfault:

UNREACHABLE executed!
Stack dump:
0. Running pass ‘ARM Machine Code Emitter’ on function ‘@method

And here’s the GDB backtrace:

#0 __libc_android_abort () at bionic/libc/unistd/abort.c:82

#1 0x40e35600 in llvm::llvm_unreachable_internal (msg=0x0, file=, line=) at external/llvm/lib/Support/ErrorHandling.cpp:98
#2 0x409d34ac in (anonymous namespace)::ARMCodeEmitter::getMovi32Value (this=, MI=, MO=, Reloc=8)
at external/llvm/lib/Target/ARM/ARMCodeEmitter.cpp:439
#3 0x409e237c in (anonymous namespace)::ARMCodeEmitter::emitDataProcessingInstruction (this=0x1a7a338, MI=…, ImplicitRd=0, ImplicitRn=0)
at external/llvm/lib/Target/ARM/ARMCodeEmitter.cpp:1036
#4 0x409e2ba0 in (anonymous namespace)::ARMCodeEmitter::emitInstruction (this=0x1a7a338, MI=…) at external/llvm/lib/Target/ARM/ARMCodeEmitter.cpp:555
#5 0x409e2e68 in (anonymous namespace)::ARMCodeEmitter::runOnMachineFunction (this=0x1a7a338, MF=…)
at external/llvm/lib/Target/ARM/ARMCodeEmitter.cpp:399
#6 0x40bb6f10 in llvm::MachineFunctionPass::runOnFunction (this=0x1a7a338, F=) at external/llvm/lib/CodeGen/MachineFunctionPass.cpp:33
#7 0x40dfc234 in llvm::FPPassManager::runOnFunction (this=0x1a65100, F=…) at external/llvm/lib/VMCore/PassManager.cpp:1498

#8 0x40dfc34c in llvm::FunctionPassManagerImpl::run (this=0x1a2ea50, F=…) at external/llvm/lib/VMCore/PassManager.cpp:1449
#9 0x40dfc5a4 in llvm::FunctionPassManager::run (this=0x1a6c608, F=…) at external/llvm/lib/VMCore/PassManager.cpp:1379
#10 0x409aa988 in llvm::JIT::jitTheFunction (this=0x1a6c550, F=0x1, locked=…) at external/llvm/lib/ExecutionEngine/JIT/JIT.cpp:645
#11 0x409aa9ac in llvm::JIT::runJITOnFunctionUnlocked (this=0xdeadbaad, F=0x1, locked=…) at external/llvm/lib/ExecutionEngine/JIT/JIT.cpp:624
#12 0x409aac50 in llvm::JIT::getPointerToFunction (this=0x1a6c550, F=0x1a6aef8) at external/llvm/lib/ExecutionEngine/JIT/JIT.cpp:681
<…snip…>

Is there something obviously wrong with the way I’m declaring this global variable and then reading its value, that would lead to this segfault?

Cheers,
Stephen

Hi Stephen,

UNREACHABLE executed!
Stack dump:
0. Running pass 'ARM Machine Code Emitter' on function '@method'

LLVM currently has two completely independent JIT implementations, and this fault indicates you're trying to use the legacy one which can just about be relied on not to fail horribly for x86 (usually).

The newer system is called the MCJIT, and *should* work on ARM. If you look at how lli is implemented (tools/lli/lli.cpp) you should be able to see calls to "setUseMCJIT" which you'll want to duplicate in your code.

Your .ll code looks fine.

Cheers.

Tim

The newer system is called the MCJIT, and *should* work on ARM. If you look at how lli is implemented (tools/lli/lli.cpp) you should be able to see calls to "setUseMCJIT" which you'll want to duplicate in your code.

Side note: this won't work in 2.8 :slight_smile: In any case, asking for proper
ARM codegen in 2.8 is a big challenge.

The newer system is called the MCJIT, and should work on ARM. If you look at how lli is implemented (tools/lli/lli.cpp) you should be able to see calls to “setUseMCJIT” which you’ll want to duplicate in your code.