diff --git a/src/backend.rs b/src/backend.rs index a985fe785a..46cfcc9b14 100644 --- a/src/backend.rs +++ b/src/backend.rs @@ -10,6 +10,7 @@ use std::{ any::{Any, TypeId}, collections::HashMap, convert::TryFrom, + fmt::Display, iter::{self, FromIterator}, mem, ops::RangeInclusive, @@ -518,6 +519,7 @@ pub struct FunctionEnd { pub struct CodeGenSession<'module, M> { assembler: Assembler, pub module_context: &'module M, + pub op_offset_map: Vec<(AssemblyOffset, Box)>, labels: Labels, func_starts: Vec<(Option, DynamicLabel)>, } @@ -531,6 +533,7 @@ impl<'module, M> CodeGenSession<'module, M> { CodeGenSession { assembler, + op_offset_map: Default::default(), labels: Default::default(), func_starts, module_context, @@ -575,6 +578,7 @@ impl<'module, M> CodeGenSession<'module, M> { Ok(TranslatedCodeSection { exec_buf, func_starts, + op_offset_map: self.op_offset_map, // TODO relocatable_accesses: vec![], }) @@ -594,11 +598,11 @@ struct RelocateAccess { address: RelocateAddress, } -#[derive(Debug)] pub struct TranslatedCodeSection { exec_buf: ExecutableBuffer, func_starts: Vec, relocatable_accesses: Vec, + op_offset_map: Vec<(AssemblyOffset, Box)>, } impl TranslatedCodeSection { @@ -626,7 +630,7 @@ impl TranslatedCodeSection { } pub fn disassemble(&self) { - crate::disassemble::disassemble(&*self.exec_buf).unwrap(); + crate::disassemble::disassemble(&*self.exec_buf, &self.op_offset_map).unwrap(); } } @@ -651,7 +655,7 @@ type Labels = HashMap< >; pub struct Context<'this, M> { - asm: &'this mut Assembler, + pub asm: &'this mut Assembler, reloc_sink: &'this mut dyn binemit::RelocSink, module_context: &'this M, current_function: u32, @@ -2325,10 +2329,22 @@ impl<'this, M: ModuleContext> Context<'this, M> { let end_label = self.create_label(); if count > 0 { + // TODO: Handle this failing (because we might have all registers used for block + // args we can't rely on this succeeding) let selector_reg = self.into_temp_reg(GPRType::Rq, selector).unwrap(); selector = ValueLocation::Reg(selector_reg); - let tmp = self.take_reg(I64).unwrap(); + let (tmp, pop_tmp) = if let Some(reg) = self.take_reg(I64) { + (reg, false) + } else { + let out_reg = if selector_reg == RAX { RCX } else { RAX }; + + dynasm!(self.asm + ; push Rq(out_reg.rq().unwrap()) + ); + + (out_reg, true) + }; self.immediate_to_reg(tmp, (count as u32).into()); dynasm!(self.asm @@ -2339,12 +2355,21 @@ impl<'this, M: ModuleContext> Context<'this, M> { Rq(selector_reg.rq().unwrap()) * 5 ] ; add Rq(selector_reg.rq().unwrap()), Rq(tmp.rq().unwrap()) + ); + + if pop_tmp { + dynasm!(self.asm + ; pop Rq(tmp.rq().unwrap()) + ); + } + + self.block_state.regs.release(tmp); + + dynasm!(self.asm ; jmp Rq(selector_reg.rq().unwrap()) ; start_label: ); - self.block_state.regs.release(tmp); - for target in targets { let label = target .map(|target| self.target_to_label(target)) @@ -2743,14 +2768,21 @@ impl<'this, M: ModuleContext> Context<'this, M> { ; mov DWORD [rsp + out_offset], i as i32 ); } else { - let scratch = self.take_reg(I64).unwrap(); + if let Some(scratch) = self.take_reg(I64) { + dynasm!(self.asm + ; mov Rq(scratch.rq().unwrap()), QWORD i + ; mov [rsp + out_offset], Rq(scratch.rq().unwrap()) + ); - dynasm!(self.asm - ; mov Rq(scratch.rq().unwrap()), QWORD i - ; mov [rsp + out_offset], Rq(scratch.rq().unwrap()) - ); - - self.block_state.regs.release(scratch); + self.block_state.regs.release(scratch); + } else { + dynasm!(self.asm + ; push rax + ; mov rax, QWORD i + ; mov [rsp + out_offset], rax + ; pop rax + ); + } } } (ValueLocation::Stack(in_offset), CCLoc::Reg(out_reg)) => { @@ -2978,7 +3010,6 @@ impl<'this, M: ModuleContext> Context<'this, M> { fn into_temp_loc(&mut self, ty: impl Into>, val: ValueLocation) -> CCLoc { match val { - ValueLocation::Stack(o) => CCLoc::Stack(o), _ => { if let Some(gpr) = self.into_temp_reg(ty, val) { CCLoc::Reg(gpr) diff --git a/src/disassemble.rs b/src/disassemble.rs index 2a6eb2cd84..9c3622f49c 100644 --- a/src/disassemble.rs +++ b/src/disassemble.rs @@ -1,32 +1,51 @@ -use crate::error::Error; use capstone::prelude::*; -use std::fmt::Write; +use dynasmrt::AssemblyOffset; +use std::error::Error; +use std::fmt::{Display, Write}; -pub fn disassemble(mem: &[u8]) -> Result<(), Error> { +pub fn disassemble( + mem: &[u8], + mut ops: &[(AssemblyOffset, impl Display)], +) -> Result<(), Box> { let mut cs = Capstone::new() .x86() .mode(arch::x86::ArchMode::Mode64) .build()?; println!("{} bytes:", mem.len()); - let insns = cs.disasm_all(&mem, 0x0).unwrap(); + let insns = cs.disasm_all(&mem, 0x0)?; for i in insns.iter() { let mut line = String::new(); - write!(&mut line, "{:4x}:\t", i.address()).unwrap(); + let address = i.address(); + + loop { + if let Some((offset, op)) = ops.first() { + if offset.0 as u64 <= address { + ops = &ops[1..]; + println!("{}", op); + } else { + break; + } + } else { + break; + } + } + + write!(&mut line, "{:4x}:\t", i.address())?; let mut bytes_str = String::new(); for b in i.bytes() { - write!(&mut bytes_str, "{:02x} ", b).unwrap(); + write!(&mut bytes_str, "{:02x} ", b)?; } - write!(&mut line, "{:24}\t", bytes_str).unwrap(); + write!(&mut line, "{:24}\t", bytes_str)?; if let Some(s) = i.mnemonic() { - write!(&mut line, "{}\t", s).unwrap(); + write!(&mut line, "{}\t", s)?; } if let Some(s) = i.op_str() { - write!(&mut line, "{}", s).unwrap(); + write!(&mut line, "{}", s)?; } println!("{}", line); diff --git a/src/function_body.rs b/src/function_body.rs index 487a213ecd..06f8de87db 100644 --- a/src/function_body.rs +++ b/src/function_body.rs @@ -5,9 +5,10 @@ use crate::error::Error; use crate::microwasm::*; use crate::module::{ModuleContext, SigType, Signature}; use cranelift_codegen::binemit; +use dynasmrt::DynasmApi; use either::{Either, Left, Right}; use multi_mut::HashMapMultiMut; -use std::{collections::HashMap, hash::Hash}; +use std::{collections::HashMap, fmt, hash::Hash, mem}; #[derive(Debug)] struct Block { @@ -73,7 +74,7 @@ where ) } -pub fn translate( +pub fn translate( session: &mut CodeGenSession, reloc_sink: &mut dyn binemit::RelocSink, func_idx: u32, @@ -107,7 +108,12 @@ where let mut body = body.into_iter().peekable(); let module_context = &*session.module_context; + let mut op_offset_map = mem::replace(&mut session.op_offset_map, vec![]); let ctx = &mut session.new_context(func_idx, reloc_sink); + op_offset_map.push(( + ctx.asm.offset(), + Box::new(format!("Function {}:", func_idx)), + )); let params = func_type .params() @@ -126,8 +132,6 @@ where Block { label: BrTarget::Return, params: num_returns as u32, - // TODO: This only works for integers - // calling_convention: Some(Left(BlockCallingConvention::function_start(ret_locs( func_type.returns().iter().map(|t| t.to_microwasm_type()), )))), @@ -146,6 +150,26 @@ where block.is_next = true; } + struct DisassemblyOpFormatter