我目前正在为一种玩具语言编写一个编译器;这对我来说是一个新的领域。我使用 LLVM C++ API来生成LLVM IR,并从那里生成一个对象。
问题在于(我认为)链接对象并能够执行它。
我有main.ll
,由我能想出的绝对最小的IR组成:
define void @main() {
ret void
}
这在lli main.ll
中运行得很好,也就是说,它什么也不做。
我用:llc --filetype=obj -o main.{o,ll}
将其编译成对象格式。
并链接到没有使用:ld.lld -o main{,.o}
的现有库
然而,产生的二进制立即分段错误。我采纳了一些教程的建议,这些教程引导我尝试通过GCC链接,我被告知,“在制作饼对象时不能使用Relocations”,维基百科告诉我,它指的是所产生的二进制文件中的位置独立性。
因此,我重新编译为object with:llc --filetype=obj --relocation-model=pic main.{o,ll}
,并与GCC一起重新编译,运行输出并没有像预期的那样工作。
但是,再次运行ld.lld
命令并尝试运行该二进制文件,再次,立即执行分段错误。
所以,我的第一个问题是:对于这个简单的例子,在链接对象(假设我链接正确)和二进制之间,我遗漏了什么步骤?。
是否有我缺少的ld
标志,一些必需的库,即使我没有特别使用其中的任何一个?
当我试图链接到libc来使用IR中的printf
时,即使GCC方法也有更多的问题,但是我认为在攻击它之前,我需要更好地理解这个简单的例子。
任何帮助都将不胜感激。
发布于 2020-10-24 13:55:31
对于任何发现这一点并试图将.ll
文件变成可执行文件的人,我已经发现C运行时库是缺少的。在默认情况下,gcc
和clang
都包括了这些选项,但是-v
选项并没有给我带来太多遗憾.
使用PIC_
的LLVM下的PIC_
并将结果对象动态地链接到C运行时库中,我设法使.ll
文件定期运行。
一个示例命令(显然是OS特定的)将是:
ld --verbose -L/usr/lib -lc \
-dynamic-linker \
/lib64/ld-linux-x86-64.so.2 \
/usr/lib/Scrt1.o \
/usr/lib/crti.o \
/usr/lib/gcc/x86_64-pc-linux-gnu/10.2.0/crtbeginS.o \
/usr/lib/gcc/x86_64-pc-linux-gnu/10.2.0/crtendS.o \
<object file> \
-o <binary> \
/usr/lib/crtn.o
除了猜测之外,我还不能百分之百地确定这件事的“原因”,但这是可行的,而且您的标准ld -L... -lc <object file>
没有。
如果有人能作出澄清,我很乐意接受他们的答覆。
https://stackoverflow.com/questions/64490897
复制相似问题