1. 下载和编译 LLVM

LLVM 下载地址 http://releases.llvm.org/download.html
目前最新版是 6.0.0,下载完成之后,执行 tar 解压 llvm 包:

 
1
2
tar -xzvf llvm-6.0.0.src.tar.xz
 

再下载 Clang 解压:

 
1
2
tar -xzvf cfe-6.0.0.src.tar.xz
 

将 cfe-6.0.0.src 目录复制到 llvm-6.0.0.src/tools,重命名为 clang。通过 brew 安装 cmake:

 
1
2
brew install cmake
 

然后在命令行下切换到 llvm-6.0.0.src 目录,新建 build 目录,切换到 build 目录执行 cmake 生成配置文件,命令如下:

 
1
2
3
4
mkdir build
cd build
cmake -G Xcode CMAKE_BUILD_TYPE="Debug" ..
 

执行完成之后,可以看到 Xcode 的工程文件 LLVM.xcodeproj,打开工程文件,会提示是否自动创建 Schemes,如图所示:

点击 Manually Manage Schemes 手动创建,添加 ALL_BUILD,如图所示:

然后在 Xcode 上进行编译,编译过程比如慢,可能得二十分钟到半小时左右,全部编译完文件会在 11G 左右。

2. 编写 Pass 代码

我们编写第一个 Pass 的功能很简单,只是输出程序中的每个方法名,操作步骤如下:

(1) 在 lib/Transforms 目录下新建一个文件夹,文件夹名称为 FirstPass,在 FirstPass 目录下创建文件 FirstPass.cpp,代码如下:

 
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
//导入头文件
#include "llvm/ADT/Statistic.h"
#include "llvm/IR/Function.h"
#include "llvm/Pass.h"
#include "llvm/Support/raw_ostream.h"
 
using namespace llvm;  //指定所使用的 LLVM 命名空间
 
namespace {
 
  //定义 First 类继承自 FunctionPass
  struct First : public FunctionPass {
    static char ID; // Pass ID
    First() : FunctionPass(ID) {}
 
    //定义 runOnFunction 重载继承父类的抽象虚函数
    bool runOnFunction(Function &F) override {
 
      //打印每个函数的名字
      errs() << "First: ";
      errs().write_escaped(F.getName()) << '\n';
      return false;
    }
  };
}
 
char First::ID = 0;  //初始化 Pass ID
 
//最后注册 FirstPass, 指定命令行参数为 First
static RegisterPass X("First", "First Pass");
 

(2) 然后再在 lib/Transforms/TestPass 下新建 CMakeList.txt,编辑内容如下:

 
1
2
3
4
5
6
7
8
9
add_llvm_loadable_module( LLVMFirstPass
  FirstPass.cpp
 
  DEPENDS
  intrinsics_gen
  PLUGIN_TOOL
  opt
  )
 

(3) 在 lib/Transforms/CMakeLists.txt 添加 add_subdirectory(FirstPass)

(4) 重新编译整个工程,添加 LLVMFirstPass 到 Scheme,如图:

编译 LLVMFirstPass 成功之后,动态库保存在 build/Debug/lib/LLVMFirstPass.dylib。

3. 使用 opt 加载和调试 Pass

(1) 编写一段测试代码:

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
 
#include <stdio.h>
 
int test() {
 
        printf("test\n");
        return 0;
}
int main(){
 
        int num = 1;
        printf("main %d\n", num);
        test();
        return 0;
}
 

编译源文件,生成 Bitcode:

 
1
2
clang -emit-llvm -c test.c -o test.bc
 

(2) 在 Xcode 中将 opt 添加到 scheme,编辑 scheme 的启动参数,-load 参数指向 LLVMFirstPass.dylib,-First 参数就是刚才在源代码里注册的参数,如图所示:

编译 opt 并运行起来,可以看到输出了程序的每个函数名称,并且前面还打印了 First 字符串,效果如下:

 
1
2
3
4
First: test
First: main
Program ended with exit code: 0
 

opt 编译成功保存在 build/Debug/bin/opt。也可以给 pass 的代码下断点,在 Xcode 上运行 opt 就可以调试 pass,效果如图:

原文地址:https://www.exchen.net/%E5%BC%80%E5%8F%91%E5%92%8C%E8%B0%83%E8%AF%95%E7%AC%AC%E4%B8%80%E4%B8%AA-llvm-pass.html

