1、
LLVM(Low Level VirtualMachine)是伊利诺伊州立大学香槟分校的ChrisLattner主持开发的一个编译器框架。随着ChrisLattner去苹果公司,LLVM作为苹果公司官方支持的编译器。相比于GCC,LLVM很多方面在性能都超过GCC。LLVM在2012年获得ACM软件系统奖。
Valgrind是一款用于内存调试、内存泄露检测以及性能分析的软件开发工具,它是一个由来自全世界的开发者组织合作开发得到的软件,他的初始作者在2006年获得第二节Google-O’Reilly开源代码奖。
2、
LLVM作为编译器后端不负责将源程序语言转换成为LLVMIR,这部分由各自语言的编译器前端完成,Clang是C/C++/Object-C语言的前端;llvm-gcc可以作为Fortran语言的前端。当编译器前端将语言编译成为LLVMIR之后,LLVM就对IR进行优化,根据平台(x86、arm等)不一样,把LLVMIR编译器转换成为对应平台的机器语言然后执行,或者可以JIT执行。LLVM的结构如下所示:
int mian() { } |
; ModuleID = 'test.ll' target datalayout ="e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:32:32-n8:16:32-S128" target triple = "i386-pc-linux-gnu" ; Function Attrs: nounwind define i32 @_Z4mianv() #0 { entry: } attributes #0 = { nounwind"less-precise-fpmad"="false" "no-frame-pointer-elim"="true""no-frame-pointer-elim-non-leaf"="true" "no-infs-fp-math"="false""no-nans-fp-math"="false" "unsafe-fp-math"="false""use-soft-float"="false" } |
从上图可以看出中间代码的基本结果,最开始是一些目标平台的信息,结尾是一些属性,这两部分不是LLVMIR的重点,除此之外,LLVMIR可以分为三部分:全局变量、函数和符号表入口(上图没有)。从LLVMIR可以看出他的三地址形式,同时它的类型表示都是用像‘i32’这样的形式,还没有指定特定的寄存器,这样即达到了与目标平台无关的目的。
3、
与LLVM不同的是,Valgrind不需要程序的源代码,Valgrind直接对可执行文件进行操作,目前为止它已经支持大多数的主流平台(X86,ARM,AMD)。Valgrind在对可执行文件进行分析的时候,相当于添加了一个Vargrind自己的虚拟层,其结构图如下所示:
Valgrind首先初始化VEX二进制翻译引擎,接着VEX的前端将可执行文件的二进制代码装换成为VEX 中间代码表示(IR),然后Valgrind工具对VEX中间代码进行优化和插桩,最后VEX后端将VEX IR翻译成为机器码执行程序。Valgrind内部结构图如下所示:
Valgrind的中间代码形式如下图所示:
左边是机器码对应的汇编代码,右边则是那VEX IR的中间代码表示。从图中可以看出VEX IR是一种二地址形式的中间表示,对于每一条机器指令,VEX将它翻译成为VEX IR中的一个基本块。VEX IR是一种和RISC指令集很相似的指令集,也是SSA(Static SingleAssignment)形式的,这就意味它可以有无穷数量的变量。对于每一个变量它都有类型,不存在隐式的类型转换。
Valgrind内部的检测工具根据自己的需求会对VEX IR插桩一些自己需要的指令,当指令插桩完成,VEXBack-End首先为SSA形式的变量分配寄存器,然后将VEX IR转换成为机器码,然后执行。其转换如下:
VEX IR中间表示:
为其中的变量分配寄存器:
翻译成为机器码:
4、
1)
2)
3)
5、
1)
2)
3)
6、
LLVMIR和VEX IR都是很好的中间表示,他们有很多共同点,由于目标不同,所以它们也存在一些区别。LLVM作为一个越来越受欢迎的编译器框架,LLVMIR作为其中间代码表示会被更多的人所认识。VEX IR作为动态分析工具Valgrind的中间表示,会被更多专业相关的人所接受。