2 releases

0.2.1 Jan 5, 2022
0.2.0 Jan 5, 2022

#1162 in Programming languages

MIT license

205KB
6K SLoC

Vicis

CI codecov

Vicis enables you to manipulate LLVM IR in pure Rust (without LLVM!).

Feel free to create issues and pull requests!

Requirements

  • llvm (== 12.0.0) is used for tests
    • You don't need it anymore!

Examples

  • Read *.ll file
cargo run --example parse FILE.ll
  • Interpret *.ll file
cargo run --example interpreter FILE.ll
  • Iterate over instructions
fn main() {
    let asm = r#"
      source_filename = "asm"
      target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"     
      target triple = "x86_64-pc-linux-gnu"  

      ; Function Attrs: noinline nounwind optnone uwtable
      define dso_local i32 @main() #0 {
        %1 = alloca i32, align 4
        store i32 42, i32* %1
        ret i32 0
      }

      attributes #0 = { noinline nounwind optnone uwtable }
    "#;

    // Parse the assembly and get a module
    let module = module::parse_assembly(asm).unwrap();

    run_on_module(&module);
}

fn run_on_module(module: &Module) {
    for (_, function) in module.functions() {
        run_on_function(function);
    }
}

fn run_on_function(func: &Function) {
    for block_id in func.layout.block_iter() {
        for inst_id in func.layout.inst_iter(block_id) {
            let inst = func.data.inst_ref(inst_id);
            // Do something with `inst` ....
        }
    }
}
  • Compile LLVM IR into machine code
// LLVM Assembly
let asm = r#"
  source_filename = "asm"
  target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"     
  target triple = "x86_64-pc-linux-gnu"  

  ; Function Attrs: noinline nounwind optnone uwtable
  define dso_local i32 @main() #0 {
    %a = alloca i32, align 4
    store i32 2, i32* %a
    %b = load i32, i32* %a
    %c = add i32 %b, 1 ; 3
    %d = add i32 %b, 2 ; 4
    %e = add i32 %c, %d ; 7
    ret i32 %e
  }

  attributes #0 = { noinline nounwind optnone uwtable }
"#;

// Parse the assembly and get a module
let module = module::parse_assembly(asm).unwrap();

// Compile the module for x86 and get a machine module
let mach_module = compile_module(X86_64, module);

// Display the machine module as assembly
assert_eq!(
  format!("{}", mach_module),
  "  .text
  .intel_syntax noprefix
  .globl main
main:
.LBL0:
  push rbp
  mov rbp, rsp
  sub rsp, 16
  mov dword ptr [rbp-4], 2
  mov eax, dword ptr [rbp-4]
  mov ecx, eax
  add ecx, 1
  add eax, 2
  add ecx, eax
  mov eax, ecx
  add rsp, 16
  pop rbp
  ret 
"
);

Dependencies

~2.5MB
~48K SLoC