如何读写LLVM bitcode
翻译转载
我已经阅读了社交媒体上的多篇帖子,现在抱怨LLVM有多可怕。
存储库太大以至于无法获得有用的信息,每天经常有数百次提交,邮件列表几乎不可能跟踪,现在可执行的可执行文件高达40Mb …
将那些花絮放在一边 - 一旦你掌握了这头巨兽,LLVM就非常容易使用了。
为了帮助人们使用LLVM,我想我会把你会用LLVM做的琐碎的操作示例放在一起 - 解析一个LLVM的中间表示文件(称为bitcode,文件扩展名.bc),然后再写回来。
首先,我们浏览一些高级LLVM术语:
- 对于用户代码来说LLVM的主要抽象对象是Module。它是一个包含所有函数,全局变量,以及你或用户编写的代码指令的类。
- Bitcode文件实际上是LLVM Module的序列化,以便可以在一个不同的程序中重组。
- LLVM实验MemoryBuffer 对象来处理来自文件、标准输入或数组的数据
以我的例子,我将使用LLVM C API - 一个比LLVM内核C++头文件更稳定的抽象。如果你希望使用多个版本的LLVM代码,那么C API非常有用,他比LLVM C++头文件更稳定。(另外,我将LLVM广泛用于我的工作,几乎每周都会有一些LLVM C++头文件被更改以破坏我们的代码。而C API从来不会。)
这里,我将假设你已经启动了LLVM,构建完并安装了它。像这样执行一下简单的步骤:
1 | git clone https://git.llvm.org/git/llvm.git <llvm dir> |
以上步骤完成后,你将会得到一个安装在/build/install下的LLVM
至此,对于一些小可执行文件我使用了CMake。CMake是目前为止结合LLVM的最简单的方法,LLVM也使用它作为自己的构建系统。
1 | project(llvm_bc_parsing_example) |
所以现在我们已经完成了CMake的设置,我们可以使用现有的LLVM安装,现在我们可以开始使用我们的实际C代码了!
因此,要使用LLVM C API,主要需要一个头文件:
1 |
我们需要两个额外的头文件来执行bitcode的读写:
1 |
现在我们开始我们主要实现的功能,假设使用2个命令行参数,第一个是输入文件,第二个是输出文件。如果一个接收到以‘-’为文件名的参数,这意味着从标准输入读取或向标准输出写:
1 | if(3 != argc){ |
所以首先我们扫描输入文件。我们将从其他输入或一个文件名得到一个LLVM内存缓冲对象:
1 | LLVMMemoryBufferRef memoryBuffer; |
执行完这些代码后,memoryBuffer就可以读取我们的bitcode文件转为LLVM module。现在我们创建module
1 | // now create our module using the memory buffer |
一旦我们得到module,我们不再需要memory buffer了,我们直接释放这部分内存。我们设法获取了一个LLVM bitcode文件,将其反序列化为一个LLVM module,之后就可以随你操作了。因此假设你已经使用LLVM module完成了所有操作了,并希望写回bitcode文件.
方法和读取方法正交,我们寻找特殊文件名‘-’做相应处理:
1 | // check if we are to write our output file to stdout |
最后我们需要对内存清理,删除module:LLVMDisposeModule(module);
我们现在就可以扫描并输出一个LLVM bitcode文件。
GitHub Example