在阅读了使用蹦床在 LLVM 中生成闭包之后,我尝试编译一些在互联网上漂浮的蹦床示例(特别是这个)。gist 中给出的 LLVM IR 如下:
declare void @llvm.init.trampoline(i8*, i8*, i8*);
declare i8* @llvm.adjust.trampoline(i8*);
define i32 @foo(i32* nest %ptr, i32 %val) {
%x = load i32* %ptr
%sum = add i32 %x, %val
ret i32 %sum
}
define i32 @main(i32, i8**) {
%closure = alloca i32
store i32 13, i32* %closure
%closure_ptr = bitcast i32* %closure to i8*
%tramp_buf = alloca [32 x i8], align 4
%tramp_ptr = getelementptr [32 x i8]* %tramp_buf, i32 0, i32 0
call void @llvm.init.trampoline(
i8* %tramp_ptr,
i8* bitcast (i32 (i32*, i32)* @foo to i8*),
i8* %closure_ptr)
%ptr = call i8* @llvm.adjust.trampoline(i8* %tramp_ptr)
%fp = bitcast i8* %ptr to i32(i32)*
%res = call i32 %fp (i32 13)
ret i32 %res
}
但是,使用clang trampolines.ll
并执行它编译它会导致SIGSEGV
(fish 给出的确切错误是fish: Job 1, './a.out ' terminated by signal SIGSEGV (Address boundary error)
)。
经过一些测试,事实证明“蹦床”函数的调用是导致 SIGSEGV 的指令,因为将其注释掉(并返回一个虚拟值)工作正常。
问题似乎也不在于clang
两者,因为手动运行llvm-as
等llc
也不起作用。在另一台机器上编译也不起作用。这让我相信我的机器或 LLVM 做错了什么。
我的铿锵版本:
Apple LLVM version 6.1.0 (clang-602.0.49) (based on LLVM 3.6.0svn)
Target: x86_64-apple-darwin14.3.0
Thread model: posix