use crate::{
jump::{relocate, JumpTable},
wasm::ToLSBytes,
Buffer, Error, Result, BUFFER_LIMIT,
};
use opcodes::ShangHai as OpCode;
impl JumpTable {
pub fn relocate(&mut self, buffer: &mut Buffer) -> Result<()> {
self.shift_targets()?;
tracing::trace!("code section offset: 0x{:x}", self.code.offset());
while let Some((pc, jump)) = self.jump.pop_first() {
tracing::debug!(
"Relocating jump {:?} at pc=0x{:x}, current_offset=0x{:x}",
jump,
pc,
self.code.offset()
);
let target = self.target(&jump)?;
tracing::debug!(
"relocate: pc=0x{:x}, jump={:?}, target=0x{:x}",
pc,
jump,
target
);
let offset = relocate::pc(buffer, pc, target)?;
self.shift_label_pc(pc, offset as u16)?;
}
buffer.extend_from_slice(&self.code.finish());
Ok(())
}
}
fn pc(buffer: &mut Buffer, original_pc: u16, target_pc: u16) -> Result<usize> {
let original_pc = original_pc as usize;
let mut new_buffer: Buffer = buffer[..original_pc].into();
let rest_buffer: Buffer = buffer[original_pc..].into();
let target = target_pc.to_ls_bytes();
if target.len() == 1 {
new_buffer.push(OpCode::PUSH1.into());
} else {
new_buffer.push(OpCode::PUSH2.into());
}
tracing::trace!(
"push bytes: 0x{} at 0x{}",
hex::encode(&target),
hex::encode(original_pc.to_ls_bytes())
);
new_buffer.extend_from_slice(&target);
new_buffer.extend_from_slice(&rest_buffer);
if new_buffer.len() > BUFFER_LIMIT {
return Err(Error::BufferOverflow(new_buffer.len()));
}
*buffer = new_buffer;
Ok(1 + target.len())
}