LLVM IR到编译后的可执行段错误

时间:2020-10-22 21:37:34

标签: compilation llvm executable llvm-ir

我目前正努力为玩具语言编写编译器;这对我来说是一个新领域。我正在使用 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进行链接,并得知“制作PIE对象时无法使用[[重定位]”,而Wikipedia告诉我这是指结果二进制文件中的位置独立性。 / p>

所以我用llc --filetype=obj --relocation-model=pic main.{o,ll}重新编译为对象,并用GCC重新编译,并且它起作用了,运行输出并没有达到预期的效果。

但是再次运行ld.lld命令并再次尝试运行该二进制文件,则会立即出现段错误。

所以,我的第一个问题是:在这个简单的示例中,链接对象(假设我正确链接)和二进制文件之间缺少什么步骤?

我是否缺少ld标志,即使我没有特别使用某个标志,也缺少一些必需的库?


当我尝试链接到libc以在IR中使用printf时,甚至还有GCC方法的更多问题,但我认为在攻击之前,我需要对这个简单的示例有更好的了解。

任何帮助将不胜感激。

1 个答案:

答案 0 :(得分:0)

对于其他找到此文件并尝试将.ll文件制成可执行文件的人:我发现C运行时库丢失了。 gccclang都默认包含这些选项,但是-v选项并没有给我带来太多麻烦……

使用PIC_的LLVM下的relocation model并将结果对象与C运行时库动态链接,我设法使.ll文件能够正常运行。

一个示例命令(显然是特定于操作系统的)是:

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>并不可行。

如果有人可以提供说明,我会很乐意接受他们的回答。