use crate::{
jump::{Jump, JumpTable},
Error, Result,
};
impl JumpTable {
pub fn target(&self, jump: &Jump) -> Result<u16> {
match jump {
Jump::Label(label) => Ok(*label),
Jump::Func(func) => Ok(*self.func.get(func).ok_or(Error::FuncNotFound(*func))?),
Jump::ExtFunc(ext) => Ok(self.code.offset_of(ext).ok_or(Error::ExtFuncNotFound)?),
}
}
pub fn shift_targets(&mut self) -> Result<()> {
let mut total_offset = 0;
let mut target_sizes = Vec::new();
let jumps = self.jump.clone();
for (original_pc, jump) in jumps.iter() {
let pc = original_pc + total_offset;
let raw_target = self.target(jump)?;
let target = if raw_target > *original_pc {
raw_target + total_offset
} else {
raw_target
};
let instr_size = if target > 0xff {
3 } else {
2 };
target_sizes.push((pc, instr_size));
total_offset += instr_size;
}
total_offset = 0;
for (pc, size) in target_sizes {
tracing::debug!("shift target at pc=0x{pc:x} with size={size}");
self.shift_target(pc, size)?;
total_offset += size;
}
Ok(())
}
pub fn shift_target(&mut self, ptr: u16, offset: u16) -> Result<()> {
self.code.shift(offset);
self.shift_label_target(ptr, offset)?;
self.shift_func_target(ptr, offset)
}
pub fn shift_func_target(&mut self, ptr: u16, offset: u16) -> Result<()> {
self.func.iter_mut().try_for_each(|(index, target)| {
if *target > ptr {
let next_target = *target + offset;
tracing::trace!(
"shift Func({index}) target with offset={offset}: 0x{target:x}(0x{ptr:x}) -> 0x{:x}",
next_target
);
*target = next_target;
}
Ok(())
})
}
pub fn shift_label_target(&mut self, ptr: u16, offset: u16) -> Result<()> {
for (_, jump) in self.jump.iter_mut() {
let Jump::Label(target) = jump else {
continue;
};
if *target > ptr {
let next_target = *target + offset;
tracing::trace!(
"shift Label target with offset={offset}: 0x{target:x}(0x{ptr:x}) -> 0x{:x}",
next_target,
);
*target = next_target;
}
}
Ok(())
}
}