关于LLVM IR和Valgrind 中间语言区别

来源:互联网 发布:网络论坛系统cms 编辑:程序博客网 时间:2024/06/05 11:01

1、         LLVMValgrind简介

LLVM(Low Level VirtualMachine)是伊利诺伊州立大学香槟分校的ChrisLattner主持开发的一个编译器框架。随着ChrisLattner去苹果公司,LLVM作为苹果公司官方支持的编译器。相比于GCCLLVM很多方面在性能都超过GCCLLVM2012年获得ACM软件系统奖。

Valgrind是一款用于内存调试、内存泄露检测以及性能分析的软件开发工具,它是一个由来自全世界的开发者组织合作开发得到的软件,他的初始作者在2006年获得第二节Google-O’Reilly开源代码奖。

2、         LLVM的结构和LLVM IR(IntermediateRepresentation)

LLVM作为编译器后端不负责将源程序语言转换成为LLVMIR,这部分由各自语言的编译器前端完成,ClangC/C++/Object-C语言的前端;llvm-gcc可以作为Fortran语言的前端。当编译器前端将语言编译成为LLVMIR之后,LLVM就对IR进行优化,根据平台(x86arm等)不一样,把LLVMIR编译器转换成为对应平台的机器语言然后执行,或者可以JIT执行。LLVM的结构如下所示:

      LLVM IR在整个过程中是一种承上启下作用,它与源语言无关,与执行平台无关,它是一种SSA(Static SingleAssignment)形式的代码,和RISC指令很像的指令,它被设计成为三地址形式。

      下面是一个对应的例子:

程序的源码:

int mian()

{

  int a = 10;

  int b = 20;

  int c = a + b;

  int d = b / a;

  return 0;

}

对应的LLVM中间代码:

; 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:

  %a = alloca i32, align4

  %b = alloca i32, align4

  %c = alloca i32, align4

  %d = alloca i32, align4

  store i32 10, i32* %a, align4          //a=10

  store i32 20, i32* %b, align4          //b=20

  %0 = load i32* %a, align4

  %1 = load i32* %b, align4

  �d = add nsw i32 %0,%1          //a+b

  store i32 �d, i32* %c, align4       //c=a+b

  %2 = load i32* %b, align4

  %3 = load i32* %a, align4

  %div = sdiv i32 %2,%3             // b/a

  store i32 %div, i32* %d, align4

  ret i320

}

 

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、         Valgrind的结构和VEX IR

LLVM不同的是,Valgrind不需要程序的源代码,Valgrind直接对可执行文件进行操作,目前为止它已经支持大多数的主流平台(X86,ARM,AMD)Valgrind在对可执行文件进行分析的时候,相当于添加了一个Vargrind自己的虚拟层,其结构图如下所示:

关于LLVM <wbr>IR <wbr>和 <wbr>Valgrind <wbr>IR的调研报告

Valgrind首先初始化VEX二进制翻译引擎,接着VEX的前端将可执行文件的二进制代码装换成为VEX中间代码表示(IR),然后Valgrind工具对VEX中间代码进行优化和插桩,最后VEX后端将VEX IR翻译成为机器码执行程序。Valgrind内部结构图如下所示:

关于LLVM <wbr>IR <wbr>和 <wbr>Valgrind <wbr>IR的调研报告

Valgrind的中间代码形式如下图所示:

关于LLVM <wbr>IR <wbr>和 <wbr>Valgrind <wbr>IR的调研报告

 

左边是机器码对应的汇编代码,右边则是那VEX IR的中间代码表示。从图中可以看出VEX IR是一种二地址形式的中间表示,对于每一条机器指令,VEX将它翻译成为VEX IR中的一个基本块。VEX IR是一种和RISC指令集很相似的指令集,也是SSA(Static SingleAssignment)形式的,这就意味它可以有无穷数量的变量。对于每一个变量它都有类型,不存在隐式的类型转换。

Valgrind内部的检测工具根据自己的需求会对VEX IR插桩一些自己需要的指令,当指令插桩完成,VEXBack-End首先为SSA形式的变量分配寄存器,然后将VEX IR转换成为机器码,然后执行。其转换如下:

VEX IR中间表示:

关于LLVM <wbr>IR <wbr>和 <wbr>Valgrind <wbr>IR的调研报告

 

为其中的变量分配寄存器:

关于LLVM <wbr>IR <wbr>和 <wbr>Valgrind <wbr>IR的调研报告

 

翻译成为机器码:

关于LLVM <wbr>IR <wbr>和 <wbr>Valgrind <wbr>IR的调研报告

 

 

4、         两者的共同点

1)     它们都是程序存在的中间形式,都代表程序在特定时间段存在方式,都能很好地表示程序的含义。

2)     它们都是SSA形式,可以拥有无数的变量,只是需要在生成机器码的时候采用寄存器分配算法为这些变量分配合适的寄存器即可。

3)     它们类RISC形式的指令集,意味着它们只需要一些简单易用的指令即可,对于复杂的操作需要将这些简单的指令进行组合。

5、         两者的区别

1)   LLVM IR来源于源代码,通过编译器前端将源程序语言转换得到。而VEX IR则是通过对可行文件的机器码进行翻译得到,不需要源程序。

2)   LLVM IR是三地址形式的,而VEX IR是二地址形式。LLVMIR采用三地址形式的好处是在表示类型的时候可以用像‘I32’这样的形式表示,同时其中并不适用寄存器,这样可以使其目标平台无关。而VEX IR则与平台相关。

3)   LLVM IR作为编译器的中间语言,有很强大的功能,在程序分析方面,LLVMIR目前只用于静态分析,VEX IR则用于动态分析。LLVMIR被用于静态分析的时候不会对其中插入一些外部的指令,VEX IR需要插桩一些用于检测的指令。

6、         总结

LLVMIRVEX IR都是很好的中间表示,他们有很多共同点,由于目标不同,所以它们也存在一些区别。LLVM作为一个越来越受欢迎的编译器框架,LLVMIR作为其中间代码表示会被更多的人所认识。VEX IR作为动态分析工具Valgrind的中间表示,会被更多专业相关的人所接受。

 

 

原创粉丝点击