You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将IR(bit code(.bc)/.ll)文件转换为图表示形式?

LLVM IR(.bc/.ll)转图表示实现方案

所有方案都基于LLVM原生工具链实现,不需要自行编写IR解析器,避免语法兼容问题。

前置准备

先安装对应版本的LLVM工具链,如果需要用Python快速开发,额外安装llvmlite库即可。两种格式的IR不需要提前手动转换,LLVM的API和工具可以直接加载.bc二进制位码和.ll文本IR。

  • 手动做格式转换可以用自带命令:
    • .bc转.ll:llvm-dis input.bc -o output.ll
    • .ll转.bc:llvm-as input.ll -o output.bc

不同场景的具体实现

1. 快速生成可视化控制流图(CFG)

控制流图以基本块为节点,块间跳转关系为边,是最常用的IR图结构,LLVM自带Pass可以直接导出,不需要写代码:

  • 执行命令导出所有函数的CFG:opt -dot-cfg input.ll -disable-output
  • 执行完成后当前目录会生成每个函数对应的.dot格式图文件,文件内包含基本块内的全部指令内容和跳转指向。
  • 如果需要导出成图片,安装graphviz后执行转换命令即可:dot -Tpng cfg.xxx.dot -o xxx_cfg.png
  • 如果需要自定义节点展示内容、边属性,可以基于LLVM的Pass框架写自定义导出逻辑,核心逻辑非常简单:遍历模块内所有函数,将每个基本块注册为图节点,再根据每个基本块末尾的终止指令(条件跳转、无条件跳转、返回等)连接后继基本块作为边。

2. 生成带语义信息的程序分析用图

如果需要做漏洞检测、程序优化相关的分析,除了控制流边,还需要调用关系、数据依赖等语义边:

  • 全局函数调用图可以直接用自带Pass导出:opt -dot-callgraph input.ll -disable-output,生成的dot文件以函数为节点,函数调用关系为边。
  • 程序依赖图(PDG)/数据流图没有官方自带的一键导出Pass,可以基于LLVM的分析接口快速实现,核心逻辑分两部分:
    • 控制依赖边:直接复用CFG的边逻辑,结合后支配树分析判断哪些边属于控制依赖(即某条分支是否执行决定了后续基本块能不能被执行)
    • 数据依赖边:遍历所有指令,基于use-def链建立关联——每个指令的操作数如果来自其他指令的输出,就在两个指令节点间加数据依赖边;如果需要考虑内存别名的情况,直接调用LLVM内置的别名分析接口即可,不需要自行实现别名逻辑。
  • 不想写C++ Pass的话,可以用llvmlite在Python端实现轻量导出,最小实现参考:
from llvmlite import binding as llvm

# 初始化LLVM环境
llvm.initialize()
llvm.initialize_native_target()
llvm.initialize_native_asmprinter()

# 加载IR文件,.bc文件用二进制模式读取后调用llvm.parse_bitcode即可
with open("input.ll", "r", encoding="utf-8") as f:
    ir_content = f.read()
module = llvm.parse_assembly(ir_content)

# 用邻接表存储指令级数据流图
instr_graph = {}
for func in module.functions:
    for basic_block in func.blocks:
        for instr in basic_block.instructions:
            node_key = f"{func.name}:{basic_block.name}:{instr}"
            instr_graph[node_key] = []
            # 遍历操作数建立use-def边
            for operand in instr.operands:
                # 过滤常量、函数参数等非指令操作数
                if hasattr(operand, "opcode") and operand.opcode is not None:
                    op_key = f"{func.name}:{operand.parent.name}:{operand}"
                    instr_graph[node_key].append(op_key)

运行后得到的邻接表就是最基础的指令级数据流图,后续可以按需往里面加控制依赖、函数调用等自定义边。

3. 生成GNN/AI4Code场景用的结构化图

如果是做图神经网络相关任务,不需要可视化输出,只要结构化的图数据,可以基于上面的遍历逻辑,按任务需求定义节点和边类型:

  • 节点可以按粒度选择:指令、基本块、函数、全局变量分别作为不同类别的节点
  • 边可以按语义分类:控制流边、数据流边、调用边、从属边(函数包含基本块、基本块包含指令)
  • 最后把邻接表导出成JSON,或者转换成对应图框架支持的输入格式即可。

注意:不要尝试手写.ll格式的解析器,LLVM IR存在大量语法边角case,不同版本的元数据、属性规则差异很大,手写解析器很容易出现兼容问题,直接用官方提供的解析接口是最稳妥的方案。

内容的提问来源于stack exchange,提问作者지아우르 레흐만 무하마드

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 22:21:30