From fe2917be66f1ac0c138ab6f5628f6b73e7626952 Mon Sep 17 00:00:00 2001 From: iximeow Date: Sun, 16 Jun 2024 12:08:41 -0700 Subject: adapting contextualize_intel to use new operand visitor stuff the reasoning for *why* `visit_operand` is better here lives as doc comments on `visit_operand` itself: it avoids going from scattered operand details to `enum Operand` only to deconstruct the enum again. instead, branch arms can get codegen'd directly against `struct Instruction` layout. --- src/long_mode/display.rs | 250 ++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 213 insertions(+), 37 deletions(-) (limited to 'src/long_mode') diff --git a/src/long_mode/display.rs b/src/long_mode/display.rs index 71bb1dd..3cfab94 100644 --- a/src/long_mode/display.rs +++ b/src/long_mode/display.rs @@ -3595,6 +3595,20 @@ impl <'instr, T: fmt::Write, Y: YaxColors> Colorize for InstructionDisplay /// No per-operand context when contextualizing an instruction! struct NoContext; +// TODO: find a better place to put this.... +fn c_to_hex(c: u8) -> u8 { + /* + static CHARSET: &'static [u8; 16] = b"0123456789abcdef"; + CHARSET[c as usize] + */ + // the conditional branch below is faster than a lookup, yes + if c < 10 { + b'0' + c + } else { + b'a' + c - 10 + } +} + impl Instruction { pub fn write_to(&self, out: &mut T) -> fmt::Result { self.display_with(DisplayStyle::Intel).contextualize(&NoColors, 0, Some(&NoContext), out) @@ -3615,9 +3629,9 @@ fn contextualize_intel(instr: &Instruction, colors: if instr.prefixes.rep_any() { if instr.opcode.can_rep() { if instr.prefixes.rep() { - write!(out, "rep ")?; + out.write_str("rep ")?; } else if instr.prefixes.repnz() { - write!(out, "repnz ")?; + out.write_str("repnz ")?; } } } @@ -3635,41 +3649,12 @@ fn contextualize_intel(instr: &Instruction, colors: if instr.operand_count > 0 { out.write_str(" ")?; - const RELATIVE_BRANCHES: [Opcode; 21] = [ - Opcode::JMP, Opcode::JRCXZ, - Opcode::LOOP, Opcode::LOOPZ, Opcode::LOOPNZ, - Opcode::JO, Opcode::JNO, - Opcode::JB, Opcode::JNB, - Opcode::JZ, Opcode::JNZ, - Opcode::JNA, Opcode::JA, - Opcode::JS, Opcode::JNS, - Opcode::JP, Opcode::JNP, - Opcode::JL, Opcode::JGE, - Opcode::JLE, Opcode::JG, - ]; - - if instr.operands[0] == OperandSpec::ImmI8 || instr.operands[0] == OperandSpec::ImmI32 { - if RELATIVE_BRANCHES.contains(&instr.opcode) { - let x = Operand::from_spec(instr, instr.operands[0]); - - return match x { - Operand::ImmediateI8(rel) => { - if rel >= 0 { - write!(out, "$+{}", colors.number(signed_i32_hex(rel as i32))) - } else { - write!(out, "${}", colors.number(signed_i32_hex(rel as i32))) - } - } - Operand::ImmediateI32(rel) => { - if rel >= 0 { - write!(out, "$+{}", colors.number(signed_i32_hex(rel))) - } else { - write!(out, "${}", colors.number(signed_i32_hex(rel))) - } - } - _ => { unreachable!() } - }; - } + if instr.visit_operand(0, &mut RelativeBranchPrinter { + inst: instr, + colors, + out, + })? { + return Ok(()); } let mut displayer = ColorizingOperandVisitor { @@ -4167,3 +4152,194 @@ impl ShowContextual { + inst: &'a Instruction, + colors: &'a Y, + out: &'a mut F, +} + +impl<'a, Y: YaxColors, F: fmt::Write> crate::long_mode::OperandVisitor for RelativeBranchPrinter<'a, Y, F> { + // return true if we printed a relative branch offset, false otherwise + type Ok = bool; + // but errors are errors + type Error = fmt::Error; + + fn visit_reg(&mut self, _reg: RegSpec) -> Result { + Ok(false) + } + fn visit_deref(&mut self, _reg: RegSpec) -> Result { + Ok(false) + } + fn visit_disp(&mut self, _reg: RegSpec, _disp: i32) -> Result { + Ok(false) + } + #[cfg_attr(feature="profiling", inline(never))] + fn visit_i8(&mut self, rel: i8) -> Result { + if RELATIVE_BRANCHES.contains(&self.inst.opcode) { + self.out.write_char('$')?; + // danger_anguished_string_write(self.out, "$"); + let mut v = rel as u8; + if rel < 0 { + self.out.write_char('-')?; + //danger_anguished_string_write(&mut self.out, "-"); + v = -rel as u8; + } else { + self.out.write_char('+')?; + // danger_anguished_string_write(&mut self.out, "+"); + } + self.out.write_str("0x")?; + // danger_anguished_string_write(self.out, "0x"); + let mut buf = [core::mem::MaybeUninit::::uninit(); 2]; + let mut curr = buf.len(); + loop { + let digit = v % 16; + let c = c_to_hex(digit as u8); + curr -= 1; + buf[curr].write(c); + v = v / 16; + if v == 0 { + break; + } + } + let buf = &buf[curr..]; + let s = unsafe { + core::mem::transmute::<&[core::mem::MaybeUninit], &str>(buf) + }; + + self.out.write_str(s)?; +// anguished_string_write(&mut self.out, s); + Ok(true) + } else { + Ok(false) + } + } + #[cfg_attr(feature="profiling", inline(never))] + fn visit_i32(&mut self, rel: i32) -> Result { + if RELATIVE_BRANCHES.contains(&self.inst.opcode) || self.inst.opcode == Opcode::XBEGIN { + self.out.write_char('$')?; + // danger_anguished_string_write(self.out, "$"); + let mut v = rel as u32; + if rel < 0 { + self.out.write_char('-')?; + // danger_anguished_string_write(&mut self.out, "-"); + v = -rel as u32; + } else { + self.out.write_char('+')?; + // danger_anguished_string_write(&mut self.out, "+"); + } + self.out.write_str("0x")?; + // danger_anguished_string_write(self.out, "0x"); + let mut buf = [core::mem::MaybeUninit::::uninit(); 8]; + let mut curr = buf.len(); + loop { + let digit = v % 16; + let c = c_to_hex(digit as u8); + curr -= 1; + buf[curr].write(c); + v = v / 16; + if v == 0 { + break; + } + } + let buf = &buf[curr..]; + let s = unsafe { + core::mem::transmute::<&[core::mem::MaybeUninit], &str>(buf) + }; + +// danger_anguished_string_write(&mut self.out, s); + + // danger_anguished_variable_length_bstring_write(unsafe { self.out.as_mut_vec() }, s.as_bytes()); + self.out.write_str(s)?; + Ok(true) + } else { + Ok(false) + } + } + fn visit_u8(&mut self, _imm: u8) -> Result { + Ok(false) + } + fn visit_i16(&mut self, _imm: i16) -> Result { + Ok(false) + } + fn visit_u16(&mut self, _imm: u16) -> Result { + Ok(false) + } + fn visit_u32(&mut self, _imm: u32) -> Result { + Ok(false) + } + fn visit_i64(&mut self, _imm: i64) -> Result { + Ok(false) + } + fn visit_u64(&mut self, _imm: u64) -> Result { + Ok(false) + } + fn visit_abs_u32(&mut self, _imm: u32) -> Result { + Ok(false) + } + fn visit_abs_u64(&mut self, _imm: u64) -> Result { + Ok(false) + } + fn visit_reg_scale(&mut self, _reg: RegSpec, _scale: u8) -> Result { + Ok(false) + } + fn visit_index_base_scale(&mut self, _base: RegSpec, _index: RegSpec, _scale: u8) -> Result { + Ok(false) + } + fn visit_reg_scale_disp(&mut self, _reg: RegSpec, _scale: u8, _disp: i32) -> Result { + Ok(false) + } + fn visit_index_base_scale_disp(&mut self, _base: RegSpec, _index: RegSpec, _scale: u8, _disp: i32) -> Result { + Ok(false) + } + fn visit_other(&mut self) -> Result { + Ok(false) + } + fn visit_reg_mask_merge(&mut self, _spec: RegSpec, _mask: RegSpec, _merge_mode: MergeMode) -> Result { + Ok(false) + } + fn visit_reg_mask_merge_sae(&mut self, _spec: RegSpec, _mask: RegSpec, _merge_mode: MergeMode, _sae_mode: crate::long_mode::SaeMode) -> Result { + Ok(false) + } + fn visit_reg_mask_merge_sae_noround(&mut self, _spec: RegSpec, _mask: RegSpec, _merge_mode: MergeMode) -> Result { + Ok(false) + } + fn visit_reg_disp_masked(&mut self, _spec: RegSpec, _disp: i32, _mask_reg: RegSpec) -> Result { + Ok(false) + } + fn visit_reg_deref_masked(&mut self, _spec: RegSpec, _mask_reg: RegSpec) -> Result { + Ok(false) + } + fn visit_reg_scale_masked(&mut self, _spec: RegSpec, _scale: u8, _mask_reg: RegSpec) -> Result { + Ok(false) + } + fn visit_reg_scale_disp_masked(&mut self, _spec: RegSpec, _scale: u8, _disp: i32, _mask_reg: RegSpec) -> Result { + Ok(false) + } + fn visit_index_base_masked(&mut self, _base: RegSpec, _index: RegSpec, _mask_reg: RegSpec) -> Result { + Ok(false) + } + fn visit_index_base_disp_masked(&mut self, _base: RegSpec, _index: RegSpec, _disp: i32, _mask_reg: RegSpec) -> Result { + Ok(false) + } + fn visit_index_base_scale_masked(&mut self, _base: RegSpec, _index: RegSpec, _scale: u8, _mask_reg: RegSpec) -> Result { + Ok(false) + } + fn visit_index_base_scale_disp_masked(&mut self, _base: RegSpec, _index: RegSpec, _scale: u8, _disp: i32, _mask_reg: RegSpec) -> Result { + Ok(false) + } +} + -- cgit v1.1