LLVM IR(一)——如何使用LLVM编译执行代码

可以转载,请注明出处!

文章目录

    • 1.1 LLVM IR的三种结构
    • 1.2将C文件转为LLVM IR汇编码
    • 1.3将LLVM IR汇编码转为bitcode
    • 1.4执行LLVM bitcode
    • 1.5链接LLVM bitcode
    • 1.6自己写一个IR然后编译执行
    • 1.7编译C接口的API,执行生成IR
        • 编写生成IR的C++代码
        • 编译C++代码生成可执行文件

在阅读这一章节之前,需要本地安装llvm环境,没安装可以参考这里:https://blog.csdn.net/qq_42570601/article/details/107146407

1.1 LLVM IR的三种结构

LLLLVM的代码有3种表示形式(三种形式等价):

  • 1)内存编译器中的IR,用户不可知。
  • 2)存于磁盘的 bitcode,是一个二进制文件,以.bc为后缀,用户可以看到,但是看不懂。
  • 3)用户可读的汇编码,这个就是我们要学习和编写的IR,以.ll为后缀。

1.2将C文件转为LLVM IR汇编码

1> 首先在你已经安装了llvm环境的Linux系统中,选择一个你方便的目录,创建一个*.c文件,文件中用C的语法写一个简单的程序,比如输出hello world,下面我创建的是tpy.c文件。

在这里插入图片描述
LLVM IR(一)——如何使用LLVM编译执行代码_第1张图片

//tpy.c文件
#include 

int main(){
        printf("Hello World!");
		return 0}

2> 使用以下命令来将C语言代码转换成LLVM IR:clang -emit-llvm -S tpy.c -o tpy.ll
这里有所有的命令:https://llvm.org/docs/CommandGuide/index.html

在这里插入图片描述

3> 生成如下的LLVM IR文件tpy.ll:

; ModuleID = 'tpy.c'
source_filename = "tpy.c"
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"

@.str = private unnamed_addr constant [13 x i8] c"Hello World!\00", align 1

; Function Attrs: noinline nounwind optnone uwtable
define i32 @main() #0 {
entry:
  %call = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([13 x i8], [13 x i8]* @.str, i32 0, i32 0))
  ret i32 0
}

declare i32 @printf(i8*, ...) #1

attributes #0 = { noinline nounwind optnone uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }

!llvm.module.flags = !{!0}
!llvm.ident = !{!1}

!0 = !{i32 1, !"wchar_size", i32 4}
!1 = !{!"clang version 6.0.0 (tags/RELEASE_600/final)"}

此时的tpy.ll文件还不能执行,因为这是一种用户可读的IR中间码,如果要执行该文件,还需要将其转成二进制文件bitcode。

1.3将LLVM IR汇编码转为bitcode

执行以下命令把tpy.ll文件的LLVM IR转为bitcode格式:llvm-as tpy.ll –o tpy.bc
在这里插入图片描述
生成的tpy.bc文件内容如下:
LLVM IR(一)——如何使用LLVM编译执行代码_第2张图片

1.4执行LLVM bitcode

执行命令:lli tpy.bc,可以输出如下内容:

在这里插入图片描述

1.5链接LLVM bitcode

  • 1.、为了展示llvm-link的功能,首先在不同文件中编写两段代码,其 中一个引用另一个:
// $ cat test1.c 被引用文件
 int func(int a) {
 a = a*2;
 return a; 
 }
// $ cat test2.c 引用文件
 #include
 extern int func(int a);
int main() {
 int num = 5;
 num = func(num);
 printf("number is %d\n", num);
 return num;
 } 
  • 2、使用以下命令将C代码转换成位流文件格式,先转成.ll文件,再 将.ll文件转成.bc文件:
clang -emit-llvm -S test1.c -o test1.ll 
clang -emit-llvm -S test2.c -o test2.ll 
llvm-as test1.ll -o test1.bc 
llvm-as test2.ll -o test2.bc 

我们得到了test1.bc和test2.bc,而test2.bc引用了test1.bc文件中的func 语法。

  • 3、通过如下方式使用llvm-link命令链接两个LLVM bitcode文件:
llvm-link test1.bc test2.bc –o output.bc
  • 4、执行output.bc文件
lli output.bc

1.6自己写一个IR然后编译执行

IR基本语法参考链接:https://blog.csdn.net/qq_42570601/article/details/107157224

在你已经安装了llvm环境的Linux系统中,选择一个你方便的目录,创建一个.ll文件,编写一段IR代码,然后同1步骤中的一样:
llvm-as tpy.ll –o tpy.bc,用该命令汇编。
lli tpy.bc,用该命令执行。

LLVM IR(一)——如何使用LLVM编译执行代码_第3张图片

上面这个程序的输出结果是31。

1.7编译C接口的API,执行生成IR

使用API参考链接:https://blog.csdn.net/qq_42570601/article/details/107771289

编写生成IR的C++代码

生成IR有以下几种方式:

  • 1)通过c++直接使用Instructions.h文件中的命令来生成IR
  • 2)使用llvm提供的c接口来生成IR,官方文档:https://llvm.org/doxygen/group__LLVMCCore.html
  • 3)使用IRBuilder来生成IR,官方文档:http://llvm.org/doxygen/classllvm_1_1IRBuilder.html

需要会使用的是2、3,IRBuilder是对C接口指令类的封装,所以这两个要结合看,用2生成module、function等,用到指令就用IRBuilder。

在你已经安装了llvm环境的Linux系统中,选择一个你方便的目录,创建一个.cpp文件,编写C++代码。

编译C++代码生成可执行文件

下面main.cpp就是一个用C++编写的自动生成IR的代码,编写好代码后,使用下面命令即可生成可执行文件:

clang++ -O3 main.cpp -o main `llvm-config --cflags --ldflags` `llvm-config --libs` `llvm-config --system-libs`

在这里插入图片描述

使用./main命令执行可执行文件main,执行结果如下:

LLVM IR(一)——如何使用LLVM编译执行代码_第4张图片

你可能感兴趣的:(LLVM,linux,运维,服务器)