使用中间格式的最简单方法

时间:2012-02-02 17:50:24

标签: c gcc compiler-construction llvm intermediate-code

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

通过对gcc进行一些研究,我发现GIMPLE格式很容易理解,但我不确定修改GIMPLE代码的复杂性,也不知道从那里重新启动编译的任何方法除了使用插件并添加自己的传递。还有人警告我,文档很少,当你在使用gcc时遇到困难时会发生变化。

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

  • 平台独立性
  • 易于使用
  • 记录良好
  • 更多人使用它,所以提供更多帮助

3 个答案:

答案 0 :(得分:1)

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

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

答案 1 :(得分:1)

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

  • 平台独立性:LLVM在主要平台(Linux,Mac和Windows)上运行,并且知道如何为许多CPU类型生成代码。
  • 易于使用:IR和编译器后端是一个很难攻击的领域,但就这些问题而言,LLVM是一个很好的选择,因为它是一个相对较新的项目,有很好的文档记录,代码库非常干净。
  • 记录良好:knock yourself out
  • 更多人使用它:非常活跃的开发和使用,一些公司已经大量投资(最着名的是苹果和谷歌)。

答案 2 :(得分:0)

这可能没什么用,但我想知道gcc的处理过程。从strace -f -o gcc.strace gcc -c tstamp.c输出的删节(主要是减去exec / fork调用):

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