1

我正在开发的工具需要采用编译器生成的中间格式,向其中添加一些代码,然后将修改后的中间代码提供给编译器的后端以生成最终代码。

通过对 gcc 的一些研究,我发现 GIMPLE 格式很容易理解,但我不确定修改 GIMPLE 代码的复杂性,也不知道从那里重新开始编译的任何方法,除了使用插件并添加您自己的通行证。人们还警告我,文档稀缺,当您在使用 gcc 时遇到困难时,情况会变得很艰难。

另一种选择是使用 LLVM 字节码。但我从未使用过 LLVM,所以不知道使用 LLVM 我的任务会有多复杂。我不知道可能还有更好的选择。因此,我只想知道最好的选择。我的偏好如下。

  • 平台独立性
  • 便于使用
  • 有据可查
  • 更多人使用它,因此可以获得更多帮助
4

3 回答 3

1

您可能已经知道,MELT是一种用于扩展 GCC 的高级域特定语言。你可以用它很容易地处理 Gimple(等等)(也可以修改 Gcc 中的内部表示)

然而,扩展 GCC 意味着一些工作,因为 Gimple(以及 Tree)表示(与其他表示,例如 Edges..)很复杂......

于 2012-02-02T17:57:39.553 回答
1

根据您的描述,LLVM 完全符合要求。它的主要目标之一是作为一个灵活的库和框架来操作 IR 代码。它带来的无数优化、转换和分析“通过”既可以作为证明,也可以作为很好的例子。IMO LLVM 也很好地回答了您在问题中列出的 4 点:

  • 平台独立性:LLVM 在主要平台(Linux、Mac 和 Windows)上运行,并且知道如何为许多 CPU 类型生成代码。
  • 易于使用:IR 和编译器后端是一个难以破解的领域,但就这些事情而言,LLVM 是一个很好的候选者,因为它是一个相对较新的项目,有据可查,具有非常干净的代码库。
  • 有据可查:把自己打晕
  • 更多的人使用它:非常活跃的开发和使用,一些公司已经在它上投入了大量资金(最著名的是苹果和谷歌)。
于 2012-02-06T17:42:09.317 回答
0

这可能根本没有帮助,但我想知道gcc. 删节的(主要减少到 exec/fork 调用)输出来自strace -f -o gcc.strace gcc -c tstamp.c

7141  execve("/usr/bin/gcc", ["gcc", "-c", "tstamp.c"], [/* 52 vars */]) = 0
7141  open("/tmp/ccqzaCI4.s", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0600) = 3
7141  close(3)                          = 0
7141  vfork( <unfinished ...>
7142  execve("/usr/libexec/gcc/i686-redhat-linux/4.6.1/cc1", ["/usr/libexec/gcc/i686-redhat-lin"..., "-quiet", "tstamp.c", "-quiet", "-dumpbase", "tstamp.c", "-mtune=generic", "-march=i686", "-auxbase", "tstamp", "-o", "/tmp/ccqzaCI4.s"], [/* 55 vars */] <unfinished ...>
7141  <... vfork resumed> )             = 7142
7141  waitpid(7142,  <unfinished ...>
7142  <... execve resumed> )            = 0
7142  open("tstamp.c", O_RDONLY|O_NOCTTY|O_LARGEFILE) = 3
7142  close(3)                          = 0
7142  open("/tmp/ccqzaCI4.s", O_RDWR|O_CREAT|O_TRUNC|O_LARGEFILE, 0666) = 3
7142  open("/usr/include/stdio.h", O_RDONLY|O_NOCTTY|O_LARGEFILE) = 4
... (opens and closes every include file)
7142  close(4)                          = 0
7142  close(3)                          = 0
7142  exit_group(0)                     = ?
7141  <... waitpid resumed> [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], 0) = 7142
7141  vfork( <unfinished ...>
7143  execve("/usr/bin/as", ["as", "--32", "-o", "tstamp.o", "/tmp/ccqzaCI4.s"], [/* 55 vars */] <unfinished ...>
7141  <... vfork resumed> )             = 7143
7141  waitpid(7143,  <unfinished ...>
7143  <... execve resumed> )            = 0
7143  unlink("tstamp.o")                = 0
7143  open("tstamp.o", O_RDWR|O_CREAT|O_TRUNC|O_LARGEFILE, 0666) = 3
7143  open("/tmp/ccqzaCI4.s", O_RDONLY|O_LARGEFILE) = 4
7143  close(4)                          = 0
7143  close(3)                          = 0
7143  exit_group(0)                     = ?
7141  <... waitpid resumed> [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], 0) = 7143
7141  unlink("/tmp/ccqzaCI4.s")         = 0
7141  exit_group(0)                     = ?

cc1具有所有适用的逻辑。我想这是一个复杂的程序,尤其是在输入以下内容后:

/usr/libexec/gcc/i686-redhat-linux/4.6.1/cc1 --help

/usr/libexec/gcc/i686-redhat-linux/4.6.1/cc1 --help=C
于 2012-02-02T18:27:08.560 回答