我正在研究LLVM IR,但无法通过谷歌和文档解决一个问题:LLVM解释器lli
在哪里查找外部(未显式定义的函数,即基本系统函数)。例如,如果我想编写一个不依赖其他库,在Linux上可以将一些内容输出到屏幕上的简单程序,我可以像这样做:
@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
是为了与ld
和lli
的交叉兼容而存在的。因此,以上代码在两者中都可以正常工作。我可以使用lli
来运行它,代码将从main
开始执行;或者使用llc
编译,然后用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
或其他库,我知道我可以重写函数名称来达到这个目的,但那样我就无法确定哪些内容已被重写,所以如果 printf
被使用但未定义,我会很高兴看到 lli
抛出错误。或者我可能理解错了,lli
不能在这种裸环境中运行。
lli -entry-function=_start file.ll
可以选择任何入口点。但是我仍然不知道如何剥离预加载代码的解释器。有一个选项-extra-object=<object>
,但我找不到禁用默认加载的所有对象的选项。 - mucka