llvm學習(一)————朦胧的感觉


做个开始标记:       

       在上大学的时候,就想拥有一个自己的博客,想要写出一些有质量的博文。现在回过头来,感到很失望,博文数量少,质量差。在这里将记录我的llvm学习之路,希望和朋友交流学习。

       以前多多少少接触过一点llvm的东东,现在想要全面系统的学习一下。下面是我收集到的一些资料,提供链接。

下面两个链接,自认为可以让我们知道究竟什么是llvm,对llvm的框架做了概括的介绍,可以是我们对llvm有个整体把握。

使用 LLVM 框架创建一个工作编译器,第 1 部分    (在此附编译方法:test$ clang++  IRBuilder.cpp  `llvm-config --cppflags --ldflags --libs core` -o IRBuilder)

使用 LLVM 框架创建有效的编译器,第 2 部分

下面两个链接是我学习写第一个pass所找的资料,希望对大家有帮助:

llvm官方提供的写pass的方法

一位台湾同胞写的第一个pass(自认为更适合llvm初学者)  PS:众所周知的原因,该博文无法正常访问,我将其附在我的博文后面,如果可以访问,请尽量访问原作者博文。

官方llvm-programmer-s-manual文档的中文翻译































































附录一 :LLVM 寫一個 pass - 教學入門篇

注意!! 這篇文章並非官方的 Writing an LLVM Pass 的中文翻譯版本!!



而是精簡版, 採用建置方式是將 pass 的程式碼獨立於 LLVM 的 Source tree 外
這樣的好處是可避免與整串 LLVM 搞在一起, 並且對於整體建置流程會較為清楚

這篇文章對於讀者有些假設 :
  1. 已經會建置 LLVM (不會? 建置與安裝 LLVM + Clang)
  2. 對於 Makefile 有一點基礎知識 (沒有? 快來惡補)


1. 先從 LLVM 抄一個 Hello Pass
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#define DEBUG_TYPE "hello"
#include "llvm/Pass.h"
#include "llvm/Function.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/ADT/Statistic.h"
usingnamespacellvm;
 
namespace{
  // Hello - The first implementation, without getAnalysisUsage.
  structHello : publicFunctionPass {
    staticcharID;// Pass identification, replacement for typeid
    Hello() : FunctionPass(ID) {}
 
    virtualboolrunOnFunction(Function &F) {
      errs() << "Hello: ";
      errs() << F.getName() << '\n';
      returnfalse;
    }
  };
}
 
charHello::ID = 0;
staticRegisterPass<Hello> X("hello","Hello World Pass");
將上列程式碼儲存成 Hello.cpp 或著任何你喜歡的檔名
原程式碼上面有一些授權宣告跟註解, 基於文章版面配置將那部份移除, 其詳細授權見LLVM Developer Policy 
說明?能建置成功前先把細節拋一邊吧

2. 建置 Makefile
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
LLVM_CONFIG=llvm-config
 
CXX=`$(LLVM_CONFIG) --bindir`/clang
CXXFLAGS=`$(LLVM_CONFIG) --cppflags` -fPIC -fno-rtti
LDFLAGS=`$(LLVM_CONFIG) --ldflags`
 
all: hello.so
 
hello.so: Hello.o
        $(CXX) -shared Hello.o -o hello.so $(LDFLAGS) -fPIC
 
Hello.o: Hello.cpp
        $(CXX) -c Hello.cpp -o Hello.o $(CXXFLAGS)
 
clean:
        rm-f *.o hello.so
把上面內容抄到與 Hello.cpp 同目錄下的 Makefile 中
注意一下 Makefile 建置動作前面的是 Tab 字元不是空白字元, 相當重要
這邊唯一要注意的是 LLVM_CONFIG 要設定為 你安裝的 llvm 路徑裡面的那個 llvm-config
例如 LLVM 裝在家目錄底下, 那麼 LLVM_CONFIG 就設定為 /home/kito/bin/llvm-config 

3. 建置與測試
接著執行 make, 
?
1
make
應該會吐出下面兩行 
?
1
2
`llvm-config --bindir`/clang-c Hello.cpp -o Hello.o `llvm-config --cppflags` -fPIC
`llvm-config --bindir`/clang-shared Hello.o -o hello.so `llvm-config --ldflags` -fPIC
然後目錄下應該會出現 Hello.so 才對 
?
1
2
ls
# Hello.cpp  Hello.o  hello.so  Makefile
接著寫個 Hello World 的小程式 
?
1
2
3
4
5
#include <stdio.h>
 
