LLVM解释器在寻找外部函数(库?)

问题描述:

我正在玩LLVM IR,并且我无法解决(在google和doc的帮助下)LLVM解释器lli正在寻找外部函数(没有明确定义的函数。意味着基本的系统功能)。例如,如果我想写出没有依赖简单的程序,在Linux上,这将写在屏幕上的东西,我可以做这样的事情:LLVM解释器在寻找外部函数(库?)

@message = private constant [12 x i8] c"hello world\0A" 
define i32 @puts(i8* %s) { 
    call i32 asm sideeffect "movl $$0x2, %edi\0Amovl $$0xC, %edx\0Amovl$$1, %eax\0Asyscall\0A", "=A,{si}"(i8* %s) #1 
    ret i32 %1 
} 
define void @exit(i32 %c) { 
    call i32 asm sideeffect "movl $$60, %eax\0Asyscall\0A", "=A,{di}"(i32 %c) #1 
    ret void 
} 
define void @main() { 
    getelementptr [12 x i8], [12 x i8]* @message, i64 0, i64 0 
    call i32 @puts(i8* %1) 
    call void @exit(i32 0) 
    ret void 
} 
define void @_start() { 
    call void @main() 
    ret void 
} 

main_start是与ldlli交叉兼容性。所以上面的代码在两者中都是一样的我可以lli这个,并且代码将从mainllc然后ld开始,它也会工作,因此代码将从_start按预期开始。现在,如果我写的代码:

@formatString = private constant [4 x i8] c"%d\0A\00" 
declare i32 @printf(i8*, ...) 
define i32 @main() { 
    %d = shl i32 2, 3 
    %s = getelementptr [4 x i8], [4 x i8]* @formatString, i64 0, i64 0 
    %call = call i32 (i8*, ...) @printf(i8* %s, i32 %d) 
    ret i32 0 
} 

它也适用于lli,但我不能ld,因为ld不知道参考printf这也在意料之中。我可以包括准备ld参数以使代码也起作用,或者干脆使用gcc file.o -o file,但这不是我的观点。我的意思是如何让lli不包含任何外部库(如libc),只运行我的代码,并可能定义我自己的入口点,所以我可以随意包含任何准备好的libc或任何其他库,我知道我可以覆盖功能的名称,并应该工作,但后来我不知道什么被重写,所以我会很高兴,如果lli抛出错误,如果printf被使用但未定义。或者,也许我错了,lli无法在这样的环境中执行。

+1

我发现'lli -entry-function = _start file.ll'可以选择任何入口点。但仍不知道如何去除预装代码的解释器。有选项'-extra-object = '但我找不到选项来禁用默认加载的所有对象。 – mucka

TL; DR:使用lli没有JIT的也许可以工作:

lli -force-interpreter main.bc 

更多信息:

一般而言,这取决于一个类型,你罩下使用JIT引擎(如果有的话)。

我不能约MCJIT(-jit-kind=mcjit)说话,因为我不熟悉,但我可以向你保证,如果你使用ORC JIT(-jit-kind=orc-mcjit-jit-kind=orc-lazy),这是不可能的。但是,这仅适用于lli,如果您决定自行使用ORC,则可以控制此行为。

lli的背景下,ORC不仅加载你的模块/外部对象,而且加载整个程序的地址空间。这意味着你得到了所有的libc和整个LLVM本身。

根据您的需要,您可能会尝试使用lli作为解释器,但由于不再涉及JIT,因此速度会更慢。

只需添加-force-interpreter选项,除非少数例外,您将很乐意继续。这些功能仍然会正常执行:

void Interpreter::initializeExternalFunctions() { 
    sys::ScopedLock Writer(*FunctionsLock); 
    (*FuncNames)["lle_X_atexit"]  = lle_X_atexit; 
    (*FuncNames)["lle_X_exit"]   = lle_X_exit; 
    (*FuncNames)["lle_X_abort"]  = lle_X_abort; 

    (*FuncNames)["lle_X_printf"]  = lle_X_printf; 
    (*FuncNames)["lle_X_sprintf"]  = lle_X_sprintf; 
    (*FuncNames)["lle_X_sscanf"]  = lle_X_sscanf; 
    (*FuncNames)["lle_X_scanf"]  = lle_X_scanf; 
    (*FuncNames)["lle_X_fprintf"]  = lle_X_fprintf; 
    (*FuncNames)["lle_X_memset"]  = lle_X_memset; 
    (*FuncNames)["lle_X_memcpy"]  = lle_X_memcpy; 
} 
+0

不幸的是,我已经尝试过了,也许问题是我正在使用官方git新鲜的'LLVM version 5.0.0svn'。我担心问题是我可以访问解释器为itselt预装的所有功能。无论如何,谢谢你的回答! – mucka

+0

我想知道如果我可以使用'mcjit-remote-process'来实现更多的裸机环境,但是“标准的”远程进程'https://github.com/llvm-mirror/llvm/blob/master/tools/lli/ChildTarget/ChildTarget.cpp'看起来不太有希望。 – mucka

+0

我会建议设置您的自定义JIT堆栈。非常基本的自定义lli是相当容易和小。如果您需要帮助[email protected],请随时联系我 – AlexDenisov