aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoriximeow <me@iximeow.net>2021-08-21 19:58:19 -0700
committeriximeow <me@iximeow.net>2021-08-21 19:58:19 -0700
commit1c06541a85fadbc5b9fc0a3bfee10cec3c8e5667 (patch)
tree68adb5ba8768a461ee725f7b42fd1b6211df6822
parenta5a67ee666381b2716862dec6df2e85419c352bc (diff)
improve relative branch offset formatting for DisplayStyle::C
-rw-r--r--CHANGELOG1
-rw-r--r--src/long_mode/display.rs107
-rw-r--r--src/protected_mode/display.rs107
-rw-r--r--src/real_mode/display.rs107
4 files changed, 313 insertions, 9 deletions
diff --git a/CHANGELOG b/CHANGELOG
index 0febd15..c5fcfd0 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -16,6 +16,7 @@
this circumstance.
* correct `rex.b` incorrectly applying to the `*ax` register - `4f91` is `xchg rax, r9`, not `xchg r8, r9`.
* correct `nop` incorrectly ignoring `rex.b` - `4190` is `xchg rax, r8`, not `nop`.
+* `DisplayStyle::C` now has rules to nicely display `jCC`, `jmp`, `call`, `loop*`, and `j*cxz` instructions.
## 1.0.4
diff --git a/src/long_mode/display.rs b/src/long_mode/display.rs
index 7bbd83f..181217c 100644
--- a/src/long_mode/display.rs
+++ b/src/long_mode/display.rs
@@ -3463,7 +3463,7 @@ fn contextualize_intel<T: fmt::Write, Y: YaxColors>(instr: &Instruction, colors:
Ok(())
}
-fn contextualize_c<T: fmt::Write, Y: YaxColors>(instr: &Instruction, _colors: &Y, _address: u64, _context: Option<&NoContext>, out: &mut T) -> fmt::Result {
+fn contextualize_c<T: fmt::Write, Y: YaxColors>(instr: &Instruction, colors: &Y, _address: u64, _context: Option<&NoContext>, out: &mut T) -> fmt::Result {
let mut brace_count = 0;
let mut prefixed = false;
@@ -3509,6 +3509,26 @@ fn contextualize_c<T: fmt::Write, Y: YaxColors>(instr: &Instruction, _colors: &Y
}
}
+ fn write_jmp_operand<T: fmt::Write, Y: YaxColors>(op: Operand, colors: &Y, out: &mut T) -> fmt::Result {
+ match op {
+ 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!() }
+ }
+ }
+
match instr.opcode {
Opcode::Invalid => { out.write_str("invalid")?; },
Opcode::MOVS => {
@@ -3662,9 +3682,90 @@ fn contextualize_c<T: fmt::Write, Y: YaxColors>(instr: &Instruction, _colors: &Y
write!(out, "{}--", instr.operand(0))?;
}
}
+ Opcode::JMP => {
+ out.write_str("jmp ")?;
+ write_jmp_operand(instr.operand(0), colors, out)?;
+ },
+ Opcode::JRCXZ => {
+ out.write_str("if rcx == 0 then jmp ")?;
+ write_jmp_operand(instr.operand(0), colors, out)?;
+ },
+ Opcode::LOOP => {
+ out.write_str("rcx--; if rcx != 0 then jmp ")?;
+ write_jmp_operand(instr.operand(0), colors, out)?;
+ },
+ Opcode::LOOPZ => {
+ out.write_str("rcx--; if rcx != 0 and zero(rflags) then jmp ")?;
+ write_jmp_operand(instr.operand(0), colors, out)?;
+ },
+ Opcode::LOOPNZ => {
+ out.write_str("rcx--; if rcx != 0 and !zero(rflags) then jmp ")?;
+ write_jmp_operand(instr.operand(0), colors, out)?;
+ },
+ Opcode::JO => {
+ out.write_str("if _(rflags) then jmp ")?;
+ write_jmp_operand(instr.operand(0), colors, out)?;
+ },
+ Opcode::JNO => {
+ out.write_str("if _(rflags) then jmp ")?;
+ write_jmp_operand(instr.operand(0), colors, out)?;
+ },
+ Opcode::JB => {
+ out.write_str("if /* unsigned */ below(rflags) then jmp ")?;
+ write_jmp_operand(instr.operand(0), colors, out)?;
+ },
+ Opcode::JNB => {
+ out.write_str("if /* unsigned */ above_or_equal(rflags) then jmp ")?;
+ write_jmp_operand(instr.operand(0), colors, out)?;
+ },
+ Opcode::JZ => {
+ out.write_str("if zero(rflags) then jmp ")?;
+ write_jmp_operand(instr.operand(0), colors, out)?;
+ },
+ Opcode::JNZ => {
+ out.write_str("if !zero(rflags) then jmp ")?;
+ write_jmp_operand(instr.operand(0), colors, out)?;
+ },
+ Opcode::JNA => {
+ out.write_str("if /* unsigned */ below_or_equal(rflags) then jmp ")?;
+ write_jmp_operand(instr.operand(0), colors, out)?;
+ },
+ Opcode::JA => {
+ out.write_str("if /* unsigned */ above(rflags) then jmp ")?;
+ write_jmp_operand(instr.operand(0), colors, out)?;
+ },
+ Opcode::JS => {
+ out.write_str("if signed(rflags) then jmp ")?;
+ write_jmp_operand(instr.operand(0), colors, out)?;
+ },
+ Opcode::JNS => {
+ out.write_str("if !signed(rflags) then jmp ")?;
+ write_jmp_operand(instr.operand(0), colors, out)?;
+ },
+ Opcode::JP => {
+ out.write_str("if parity(rflags) then jmp ")?;
+ write_jmp_operand(instr.operand(0), colors, out)?;
+ },
+ Opcode::JNP => {
+ out.write_str("if !parity(rflags) then jmp ")?;
+ write_jmp_operand(instr.operand(0), colors, out)?;
+ },
+ Opcode::JL => {
+ out.write_str("if /* signed */ less(rflags) then jmp ")?;
+ write_jmp_operand(instr.operand(0), colors, out)?;
+ },
+ Opcode::JGE => {
+ out.write_str("if /* signed */ greater_or_equal(rflags) then jmp ")?;
+ write_jmp_operand(instr.operand(0), colors, out)?;
+ },
+ Opcode::JLE => {
+ out.write_str("if /* signed */ less_or_equal(rflags) then jmp ")?;
+ write_jmp_operand(instr.operand(0), colors, out)?;
+ },
Opcode::JG => {
- write!(out, "if greater(rflags) then jmp {}", instr.operand(0))?;
- }
+ out.write_str("if /* signed */ greater(rflags) then jmp ")?;
+ write_jmp_operand(instr.operand(0), colors, out)?;
+ },
Opcode::NOP => {
write!(out, "nop")?;
}
diff --git a/src/protected_mode/display.rs b/src/protected_mode/display.rs
index 33c0cda..dac3684 100644
--- a/src/protected_mode/display.rs
+++ b/src/protected_mode/display.rs
@@ -3476,7 +3476,7 @@ fn contextualize_intel<T: fmt::Write, Y: YaxColors>(instr: &Instruction, colors:
Ok(())
}
-fn contextualize_c<T: fmt::Write, Y: YaxColors>(instr: &Instruction, _colors: &Y, _address: u32, _context: Option<&NoContext>, out: &mut T) -> fmt::Result {
+fn contextualize_c<T: fmt::Write, Y: YaxColors>(instr: &Instruction, colors: &Y, _address: u32, _context: Option<&NoContext>, out: &mut T) -> fmt::Result {
let mut brace_count = 0;
let mut prefixed = false;
@@ -3522,6 +3522,26 @@ fn contextualize_c<T: fmt::Write, Y: YaxColors>(instr: &Instruction, _colors: &Y
}
}
+ fn write_jmp_operand<T: fmt::Write, Y: YaxColors>(op: Operand, colors: &Y, out: &mut T) -> fmt::Result {
+ match op {
+ 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!() }
+ }
+ }
+
match instr.opcode {
Opcode::Invalid => { out.write_str("invalid")?; },
Opcode::MOVS => {
@@ -3675,9 +3695,90 @@ fn contextualize_c<T: fmt::Write, Y: YaxColors>(instr: &Instruction, _colors: &Y
write!(out, "{}--", instr.operand(0))?;
}
}
+ Opcode::JMP => {
+ out.write_str("jmp ")?;
+ write_jmp_operand(instr.operand(0), colors, out)?;
+ },
+ Opcode::JECXZ => {
+ out.write_str("if ecx == 0 then jmp ")?;
+ write_jmp_operand(instr.operand(0), colors, out)?;
+ },
+ Opcode::LOOP => {
+ out.write_str("ecx--; if ecx != 0 then jmp ")?;
+ write_jmp_operand(instr.operand(0), colors, out)?;
+ },
+ Opcode::LOOPZ => {
+ out.write_str("ecx--; if ecx != 0 and zero(rflags) then jmp ")?;
+ write_jmp_operand(instr.operand(0), colors, out)?;
+ },
+ Opcode::LOOPNZ => {
+ out.write_str("ecx--; if ecx != 0 and !zero(rflags) then jmp ")?;
+ write_jmp_operand(instr.operand(0), colors, out)?;
+ },
+ Opcode::JO => {
+ out.write_str("if _(rflags) then jmp ")?;
+ write_jmp_operand(instr.operand(0), colors, out)?;
+ },
+ Opcode::JNO => {
+ out.write_str("if _(rflags) then jmp ")?;
+ write_jmp_operand(instr.operand(0), colors, out)?;
+ },
+ Opcode::JB => {
+ out.write_str("if /* unsigned */ below(rflags) then jmp ")?;
+ write_jmp_operand(instr.operand(0), colors, out)?;
+ },
+ Opcode::JNB => {
+ out.write_str("if /* unsigned */ above_or_equal(rflags) then jmp ")?;
+ write_jmp_operand(instr.operand(0), colors, out)?;
+ },
+ Opcode::JZ => {
+ out.write_str("if zero(rflags) then jmp ")?;
+ write_jmp_operand(instr.operand(0), colors, out)?;
+ },
+ Opcode::JNZ => {
+ out.write_str("if !zero(rflags) then jmp ")?;
+ write_jmp_operand(instr.operand(0), colors, out)?;
+ },
+ Opcode::JNA => {
+ out.write_str("if /* unsigned */ below_or_equal(rflags) then jmp ")?;
+ write_jmp_operand(instr.operand(0), colors, out)?;
+ },
+ Opcode::JA => {
+ out.write_str("if /* unsigned */ above(rflags) then jmp ")?;
+ write_jmp_operand(instr.operand(0), colors, out)?;
+ },
+ Opcode::JS => {
+ out.write_str("if signed(rflags) then jmp ")?;
+ write_jmp_operand(instr.operand(0), colors, out)?;
+ },
+ Opcode::JNS => {
+ out.write_str("if !signed(rflags) then jmp ")?;
+ write_jmp_operand(instr.operand(0), colors, out)?;
+ },
+ Opcode::JP => {
+ out.write_str("if parity(rflags) then jmp ")?;
+ write_jmp_operand(instr.operand(0), colors, out)?;
+ },
+ Opcode::JNP => {
+ out.write_str("if !parity(rflags) then jmp ")?;
+ write_jmp_operand(instr.operand(0), colors, out)?;
+ },
+ Opcode::JL => {
+ out.write_str("if /* signed */ less(rflags) then jmp ")?;
+ write_jmp_operand(instr.operand(0), colors, out)?;
+ },
+ Opcode::JGE => {
+ out.write_str("if /* signed */ greater_or_equal(rflags) then jmp ")?;
+ write_jmp_operand(instr.operand(0), colors, out)?;
+ },
+ Opcode::JLE => {
+ out.write_str("if /* signed */ less_or_equal(rflags) then jmp ")?;
+ write_jmp_operand(instr.operand(0), colors, out)?;
+ },
Opcode::JG => {
- write!(out, "if greater(eflags) then jmp {}", instr.operand(0))?;
- }
+ out.write_str("if /* signed */ greater(rflags) then jmp ")?;
+ write_jmp_operand(instr.operand(0), colors, out)?;
+ },
Opcode::NOP => {
write!(out, "nop")?;
}
diff --git a/src/real_mode/display.rs b/src/real_mode/display.rs
index 3a9fddc..1065255 100644
--- a/src/real_mode/display.rs
+++ b/src/real_mode/display.rs
@@ -3476,7 +3476,7 @@ fn contextualize_intel<T: fmt::Write, Y: YaxColors>(instr: &Instruction, colors:
Ok(())
}
-fn contextualize_c<T: fmt::Write, Y: YaxColors>(instr: &Instruction, _colors: &Y, _address: u32, _context: Option<&NoContext>, out: &mut T) -> fmt::Result {
+fn contextualize_c<T: fmt::Write, Y: YaxColors>(instr: &Instruction, colors: &Y, _address: u32, _context: Option<&NoContext>, out: &mut T) -> fmt::Result {
let mut brace_count = 0;
let mut prefixed = false;
@@ -3522,6 +3522,26 @@ fn contextualize_c<T: fmt::Write, Y: YaxColors>(instr: &Instruction, _colors: &Y
}
}
+ fn write_jmp_operand<T: fmt::Write, Y: YaxColors>(op: Operand, colors: &Y, out: &mut T) -> fmt::Result {
+ match op {
+ 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!() }
+ }
+ }
+
match instr.opcode {
Opcode::Invalid => { out.write_str("invalid")?; },
Opcode::MOVS => {
@@ -3675,9 +3695,90 @@ fn contextualize_c<T: fmt::Write, Y: YaxColors>(instr: &Instruction, _colors: &Y
write!(out, "{}--", instr.operand(0))?;
}
}
+ Opcode::JMP => {
+ out.write_str("jmp ")?;
+ write_jmp_operand(instr.operand(0), colors, out)?;
+ },
+ Opcode::JCXZ => {
+ out.write_str("if cx == 0 then jmp ")?;
+ write_jmp_operand(instr.operand(0), colors, out)?;
+ },
+ Opcode::LOOP => {
+ out.write_str("cx--; if cx != 0 then jmp ")?;
+ write_jmp_operand(instr.operand(0), colors, out)?;
+ },
+ Opcode::LOOPZ => {
+ out.write_str("cx--; if cx != 0 and zero(rflags) then jmp ")?;
+ write_jmp_operand(instr.operand(0), colors, out)?;
+ },
+ Opcode::LOOPNZ => {
+ out.write_str("cx--; if cx != 0 and !zero(rflags) then jmp ")?;
+ write_jmp_operand(instr.operand(0), colors, out)?;
+ },
+ Opcode::JO => {
+ out.write_str("if _(rflags) then jmp ")?;
+ write_jmp_operand(instr.operand(0), colors, out)?;
+ },
+ Opcode::JNO => {
+ out.write_str("if _(rflags) then jmp ")?;
+ write_jmp_operand(instr.operand(0), colors, out)?;
+ },
+ Opcode::JB => {
+ out.write_str("if /* unsigned */ below(rflags) then jmp ")?;
+ write_jmp_operand(instr.operand(0), colors, out)?;
+ },
+ Opcode::JNB => {
+ out.write_str("if /* unsigned */ above_or_equal(rflags) then jmp ")?;
+ write_jmp_operand(instr.operand(0), colors, out)?;
+ },
+ Opcode::JZ => {
+ out.write_str("if zero(rflags) then jmp ")?;
+ write_jmp_operand(instr.operand(0), colors, out)?;
+ },
+ Opcode::JNZ => {
+ out.write_str("if !zero(rflags) then jmp ")?;
+ write_jmp_operand(instr.operand(0), colors, out)?;
+ },
+ Opcode::JNA => {
+ out.write_str("if /* unsigned */ below_or_equal(rflags) then jmp ")?;
+ write_jmp_operand(instr.operand(0), colors, out)?;
+ },
+ Opcode::JA => {
+ out.write_str("if /* unsigned */ above(rflags) then jmp ")?;
+ write_jmp_operand(instr.operand(0), colors, out)?;
+ },
+ Opcode::JS => {
+ out.write_str("if signed(rflags) then jmp ")?;
+ write_jmp_operand(instr.operand(0), colors, out)?;
+ },
+ Opcode::JNS => {
+ out.write_str("if !signed(rflags) then jmp ")?;
+ write_jmp_operand(instr.operand(0), colors, out)?;
+ },
+ Opcode::JP => {
+ out.write_str("if parity(rflags) then jmp ")?;
+ write_jmp_operand(instr.operand(0), colors, out)?;
+ },
+ Opcode::JNP => {
+ out.write_str("if !parity(rflags) then jmp ")?;
+ write_jmp_operand(instr.operand(0), colors, out)?;
+ },
+ Opcode::JL => {
+ out.write_str("if /* signed */ less(rflags) then jmp ")?;
+ write_jmp_operand(instr.operand(0), colors, out)?;
+ },
+ Opcode::JGE => {
+ out.write_str("if /* signed */ greater_or_equal(rflags) then jmp ")?;
+ write_jmp_operand(instr.operand(0), colors, out)?;
+ },
+ Opcode::JLE => {
+ out.write_str("if /* signed */ less_or_equal(rflags) then jmp ")?;
+ write_jmp_operand(instr.operand(0), colors, out)?;
+ },
Opcode::JG => {
- write!(out, "if greater(eflags) then jmp {}", instr.operand(0))?;
- }
+ out.write_str("if /* signed */ greater(rflags) then jmp ")?;
+ write_jmp_operand(instr.operand(0), colors, out)?;
+ },
Opcode::NOP => {
write!(out, "nop")?;
}