使用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库实现:
- 初始化JIT模块与Context,开启反汇编
- 配置目标架构的汇编语法(比如Intel)
- 编译函数后,从
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
相关产品推荐
相关产品推荐