开发和调试第一个 LLVM Pass的更多相关文章

  1. tomcat开发远程调试端口以及利用eclipse进行远程调试

    一.tomcat开发远程调试端口 方法1 WIN系统 在catalina.bat里:  SET CATALINA_OPTS=-server -Xdebug -Xnoagent -Djava.compi ...

  2. 使用VS Code 从零开始开发并调试.NET Core 应用程序

    最新文章:http://www.cnblogs.com/linezero/p/VSCodeNETCore.html 使用VS Code 从零开始开发并调试.NET Core 应用程序,C#调试. 上一 ...

  3. Asp.net Mvc模块化开发之“开启模块开发、调试的简单愉快之旅”

    整个世界林林种种,把所有的事情都划分为对立的两个面. 每个人都渴望的财富划分为富有和贫穷,身高被划分为高和矮,身材被划分为胖和瘦,等等. 我们总是感叹,有钱人的生活我不懂;有钱人又何尝能懂我们每天起早 ...

  4. Web程序员开发App系列 - 开发我的第一个App,源码下载

    Web程序员开发App系列 Web程序员开发App系列 - 认识HBuilder Web程序员开发App系列 - 申请苹果开发者账号 Web程序员开发App系列 - 调试Android和iOS手机代码 ...

  5. Nginx 模块开发(1)—— 一个稍稍能说明问题模块开发 Step By Step 过程

    1. Nginx 介绍        Nginx是俄罗斯人编写的十分轻量级的HTTP服务器,它的发音为“engine X”, 是一个高性能的HTTP和反向代理服务器,同时也是一个IMAP/POP3/S ...

  6. 搭建Go开发及调试环境(LiteIDE + GoClipse)

    搭建Go开发及调试环境(LiteIDE + GoClipse) -- Windows篇 这里以Windows7 64位为例,如果是32位环境需安装对应版本程序. 一.安装golang1.2.2 1.3 ...

  7. 开发并调试 Mail Add-in

    开发并调试 Mail Add-in (mail app for Outlook) 准备工作 如果你的邮箱搭建在 Exchange Server 上,则可以创建邮件应用程序(Mail Add-in)来扩 ...

  8. Xcode开发和调试总结

    Xcode是iOS开发主要的工具.IDE.关于Xcode的细枝末节,可以参考苹果的官方文档或者众多的说明.此文档主要涉及常用开发和调试注意事项,参考版本为Xcode 5.1.1. 目标设置: 在此,我 ...

  9. vue.js拓展篇(8):测试开发与调试

    内容 第15章:测试开发与调试 任何实际项目的开发,除了功能性代码的完成,规范的开发流程和严谨的测试都是不可或缺的.合理使用工具将事半功倍. 1.ESLint ESLint是Lint语法检查工具,避免 ...

随机推荐

  1. EF单实对应多表

    一.单实体对应多表 适用场景主表,拥有相同主键附属表或扩展表. 1. 建表词句 CREATE TABLE [Chapter2].[Product]( [SKU] [int] primary key , ...

  2. 常用APDU指令错误码

    状态码 性质 错误解释 9000 正常 成功执行 6200 警告 信息未提供 6281 警告 回送数据可能出错 6282 警告 文件长度小于Le 6283 警告 选中的文件无效 6284 警告 FCI ...

  3. 第三次Scrum

    1.小组成员 周 斌舒 溢许嘉荣唐 浩黄欣欣廖帅元刘洋江薛思汝 2.小组第三次冲刺完成情况 github仓库小组的第三次任务是完成体系结构环境图和系统原型图.在体系结构设计中,分为上级系统----把目 ...

  4. recvfrom WSAEFAULT 10014 的错误记录

    在使用 recvfrom 时一直没报错, 像这样 recvfrom(sock, Data, , (sockaddr*)&server_addr, &send_size) 当我看见百度百 ...

  5. mongo 聚合函数

    一: 聚合 常见的聚合操作跟sql server一样,有:count,distinct,group,mapReduce. <1> count count是最简单,最容易,也是最常用的聚合工 ...

  6. Ubuntu双系统安装过程中遇到的问题

    1.在第六步选择时区的时候,会报错,这时候可以选择断开网络(取消右上角的网络选项)! 2.用easybcd添加启动项以后,无法进入,F12进入BIOS,选择Ubuntu进入,因为以前的BIOS BOO ...

  7. Linux内核收包过程

    net/core/dev.c int __init net_dev_init(void) { queue->backlog.poll = process_backlog; open_softir ...

  8. json转换为tree对象(递归)

    const newTeam = function (data, parentId) { 2 let itemArr = []; 3 for (let i = 0; i < data.length ...

  9. [EffectiveC++]item36:绝不重新定义继承而来的non-virtual函数

  10. C#图解教程读书笔记(第6章 类进阶)

    类成员声明语句由下列部分组成:核心声明.一组可选的修饰符和一组可选的特性(attribute). [特性] [修饰符] 核心声明 修饰符: 如果有修饰符,必须放在核心声明之前. 如果有多个修饰符,要有 ...