intmain () {
  printf("Hello LLVM!\n");
}
將以上簡單內容存檔成 HelloWorld.c 接著把 Hello World 產生 .bc 檔, 加上 -emit-llvm 告訴 llvm 你要產生 bitcode 
?
1
clang -c -emit-llvm -o HelloWorld.bcHelloWorld.c
最後步驟就是把你的 HelloWorld.bc 丟到前面寫的 Hello Pass ! 
?
1
opt -load ./hello.so -hello HelloWorld.bc-o/dev/null
後面 -o /dev/null 的意思是叫 opt 把經過最佳化或分析的結果直接丟掉
執行完後 LLVM 就會跟你說 Hello 了!
?
1
Hello: main
main 是你 Hello World 中的 Function 名稱
4. 回頭看一下 Hello Pass
DEBUG_TYPE 是 LLVM 拿來統計該 pass 被呼叫幾次或著是使用 DEBUG 輸出除錯訊息的時候用的
?
1
#define DEBUG_TYPE "hello"
include 要用到的 LLVM 的
?
1
2
3
4
#include "llvm/Pass.h"
#include "llvm/Function.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/ADT/Statistic.h"
把 llvm namespace 的東西都弄進來, 雖然這是不好的習慣, 不過由於方便起見直接 using 下去吧XD
?
1
usingnamespacellvm;
匿名 namespace, 避免 export 裡面的 symbol,
聽無上一句在講啥就先跳過就可以了
?
1
namespace{
Hello 繼承 FunctionPass, 代表 Hello Pass 的輸入是以 Function 為單位
?
1
2
// Hello - The first implementation, without getAnalysisUsage.
structHello : publicFunctionPass {
現階段下面這行就照抄吧
給 LLVM 用來識別這個 Pass 的 id
?
1
staticcharID;// Pass identification, replacement for typeid
Constructor
?
1
Hello() : FunctionPass(ID) {}
這邊則是整個 pass 的精華所在, LLVM 會以一次一個 Function 為單位, 餵進來給你玩
大致上裡面的行為就是將餵進來的 Function 的名稱印出來而已
其中 return false 是告訴 LLVM 你沒有修改任何東西
?
1
2
3
4
5
virtualboolrunOnFunction(Function &F) {
  errs() << "Hello: ";
  errs() << F.getName()) << '\n';
  returnfalse;
}
class 跟 namespace 的結束, 沒啥好說的
?
1
2
  };
}
定義下一下 Hello::ID 的實體
?
1
charHello::ID = 0;
跟 LLVM 註冊你的這個 Pass, 第一個參數是 pass name, 第二個則是說明用的文字
?
1
staticRegisterPass<hello> X("hello","Hello World Pass");

5. 解析 Makefile
先指定 llvm-config 執行檔的所在位置, 如果 llvm-config 已經加到 PATH 中的話那就填 llvm-config 就好
?
1
LLVM_CONFIG=llvm-config
llvm-config 這隻程式可以幫你產生出大部分你所需的 flag
用 --help 可以檢視所有可用選項
?
1
llvm-config --help
指定編譯器使用 clang, 單純個人喜好XD
?
1
CXX=`$(LLVM_CONFIG) --bindir`/clang
指定編譯的參數, 大部分從 llvm-config --cppflags 即可,
但由於我們現在是要編譯的是 Shared Library 所以要加 -fPIC
不知道 Shared Library 是啥? 快去弄一本程式設計師的自我修養來 K 阿~~
-fno-rtti 則是指定不產生 Run-time Typeinfo 的資訊,加了此選項後 typeid 及 dynamic_cast 會無法使用,基於實作成本 LLVM 在這方面有實作自己一套的 RTTI 機制
?
1
CXXFLAGS=`$(LLVM_CONFIG) --cppflags` -fPIC -fno-rtti
指定 Link 的參數, 大部分從 llvm-config --ldflags 即可,
現在是要編譯的是 Shared Library 所以加 -shared
?
1
LDFLAGS=`$(LLVM_CONFIG) --ldflags` -shared
我們總共要建置 hello.so
?
1
all: hello.so
hello.so 怎麼生勒?, 生之前要先生出 Hello.o
然後下面一行則是建置規則
?
1
2
hello.so: Hello.o
        $(CXX) Hello.o -o hello.so $(LDFLAGS)
Hello.o 的建置規則, 以及其相依 Hello.cpp
?
1
2
Hello.o: Hello.cpp
        $(CXX) -c Hello.cpp -o Hello.o $(CXXFLAGS)
寫 Makefile 時寫個 clean 的 rule 是個好習慣 :)
?
1
2
clean:
        rm-f *.o hello.so

參考
[1] Writing an LLVM Pass
[2] 程式設計師的自我修養-連結、載入、程式庫

Update Note
  1. (11/16) 在較新版的 llvm-config 無提供 -fno-rtti 選項,必須自行在 CXXFLAGS 那邊自行添加
  2. (11/22) 上面提到那個項目目前不確定是 bug 還是怎樣,cmake 出來的 llvm-config 不會有 -fno-rtti,但 configure 建置出來的 llvm-config 則會有






  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值