生成LLVM IR及其CFG图
math.c代码
int add(int a, int b) { return a+b; } int mul(int a, int b) { return a*b; } void Test() { int r1 = add(1,2); int r2 = mul(3,4); }
编译生成IR中间代码math.ll
clang.exe -S -emit-llvm math.c -o math.ll
math.ll代码如下:
; ModuleID = 'math.c' source_filename = "math.c" target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-pc-windows-msvc19.29.30152" ; Function Attrs: noinline nounwind optnone uwtable define dso_local i32 @add(i32, i32) #0 { %3 = alloca i32, align 4 %4 = alloca i32, align 4 store i32 %1, i32* %3, align 4 store i32 %0, i32* %4, align 4 %5 = load i32, i32* %4, align 4 %6 = load i32, i32* %3, align 4 %7 = add nsw i32 %5, %6 ret i32 %7 } ; Function Attrs: noinline nounwind optnone uwtable define dso_local i32 @mul(i32, i32) #0 { %3 = alloca i32, align 4 %4 = alloca i32, align 4 store i32 %1, i32* %3, align 4 store i32 %0, i32* %4, align 4 %5 = load i32, i32* %4, align 4 %6 = load i32, i32* %3, align 4 %7 = mul nsw i32 %5, %6 ret i32 %7 } ; Function Attrs: noinline nounwind optnone uwtable define dso_local void @Test() #0 { %1 = alloca i32, align 4 %2 = alloca i32, align 4 %3 = call i32 @add(i32 1, i32 2) store i32 %3, i32* %1, align 4 %4 = call i32 @mul(i32 3, i32 4) store i32 %4, i32* %2, align 4 ret void } attributes #0 = { noinline nounwind optnone uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="false" "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"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } !llvm.module.flags = !{!0, !1} !llvm.ident = !{!2} !0 = !{i32 1, !"wchar_size", i32 2} !1 = !{i32 7, !"PIC Level", i32 2} !2 = !{!"clang version 9.0.1 (https://github.com/llvm-project.git 4dc5e59b6369d07ec453a3da46cf7fb51ce487ba)"}
生成函数调用关系CFG图
opt.exe -dot-callgraph math.ll
注1:CFG(control-flow graph)即控制流图
注2:上述命令会生成callgraph.dot的CFG文件
callgraph.dot文件内容如下:
digraph "Call graph" { label="Call graph"; Node0x2abc6af0cb0 [shape=record,label="{external node}"]; Node0x2abc6af0cb0 -> Node0x2abc6af1220; Node0x2abc6af0cb0 -> Node0x2abc6af1430; Node0x2abc6af0cb0 -> Node0x2abc6af0f50; Node0x2abc6af1220 [shape=record,label="{add}"]; Node0x2abc6af1430 [shape=record,label="{mul}"]; Node0x2abc6af0f50 [shape=record,label="{Test}"]; Node0x2abc6af0f50 -> Node0x2abc6af1220; Node0x2abc6af0f50 -> Node0x2abc6af1430; }
Graphviz Interactive预览如下:
生成函数CFG图
opt.exe -dot-cfg math.ll
注:会为math.ll中每个函数都生成一个.dot文件(形如.函数名.dot)
.add.dot代码如下:
digraph "CFG for 'add' function" { label="CFG for 'add' function"; Node0x1f698b61d50 [shape=record,label="{%2:\l %3 = alloca i32, align 4\l %4 = alloca i32, align 4\l store i32 %1, i32* %3, align 4\l store i32 %0, i32* %4, align 4\l %5 = load i32, i32* %4, align 4\l %6 = load i32, i32* %3, align 4\l %7 = add nsw i32 %5, %6\l ret i32 %7\l}"]; }
Graphviz Interactive预览如下:
.mul.dot代码如下:
digraph "CFG for 'mul' function" { label="CFG for 'mul' function"; Node0x1f698b62230 [shape=record,label="{%2:\l %3 = alloca i32, align 4\l %4 = alloca i32, align 4\l store i32 %1, i32* %3, align 4\l store i32 %0, i32* %4, align 4\l %5 = load i32, i32* %4, align 4\l %6 = load i32, i32* %3, align 4\l %7 = mul nsw i32 %5, %6\l ret i32 %7\l}"]; }
Graphviz Interactive预览如下:
.Test.dot代码如下:
digraph "CFG for 'Test' function" { label="CFG for 'Test' function"; Node0x1f698b624d0 [shape=record,label="{%0:\l %1 = alloca i32, align 4\l %2 = alloca i32, align 4\l %3 = call i32 @add(i32 1, i32 2)\l store i32 %3, i32* %1, align 4\l %4 = call i32 @mul(i32 3, i32 4)\l store i32 %4, i32* %2, align 4\l ret void\l}"]; }
Graphviz Interactive预览如下:
文件总览