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

使用Cranelift生成汇编文本:如何提取反汇编内容?

关于Cranelift生成汇编文本及适配JIT/AOT的解决方案

Cranelift完全支持生成Intel或AT&T风格的汇编文本,不需要借助Capstone/Iced这类第三方反汇编库。你提到的Context::set_disasm(bool)确实是开启该功能的关键,下面直接说明如何提取汇编文本,并分别适配JIT和AOT场景:

核心原理

开启set_disasm(true)后,Cranelift的汇编器会在生成机器码的同时,将每条指令对应的汇编文本记录到CodeBuffer的Instruction实例中,你只需遍历该结构即可提取内容。同时可以通过目标ISA的配置指定汇编语法(Intel/AT&T)。

JIT场景实现步骤

以Rust为例,结合cranelift-jit库实现:

  1. 初始化JIT模块与Context,开启反汇编
  2. 配置目标架构的汇编语法(比如Intel)
  3. 编译函数后,从CodeBuffer中遍历提取汇编文本
use cranelift::prelude::*;
use cranelift_jit::{JITBuilder, JITModule};
use cranelift_module::Module;
use cranelift_codegen::isa::x64::DisasmFormat;

fn main() {
    // 初始化JIT模块
    let mut jit_builder = JITBuilder::new(cranelift_module::default_libcall_names());
    let mut module = JITModule::new(jit_builder);
    let mut context = module.make_context();

    // 开启反汇编记录
    context.set_disasm(true);

    // 配置x64架构使用Intel语法(默认是AT&T)
    let mut target_config = module.target_config().clone();
    if let Some(x64_cfg) = target_config.as_mut_x64() {
        x64_cfg.disasm_format = DisasmFormat::Intel;
    }
    module.set_target_config(target_config);

    // 构建函数IR示例(简单加法函数)
    let mut sig = module.make_signature();
    sig.params.push(AbiParam::new(Int::I32));
    sig.params.push(AbiParam::new(Int::I32));
    sig.returns.push(AbiParam::new(Int::I32));
    context.func.signature = sig;

    let mut bb = context.func.create_block();
    let a = context.func.append_param(bb, Int::I32);
    let b = context.func.append_param(bb, Int::I32);
    context.func.ins().jump(bb, &[]);

    let bb1 = context.func.create_block();
    context.func.append_block_params_for_function_params(bb1);
    let add = context.func.ins().iadd(a, b);
    context.func.ins().return_(&[add]);

    // 编译并最终化函数
    module.define_function("add", &mut context).unwrap();
    module.finalize_definitions().unwrap();

    // 提取汇编文本
    let func = module.get_function("add").unwrap();
    let code_buffer = func.code_buffer();
    println!("JIT生成的汇编代码:");
    for instr in code_buffer.instructions() {
        if let Some(disasm) = &instr.disasm {
            println!("{}", disasm);
        }
    }
}

AOT场景实现步骤

AOT场景有两种方式:一种是直接生成汇编文本文件,另一种是生成机器码后再提取反汇编内容,这里给出两种方式的示例:

方式1:直接生成汇编文本(适合AOT发布)

use cranelift::prelude::*;
use cranelift_codegen::isa::{TargetIsa, x64::X64Isa};
use cranelift_codegen::settings::{builder, Flags};
use cranelift_codegen::isa::x64::DisasmFormat;

fn main() {
    // 创建x64架构ISA,配置Intel语法
    let flag_builder = builder();
    let flags = Flags::new(flag_builder);
    let mut isa = X64Isa::new(flags, cranelift_codegen::isa::x64::X64Architecture::X86_64)
        .unwrap();
    isa.set_disasm_format(DisasmFormat::Intel);

    // 构建函数Context与IR
    let mut context = Context::new();
    context.set_disasm(true);

    let mut sig = Signature::new(CallingConvention::SystemV);
    sig.params.push(AbiParam::new(Int::I32));
    sig.params.push(AbiParam::new(Int::I32));
    sig.returns.push(AbiParam::new(Int::I32));
    context.func.signature = sig;

    let mut bb = context.func.create_block();
    let a = context.func.append_param(bb, Int::I32);
    let b = context.func.append_param(bb, Int::I32);
    context.func.ins().jump(bb, &[]);

    let bb1 = context.func.create_block();
    context.func.append_block_params_for_function_params(bb1);
    let add = context.func.ins().iadd(a, b);
    context.func.ins().return_(&[add]);

    // 编译函数并生成汇编文本
    let mut codegen_ctx = cranelift_codegen::Context::for_function(context.func);
    codegen_ctx.compile(&*isa).unwrap();
    let func = codegen_ctx.func;

    let mut asm_output = String::new();
    isa.emit_to_assembler(&func, &mut asm_output).unwrap();
    println!("AOT生成的汇编代码:");
    println!("{}", asm_output);

    // 可选:将汇编文本写入文件
    // std::fs::write("add.s", asm_output).unwrap();
}

方式2:生成机器码后提取反汇编

和JIT场景类似,编译得到CodeBuffer后直接遍历提取,适合需要同时生成机器码和汇编文本的场景。

注意事项

  • 不同架构的汇编语法配置方式不同,比如AArch64架构需要修改对应ISA的反汇编格式配置。
  • Context::set_disasm(true)必须在编译前调用,否则CodeBuffer不会记录汇编文本。
  • JIT场景中,函数加载到内存后,CodeBuffer中的指令地址可以对应到内存中的实际机器码地址,方便调试关联。

内容的提问来源于stack exchange,提问作者nickkoro

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 05:55:15