- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我特别需要在我的 C++ 代码运行期间逐行解析 LLVM IR 代码,我需要知道每行的哪些操作数发生了什么操作。
例如,如果 IR 代码是:
%0 = load i32* %a, align 4
我想知道在我的 C++ 代码运行期间,来自 %a
的值正在加载到 %0
。我考虑过使用简单的文本解析 C++ 程序来执行此操作(解析 IR 并搜索 IR 关键字),但想知道是否有任何现有库(可能来自 LLVM 本身)可以帮助我避免这样做。
最佳答案
理论上,我们可以直接利用 LLVM::LLLexer
为逐行解析的 LLVM IR 编写我们自己的解析器。
以下答案假设您只对 LLVM IR 文件的每个函数内部的操作感兴趣,因为 LLVM IR 文件中的其他信息不包含任何关于操作的信息。操作只能位于函数中。 IR的其他部分,如结构体定义、函数声明等,只有类型信息,不包含操作信息。
基于上述假设,您关于逐行解析 LLVM IR 以获取 IR 文件中的操作信息的问题可以转化为解析 LLVM IR 文件中每个函数中的每个操作。
LLVM 确实有一个现有的实现,可以直接逐行解析 LLVM IR 文件以直接获取有关操作的信息,并且由于 IR 文件的函数顺序是它们在 LLVM IR 文件中出现的顺序,因此操作顺序以下实现的输出只是给定 LLVM IR 文件中的操作序列。
因此我们可以利用 parseBitcodeFile
llvm提供的接口(interface)。这样的接口(interface)将首先使用一个LLVM::LLLexer
。将 LLVM IR 文件拆分为 token ,然后将 token 提供给 Parser
进行分析,最后生成一个ErrorOr<llvm::Module *>
模块信息,函数列表在模块中的顺序与llvm ir文件中的顺序相同。
然后我们可以每个LLVM::BasicBlock
每个 LLVM::Function
在LLVM::Module
.然后迭代每个 LLVM::Instruction
, 并获取有关每个操作数的信息 LLVM::Value
.下面是实现代码。
#include <iostream>
#include <string>
#include <llvm/Support/MemoryBuffer.h>
#include <llvm/Support/ErrorOr.h>
#include <llvm/IR/Module.h>
#include <llvm/IR/LLVMContext.h>
#include <llvm/Bitcode/ReaderWriter.h>
#include <llvm/Support/raw_ostream.h>
using namespace llvm;
int main(int argc, char *argv[]) {
if (argc != 2) {
std::cerr << "Usage: " << argv[0] << "bitcode_filename" << std::endl;
return 1;
}
StringRef filename = argv[1];
LLVMContext context;
ErrorOr<std::unique_ptr<MemoryBuffer>> fileOrErr =
MemoryBuffer::getFileOrSTDIN(filename);
if (std::error_code ec = fileOrErr.getError()) {
std::cerr << " Error opening input file: " + ec.message() << std::endl;
return 2;
}
ErrorOr<llvm::Module *> moduleOrErr =
parseBitcodeFile(fileOrErr.get()->getMemBufferRef(), context);
if (std::error_code ec = fileOrErr.getError()) {
std::cerr << "Error reading Moduule: " + ec.message() << std::endl;
return 3;
}
Module *m = moduleOrErr.get();
std::cout << "Successfully read Module:" << std::endl;
std::cout << " Name: " << m->getName().str() << std::endl;
std::cout << " Target triple: " << m->getTargetTriple() << std::endl;
for (auto iter1 = m->getFunctionList().begin();
iter1 != m->getFunctionList().end(); iter1++) {
Function &f = *iter1;
std::cout << " Function: " << f.getName().str() << std::endl;
for (auto iter2 = f.getBasicBlockList().begin();
iter2 != f.getBasicBlockList().end(); iter2++) {
BasicBlock &bb = *iter2;
std::cout << " BasicBlock: " << bb.getName().str() << std::endl;
for (auto iter3 = bb.begin(); iter3 != bb.end(); iter3++) {
Instruction &inst = *iter3;
std::cout << " Instruction " << &inst << " : " << inst.getOpcodeName();
unsigned int i = 0;
unsigned int opnt_cnt = inst.getNumOperands();
for(; i < opnt_cnt; ++i)
{
Value *opnd = inst.getOperand(i);
std::string o;
// raw_string_ostream os(o);
// opnd->print(os);
//opnd->printAsOperand(os, true, m);
if (opnd->hasName()) {
o = opnd->getName();
std::cout << " " << o << "," ;
} else {
std::cout << " ptr" << opnd << ",";
}
}
std:: cout << std::endl;
}
}
}
return 0;
}
请使用以下命令生成可执行文件:
clang++ ReadBitCode.cpp -o reader `llvm-config --cxxflags --libs --ldflags --system-libs`
以如下c代码为例:
struct a {
int f_a;
int f_b;
char f_c:5;
char f_d:4;
};
int my_func( int arg1, struct a obj_a) {
int x = arg1;
return x+1 + obj_a.f_c;
}
int main() {
int a = 11;
int b = 22;
int c = 33;
int d = 44;
struct a obj_a;
obj_a.f_a = 1;
obj_a.f_b = 2;
obj_a.f_c = 3;
obj_a.f_c = 4;
if ( a > 10 ) {
b = c;
} else {
b = my_func(d, obj_a);
}
return b;
}
执行以下命令后,我们可以得到一些输出:
clang -emit-llvm -o foo.bc -c foo.c
./reader foo.bc
输出应该如下所示:
Name: foo.bc
Target triple: x86_64-unknown-linux-gnu
Function: my_func
BasicBlock: entry
Instruction 0x18deb68 : alloca ptr0x18db940,
Instruction 0x18debe8 : alloca ptr0x18db940,
Instruction 0x18dec68 : alloca ptr0x18db940,
Instruction 0x18dece8 : alloca ptr0x18db940,
Instruction 0x18de968 : getelementptr coerce, ptr0x18de880, ptr0x18de880,
Instruction 0x18de9f0 : store obj_a.coerce0, ptr0x18de968,
Instruction 0x18df0a8 : getelementptr coerce, ptr0x18de880, ptr0x18db940,
Instruction 0x18df130 : store obj_a.coerce1, ptr0x18df0a8,
Instruction 0x18df1a8 : bitcast obj_a,
Instruction 0x18df218 : bitcast coerce,
Instruction 0x18df300 : call ptr0x18df1a8, ptr0x18df218, ptr0x18de8d0, ptr0x18de1a0, ptr0x18de1f0, llvm.memcpy.p0i8.p0i8.i64,
Instruction 0x18df3a0 : store arg1, arg1.addr,
Instruction 0x18df418 : load arg1.addr,
Instruction 0x18df4a0 : store ptr0x18df418, x,
Instruction 0x18df518 : load x,
Instruction 0x18df5a0 : add ptr0x18df518, ptr0x18db940,
Instruction 0x18df648 : getelementptr obj_a, ptr0x18de880, ptr0x18deab0,
Instruction 0x18df6b8 : load f_c,
Instruction 0x18df740 : shl bf.load, ptr0x18deb00,
Instruction 0x18df7d0 : ashr bf.shl, ptr0x18deb00,
Instruction 0x18df848 : sext bf.ashr,
Instruction 0x18df8d0 : add add, conv,
Instruction 0x18df948 : ret add1,
Function: llvm.memcpy.p0i8.p0i8.i64
Function: main
BasicBlock: entry
Instruction 0x18e0078 : alloca ptr0x18db940,
Instruction 0x18e00f8 : alloca ptr0x18db940,
Instruction 0x18e0178 : alloca ptr0x18db940,
Instruction 0x18e01f8 : alloca ptr0x18db940,
Instruction 0x18e0278 : alloca ptr0x18db940,
Instruction 0x18e02f8 : alloca ptr0x18db940,
Instruction 0x18e0378 : alloca ptr0x18db940,
Instruction 0x18e0410 : store ptr0x18de880, retval,
Instruction 0x18e04a0 : store ptr0x18dfe30, a,
Instruction 0x18e0530 : store ptr0x18dfe80, b,
Instruction 0x18e05c0 : store ptr0x18dfed0, c,
Instruction 0x18e0650 : store ptr0x18dff20, d,
Instruction 0x18e06f8 : getelementptr obj_a, ptr0x18de880, ptr0x18de880,
Instruction 0x18e0780 : store ptr0x18db940, f_a,
Instruction 0x18e0828 : getelementptr obj_a, ptr0x18de880, ptr0x18db940,
Instruction 0x18e08b0 : store ptr0x18deab0, f_b,
Instruction 0x18e0958 : getelementptr obj_a, ptr0x18de880, ptr0x18deab0,
Instruction 0x18e09c8 : load f_c,
Instruction 0x18e0a50 : and bf.load, ptr0x18dff70,
Instruction 0x18e0ae0 : or bf.clear, ptr0x18deb00,
Instruction 0x18e0b70 : store bf.set, f_c,
Instruction 0x18e0c18 : getelementptr obj_a, ptr0x18de880, ptr0x18deab0,
Instruction 0x18e0c88 : load f_c1,
Instruction 0x18e0d10 : and bf.load2, ptr0x18dff70,
Instruction 0x18e0da0 : or bf.clear3, ptr0x18dffc0,
Instruction 0x18ded80 : store bf.set4, f_c1,
Instruction 0x18dedf8 : load a,
Instruction 0x18dee80 : icmp ptr0x18dedf8, ptr0x18e0010,
Instruction 0x18def28 : br cmp, if.else, if.then,
BasicBlock: if.then
Instruction 0x18def98 : load c,
Instruction 0x18e1440 : store ptr0x18def98, b,
Instruction 0x18df008 : br if.end,
BasicBlock: if.else
Instruction 0x18e14b8 : load d,
Instruction 0x18e1528 : bitcast obj_a.coerce,
Instruction 0x18e1598 : bitcast obj_a,
Instruction 0x18e1680 : call ptr0x18e1528, ptr0x18e1598, ptr0x18de8d0, ptr0x18de880, ptr0x18de1f0, llvm.memcpy.p0i8.p0i8.i64,
Instruction 0x18e1738 : getelementptr obj_a.coerce, ptr0x18de880, ptr0x18de880,
Instruction 0x18e17a8 : load ptr0x18e1738,
Instruction 0x18e1848 : getelementptr obj_a.coerce, ptr0x18de880, ptr0x18db940,
Instruction 0x18e18b8 : load ptr0x18e1848,
Instruction 0x18e1970 : call ptr0x18e14b8, ptr0x18e17a8, ptr0x18e18b8, my_func,
Instruction 0x18e1a10 : store call, b,
Instruction 0x18e1a88 : br if.end,
BasicBlock: if.end
Instruction 0x18e1af8 : load b,
Instruction 0x18e1b68 : ret ptr0x18e1af8,
为了更好地了解上面的输出,请注意这一点。
在内部,对于每条LLVM指令,LLVM会直接使用其指令的地址来表示返回值。当返回值用于另一条指令时,它将直接使用该指令的地址。
对于 clang
生成的人类可读 IR , 返回值,如%0
, %add
, %conv
由LLVM IR编写生成,仅供阅读。
Instruction
类没有 LLVM IR 文件行号信息LLVM IR 只有原始 C 源代码的行号信息。这意味着我们无法了解 LLVM IR 代码中每个操作的行号。
因此,虽然我们可以逐行解析操作,但我们无法知道操作位于哪一行。
以上源码借自How to write a custom intermodular pass in LLVM? ,也针对这个问题进行了修改。
关于c++ - 如何逐行解析LLVM IR,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30195204/
我已经设置了自定义 SSIS IR,但是从 IR 节点上的当前工作目录或临时文件夹读取文件时遇到问题 https://learn.microsoft.com/en-us/sql/integration
我已经编写了一个修改中间表示 (IR) 代码的 LLVM pass。为了增加可移植性,我还希望它与 gcc 编译器一起工作。所以我想知道是否有任何工具可以将 gcc 的某些中间表示 (IR) 转换为
我已经下载了 Sony Android Add-on IR SDK ( http://developer.sonymobile.com/knowledge-base/sdks/sony-add-on-
我在手机中使用其他应用程序,使用它的 IR。但是当我尝试在任何项目中使用 IREmitter 时,它会触发该错误! mCIR = (ConsumerIrManager)getSystemService
我想找到一些 Clang/LLVM 的调试选项,其工作方式类似于 GCC -fdump-tree-all-all , -fdump-rtl-all ,和 -fdump-ipa-all-all . 基本
我使用 LLVM opt 来运行一个传递,例如,opt -load libMyPass.so my-pass foo.ll > foo1.ll。 foo.ll 是一个 IR 文件,我希望 foo1.l
我在 Raspian jessie(无像素)(所有更新和升级)上安装了当前的 lirc 包(0.9.0~pre1-1.2)并连接到(lirc 默认)GPIO 端口: 到 gpio 端口 17 - 通过
在学习 Antlr4 时,我使用 Golang 作为目标语言,所以我的玩具语言中的语句如下: $myVar = 10 $myVar + 5 将转换为一些生成结果“15”的 Golang 代码 但是,据
我正在尝试使用 SSIS 脚本任务连接到本地 REST Web 服务,并在 Azure 数据工厂的 SSIS-IR 上运行它,该 SSIS-IR 具有自托管 IR 的代理,最终连接到本地服务器。可行吗
我正在尝试关注 this链接以便为 c 代码生成 IR 表示。我使用的c代码如下 void main() { int c1 = 17; int c2 = 25; int c3 = c1 + c2
在为 lto 链接后,有没有办法获得 llvm IR?例如,我有以下行: $ clang -flto -O2 a.c main.c -fuse-ld=gold -v -save-temps 所以我想获
我正在通过这个学习 LLVM IR LangRef . 如本引用所述: LLVM programs are composed of Modules, each of which is a transl
如果这个问题听起来很愚蠢,我很抱歉。 为什么inverse document frequency使用日志?日志在 tf/idf 中有何帮助? 最佳答案 AFAIK,使用日志有助于使用几何分布对数字进行
我建立了一个LLVM定位前端,该前端会产生一些IR。随后并且完全可以预期,在某些情况下,IR输出是不正确的(例如,它看起来正确,但是执行时结果程序崩溃)。但是,我还没有找到很多有用的工具来解决这一问题
我想将C#编译为LLVM IR。因此,我认为将编译的CIL转换为LLVM IR是我可以尝试的一种方法。 我可以使用一些工具,例如vmkit和mono-llvm。 有人在使用此工具吗?或者如何将CIL转
如何创建图像以及如何使用十六进制颜色代码逐像素为其着色? 例如。我想创建一个 100x100 像素的图像,并且我想要 1x1 区域的颜色为“$002125”,2x2 区域的颜色为“$125487”..
我正在测试一个 main 函数,它只返回 void 并且在使用 lli 运行位码时出现核心转储错误(信号 65 或 73)。 : define void @main() { entry: ret
我收到一个要求,其中我有一个 c 文件,并且我正在为其生成 LLVM IR。从为每条指令生成的 LLVM IR 中,我正在计算执行需要多少个周期,现在我的问题是如何追溯到 C 代码并显示特定的 C 代
我目前正在尝试运行其他人留下的 sql 命令/脚本来建立数据库。他们有这个脚本 BEGIN; \ir file.sql \ir file.sql END; 它在第一个反斜杠处给出错误。我正在使用 Po
我特别需要在我的 C++ 代码运行期间逐行解析 LLVM IR 代码,我需要知道每行的哪些操作数发生了什么操作。 例如,如果 IR 代码是: %0 = load i32* %a, align 4 我想
我是一名优秀的程序员,十分优秀!