0%

Introduction to LLVM

What is LLVM?

LLVM的全名是Low Level Virtual Machine,和一般所知的Virtual Machine(VMWare, VirtualBox等)不同,他是一種編譯器架構。主要分成

  • 前端: Source Code -> BitCode
  • 後端: BitCode -> Native Code

由於BitCode的獨立性,可以很容易的跨平台。

而LLVM主要有以下幾個特性:

  1. RISC Like的指令集
  2. 以SSA(Static Single-Assignment) 形式提供數目不設限的虛擬暫存器
  3. 以Load/store 指令存取型態定義的指標(Typed-Pointer)
  4. 基於SSA可明確資料在運作過程中的傳遞流程
  5. 提供跟語言無關的形態資訊
  6. 在exception的支援上提供 setjmp/longjmp實作的Exception機制,並提供 invoke指令可呼叫一個需要帶有Exception Handler的函式,與提供Unwind指令,能透過Stack Frame回推到上一個invoke指令位置.

如何使用LLVM

在這裡我們使用Clang來當FrontEnd,將C語言轉換成BitCode。

依舊從Hello World開始

接著我們編譯此檔案

1
$ clang -S -emit-llvm hello.c

此時目錄下生成了hello.s,觀看其內容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
; ModuleID = 'hello.c'
target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-freebsd9.0"

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

define i32 @main() nounwind uwtable {
entry:
%retval = alloca i32, align 4
store i32 0, i32* %retval
%call = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([14 x i8]* @.str, i32 0, i32 0))
ret i32 0
}

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

注意,在這邊我們有加上 -emit-llvm的選項,表示我們要使用LLVM的對應組件,如果沒加這命令的話,其作用跟一般的Native Complier相同,如下。

1
$ clang -S hello.c

一樣產生hello.s,但是內容完全不同

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
        .file   "hello.c"
.text
.globl main
.align 16, 0x90
.type main,@function
main: # @main
.Ltmp2:
.cfi_startproc
# BB#0: # %entry
pushq %rbp
.Ltmp3:
.cfi_def_cfa_offset 16
.Ltmp4:
.cfi_offset %rbp, -16
movq %rsp, %rbp
.Ltmp5:
.cfi_def_cfa_register %rbp
subq $16, %rsp
leaq .L.str, %rdi
movl $0, -4(%rbp)
movb $0, %al
callq printf
movl $0, %ecx
movl %eax, -8(%rbp) # 4-byte Spill
movl %ecx, %eax
addq $16, %rsp
popq %rbp
ret
.Ltmp6:
.size main, .Ltmp6-main
.Ltmp7:
.cfi_endproc
.Leh_func_end0:

.type .L.str,@object # @.str
.section .rodata.str1.1,"aMS",@progbits,1
.L.str:
.asciz "Hello World!\n"
.size .L.str, 14


.section ".note.GNU-stack","",@progbits

如何產生 BitCode

1
$ clang -emit-llvm hello.c -c -o hello.bc

如何用 LLVM的JIT執行BitCode

1
$ lli hello.bc

如何看BitCode的Assembly Code

1
$ llvm-dis < hello.bc | less

如何用BitCode產生 Native Assembly Code

1
$ llc hello.bc -o hello.s

如何用BitCode產生Native Machine Code

可以直接從BitCode下手,或是從上一步驟產生出來的Assembly Code下手

1
2
$ clang hello.bc -o hello_native
$ clang hello.s -o hello_native