use std::io::{self, Write};
use super::{Encoder, method};
pub struct BcjX86Encoder<W: Write> {
inner: W,
buffer: Vec<u8>,
position: u32,
state: u32,
}
impl<W: Write> std::fmt::Debug for BcjX86Encoder<W> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("BcjX86Encoder")
.field("position", &self.position)
.finish_non_exhaustive()
}
}
impl<W: Write + Send> BcjX86Encoder<W> {
pub fn new(inner: W) -> Self {
Self {
inner,
buffer: Vec::new(),
position: 0,
state: 0,
}
}
pub fn new_with_start_pos(inner: W, start_pos: u32) -> Self {
Self {
inner,
buffer: Vec::new(),
position: start_pos,
state: 0,
}
}
fn process_buffer(&mut self) -> io::Result<()> {
if self.buffer.is_empty() {
return Ok(());
}
let processed = bcj_x86_convert(&mut self.buffer, self.position, &mut self.state, true);
if processed > 0 {
self.inner.write_all(&self.buffer[..processed])?;
self.buffer.drain(..processed);
self.position = self.position.wrapping_add(processed as u32);
}
Ok(())
}
pub fn try_finish(mut self) -> io::Result<W> {
if !self.buffer.is_empty() {
self.inner.write_all(&self.buffer)?;
}
Ok(self.inner)
}
}
impl<W: Write + Send> Write for BcjX86Encoder<W> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.buffer.extend_from_slice(buf);
while self.buffer.len() >= 5 {
let prev_len = self.buffer.len();
self.process_buffer()?;
if self.buffer.len() == prev_len {
break;
}
}
Ok(buf.len())
}
fn flush(&mut self) -> io::Result<()> {
self.process_buffer()?;
self.inner.flush()
}
}
impl<W: Write + Send> Encoder for BcjX86Encoder<W> {
fn method_id(&self) -> &'static [u8] {
method::BCJ_X86
}
fn finish(mut self: Box<Self>) -> io::Result<()> {
if !self.buffer.is_empty() {
self.inner.write_all(&self.buffer)?;
}
self.inner.flush()
}
}
fn bcj_x86_convert(buf: &mut [u8], ip: u32, state: &mut u32, encoding: bool) -> usize {
const LOOKAHEAD: usize = 5;
if buf.len() < LOOKAHEAD {
return 0;
}
let mut pos: usize = 0;
let mut mask = *state & 7;
loop {
let p = pos;
while pos < buf.len() - 4 {
if buf[pos] & 0xfe == 0xe8 {
break;
}
pos += 1;
}
let d = pos - p;
if pos >= buf.len() - 4 {
if d > 2 {
*state = 0;
} else {
*state = mask >> d;
}
let _ = ip.wrapping_add(pos as u32);
return pos;
}
if d > 2 {
mask = 0;
} else {
mask >>= d;
if mask != 0
&& (mask > 4 || mask == 3 || test_x86_ms_byte(buf[pos + (mask >> 1) as usize + 1]))
{
mask = (mask >> 1) | 4;
pos += 1;
continue;
}
}
if test_x86_ms_byte(buf[pos + 4]) {
let mut v =
u32::from_le_bytes([buf[pos + 1], buf[pos + 2], buf[pos + 3], buf[pos + 4]]);
let cur = ip.wrapping_add(LOOKAHEAD as u32).wrapping_add(pos as u32);
pos += LOOKAHEAD;
if encoding {
v = v.wrapping_add(cur);
} else {
v = v.wrapping_sub(cur);
}
if mask != 0 {
let sh = (mask & 6) << 2;
if test_x86_ms_byte((v >> sh) as u8) {
v ^= ((0x100u32) << sh).wrapping_sub(1);
if encoding {
v = v.wrapping_add(cur);
} else {
v = v.wrapping_sub(cur);
}
}
mask = 0;
}
let bytes = v.to_le_bytes();
buf[pos - 4] = bytes[0];
buf[pos - 3] = bytes[1];
buf[pos - 2] = bytes[2];
buf[pos - 1] = 0u8.wrapping_sub(bytes[3] & 1);
} else {
mask = (mask >> 1) | 4;
pos += 1;
}
}
}
#[inline]
fn test_x86_ms_byte(b: u8) -> bool {
b.wrapping_add(1) & 0xfe == 0
}
pub struct BcjArmEncoder<W: Write> {
inner: W,
buffer: Vec<u8>,
position: u32,
}
impl<W: Write> std::fmt::Debug for BcjArmEncoder<W> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("BcjArmEncoder")
.field("position", &self.position)
.finish_non_exhaustive()
}
}
impl<W: Write + Send> BcjArmEncoder<W> {
pub fn new(inner: W) -> Self {
Self {
inner,
buffer: Vec::new(),
position: 4, }
}
fn process_buffer(&mut self) -> io::Result<()> {
let aligned_len = self.buffer.len() & !3;
if aligned_len < 4 {
return Ok(());
}
let mut i = 0;
while i + 4 <= aligned_len {
let mut v = u32::from_le_bytes([
self.buffer[i],
self.buffer[i + 1],
self.buffer[i + 2],
self.buffer[i + 3],
]);
self.position = self.position.wrapping_add(4);
if self.buffer[i + 3] == 0xeb {
v <<= 2;
v = v.wrapping_add(self.position); v >>= 2;
v &= 0x00ffffff;
v |= 0xeb000000;
}
let bytes = v.to_le_bytes();
self.buffer[i] = bytes[0];
self.buffer[i + 1] = bytes[1];
self.buffer[i + 2] = bytes[2];
self.buffer[i + 3] = bytes[3];
i += 4;
}
self.inner.write_all(&self.buffer[..aligned_len])?;
self.buffer.drain(..aligned_len);
Ok(())
}
pub fn try_finish(mut self) -> io::Result<W> {
if !self.buffer.is_empty() {
self.inner.write_all(&self.buffer)?;
}
Ok(self.inner)
}
}
impl<W: Write + Send> Write for BcjArmEncoder<W> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.buffer.extend_from_slice(buf);
while self.buffer.len() >= 8 {
self.process_buffer()?;
}
Ok(buf.len())
}
fn flush(&mut self) -> io::Result<()> {
self.process_buffer()?;
self.inner.flush()
}
}
impl<W: Write + Send> Encoder for BcjArmEncoder<W> {
fn method_id(&self) -> &'static [u8] {
method::BCJ_ARM
}
fn finish(mut self: Box<Self>) -> io::Result<()> {
if !self.buffer.is_empty() {
self.inner.write_all(&self.buffer)?;
}
self.inner.flush()
}
}
pub struct BcjArm64Encoder<W: Write> {
inner: W,
buffer: Vec<u8>,
position: u32,
}
impl<W: Write> std::fmt::Debug for BcjArm64Encoder<W> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("BcjArm64Encoder")
.field("position", &self.position)
.finish_non_exhaustive()
}
}
impl<W: Write + Send> BcjArm64Encoder<W> {
pub fn new(inner: W) -> Self {
Self {
inner,
buffer: Vec::new(),
position: 0,
}
}
fn process_buffer(&mut self) -> io::Result<()> {
let aligned_len = self.buffer.len() & !3;
if aligned_len < 4 {
return Ok(());
}
let flag: u32 = 1 << (24 - 4);
let mask: u32 = (1 << 24) - (flag << 1);
let mut i = 0;
while i + 4 <= aligned_len {
let mut v = u32::from_le_bytes([
self.buffer[i],
self.buffer[i + 1],
self.buffer[i + 2],
self.buffer[i + 3],
]);
if (v.wrapping_sub(0x94000000)) & 0xfc000000 == 0 {
let c = self.position >> 2;
v = v.wrapping_add(c); v &= 0x03ffffff;
v |= 0x94000000;
}
else if v.wrapping_sub(0x90000000) & 0x9f000000 == 0 {
let temp = v.wrapping_add(flag);
if temp & mask == 0 {
let mut z = (v & 0xffffffe0) | (v >> 26);
let c = (self.position >> (12 - 3)) & !7u32;
z = z.wrapping_add(c); v = 0x90000000;
v |= z << 26;
v |= 0x00ffffe0 & ((z & ((flag << 1) - 1)).wrapping_sub(flag));
v |= temp & 0x1f; }
}
let bytes = v.to_le_bytes();
self.buffer[i] = bytes[0];
self.buffer[i + 1] = bytes[1];
self.buffer[i + 2] = bytes[2];
self.buffer[i + 3] = bytes[3];
self.position = self.position.wrapping_add(4);
i += 4;
}
self.inner.write_all(&self.buffer[..aligned_len])?;
self.buffer.drain(..aligned_len);
Ok(())
}
pub fn try_finish(mut self) -> io::Result<W> {
if !self.buffer.is_empty() {
self.inner.write_all(&self.buffer)?;
}
Ok(self.inner)
}
}
impl<W: Write + Send> Write for BcjArm64Encoder<W> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.buffer.extend_from_slice(buf);
while self.buffer.len() >= 8 {
self.process_buffer()?;
}
Ok(buf.len())
}
fn flush(&mut self) -> io::Result<()> {
self.process_buffer()?;
self.inner.flush()
}
}
impl<W: Write + Send> Encoder for BcjArm64Encoder<W> {
fn method_id(&self) -> &'static [u8] {
method::BCJ_ARM64
}
fn finish(mut self: Box<Self>) -> io::Result<()> {
if !self.buffer.is_empty() {
self.inner.write_all(&self.buffer)?;
}
self.inner.flush()
}
}
pub struct BcjArmThumbEncoder<W: Write> {
inner: W,
buffer: Vec<u8>,
position: u32,
}
impl<W: Write> std::fmt::Debug for BcjArmThumbEncoder<W> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("BcjArmThumbEncoder")
.field("position", &self.position)
.finish_non_exhaustive()
}
}
impl<W: Write + Send> BcjArmThumbEncoder<W> {
pub fn new(inner: W) -> Self {
Self {
inner,
buffer: Vec::new(),
position: 4,
}
}
fn process_buffer(&mut self) -> io::Result<()> {
let aligned_len = self.buffer.len() & !3;
if aligned_len < 4 {
return Ok(());
}
let mut i = 0;
while i + 4 <= aligned_len {
if (self.buffer[i + 1] & 0xf8) == 0xf0 && (self.buffer[i + 3] & 0xf8) == 0xf8 {
let b1 = u32::from(self.buffer[i]);
let b2 = u32::from(self.buffer[i + 1]);
let b3 = u32::from(self.buffer[i + 2]);
let b4 = u32::from(self.buffer[i + 3]);
let mut addr = ((b2 & 0x07) << 19) | (b1 << 11) | ((b4 & 0x07) << 8) | b3;
addr <<= 1;
let cur = self.position.wrapping_add(4);
addr = addr.wrapping_add(cur);
self.buffer[i] = ((addr >> 11) & 0xff) as u8;
self.buffer[i + 1] = (0xf0 | ((addr >> 19) & 0x07)) as u8;
self.buffer[i + 2] = ((addr >> 1) & 0xff) as u8;
self.buffer[i + 3] = (0xf8 | ((addr >> 9) & 0x07)) as u8;
}
self.position = self.position.wrapping_add(4);
i += 4;
}
self.inner.write_all(&self.buffer[..aligned_len])?;
self.buffer.drain(..aligned_len);
Ok(())
}
pub fn try_finish(mut self) -> io::Result<W> {
if !self.buffer.is_empty() {
self.inner.write_all(&self.buffer)?;
}
Ok(self.inner)
}
}
impl<W: Write + Send> Write for BcjArmThumbEncoder<W> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.buffer.extend_from_slice(buf);
while self.buffer.len() >= 8 {
self.process_buffer()?;
}
Ok(buf.len())
}
fn flush(&mut self) -> io::Result<()> {
self.process_buffer()?;
self.inner.flush()
}
}
impl<W: Write + Send> Encoder for BcjArmThumbEncoder<W> {
fn method_id(&self) -> &'static [u8] {
method::BCJ_ARM_THUMB
}
fn finish(mut self: Box<Self>) -> io::Result<()> {
if !self.buffer.is_empty() {
self.inner.write_all(&self.buffer)?;
}
self.inner.flush()
}
}
pub struct BcjPpcEncoder<W: Write> {
inner: W,
buffer: Vec<u8>,
position: u32,
}
impl<W: Write> std::fmt::Debug for BcjPpcEncoder<W> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("BcjPpcEncoder")
.field("position", &self.position)
.finish_non_exhaustive()
}
}
impl<W: Write + Send> BcjPpcEncoder<W> {
pub fn new(inner: W) -> Self {
Self {
inner,
buffer: Vec::new(),
position: 0,
}
}
fn process_buffer(&mut self) -> io::Result<()> {
let aligned_len = self.buffer.len() & !3;
if aligned_len < 4 {
return Ok(());
}
let mut i = 0;
while i + 4 <= aligned_len {
let mut v = u32::from_be_bytes([
self.buffer[i],
self.buffer[i + 1],
self.buffer[i + 2],
self.buffer[i + 3],
]);
if (self.buffer[i] & 0xfc) == 0x48 && (self.buffer[i + 3] & 3) == 1 {
v = v.wrapping_add(self.position); v &= 0x03ffffff;
v |= 0x48000000;
}
let bytes = v.to_be_bytes();
self.buffer[i] = bytes[0];
self.buffer[i + 1] = bytes[1];
self.buffer[i + 2] = bytes[2];
self.buffer[i + 3] = bytes[3];
self.position = self.position.wrapping_add(4);
i += 4;
}
self.inner.write_all(&self.buffer[..aligned_len])?;
self.buffer.drain(..aligned_len);
Ok(())
}
pub fn try_finish(mut self) -> io::Result<W> {
if !self.buffer.is_empty() {
self.inner.write_all(&self.buffer)?;
}
Ok(self.inner)
}
}
impl<W: Write + Send> Write for BcjPpcEncoder<W> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.buffer.extend_from_slice(buf);
while self.buffer.len() >= 8 {
self.process_buffer()?;
}
Ok(buf.len())
}
fn flush(&mut self) -> io::Result<()> {
self.process_buffer()?;
self.inner.flush()
}
}
impl<W: Write + Send> Encoder for BcjPpcEncoder<W> {
fn method_id(&self) -> &'static [u8] {
method::BCJ_PPC
}
fn finish(mut self: Box<Self>) -> io::Result<()> {
if !self.buffer.is_empty() {
self.inner.write_all(&self.buffer)?;
}
self.inner.flush()
}
}
pub struct BcjSparcEncoder<W: Write> {
inner: W,
buffer: Vec<u8>,
position: u32,
}
impl<W: Write> std::fmt::Debug for BcjSparcEncoder<W> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("BcjSparcEncoder")
.field("position", &self.position)
.finish_non_exhaustive()
}
}
impl<W: Write + Send> BcjSparcEncoder<W> {
pub fn new(inner: W) -> Self {
Self {
inner,
buffer: Vec::new(),
position: 0,
}
}
fn process_buffer(&mut self) -> io::Result<()> {
let aligned_len = self.buffer.len() & !3;
if aligned_len < 4 {
return Ok(());
}
let mut i = 0;
while i + 4 <= aligned_len {
let mut v = u32::from_be_bytes([
self.buffer[i],
self.buffer[i + 1],
self.buffer[i + 2],
self.buffer[i + 3],
]);
if (self.buffer[i] == 0x40 && (self.buffer[i + 1] & 0xc0) == 0)
|| (self.buffer[i] == 0x7f && self.buffer[i + 1] >= 0xc0)
{
v <<= 2;
v = v.wrapping_add(self.position); v &= 0x01ffffff;
v = v.wrapping_sub(1 << 24);
v ^= 0xff000000;
v >>= 2;
v |= 0x40000000;
}
let bytes = v.to_be_bytes();
self.buffer[i] = bytes[0];
self.buffer[i + 1] = bytes[1];
self.buffer[i + 2] = bytes[2];
self.buffer[i + 3] = bytes[3];
self.position = self.position.wrapping_add(4);
i += 4;
}
self.inner.write_all(&self.buffer[..aligned_len])?;
self.buffer.drain(..aligned_len);
Ok(())
}
pub fn try_finish(mut self) -> io::Result<W> {
if !self.buffer.is_empty() {
self.inner.write_all(&self.buffer)?;
}
Ok(self.inner)
}
}
impl<W: Write + Send> Write for BcjSparcEncoder<W> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.buffer.extend_from_slice(buf);
while self.buffer.len() >= 8 {
self.process_buffer()?;
}
Ok(buf.len())
}
fn flush(&mut self) -> io::Result<()> {
self.process_buffer()?;
self.inner.flush()
}
}
impl<W: Write + Send> Encoder for BcjSparcEncoder<W> {
fn method_id(&self) -> &'static [u8] {
method::BCJ_SPARC
}
fn finish(mut self: Box<Self>) -> io::Result<()> {
if !self.buffer.is_empty() {
self.inner.write_all(&self.buffer)?;
}
self.inner.flush()
}
}
const IA64_BRANCH_TABLE: [u8; 32] = [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 6, 6, 0, 0, 7, 7, 4, 4, 0, 0, 4, 4, 0, 0, ];
pub struct BcjIa64Encoder<W: Write> {
inner: W,
buffer: Vec<u8>,
position: u32,
}
impl<W: Write> std::fmt::Debug for BcjIa64Encoder<W> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("BcjIa64Encoder")
.field("position", &self.position)
.finish_non_exhaustive()
}
}
impl<W: Write + Send> BcjIa64Encoder<W> {
pub fn new(inner: W) -> Self {
Self {
inner,
buffer: Vec::new(),
position: 0,
}
}
fn process_buffer(&mut self) -> io::Result<()> {
let aligned_len = (self.buffer.len() / 16) * 16;
if aligned_len < 16 {
return Ok(());
}
let mut i = 0;
while i + 16 <= aligned_len {
Self::process_bundle(self.position, &mut self.buffer[i..i + 16]);
self.position = self.position.wrapping_add(16);
i += 16;
}
self.inner.write_all(&self.buffer[..aligned_len])?;
self.buffer.drain(..aligned_len);
Ok(())
}
fn process_bundle(position: u32, bundle: &mut [u8]) {
let template = bundle[0] & 0x1F;
let branch_mask = IA64_BRANCH_TABLE[template as usize];
for slot in 0..3 {
if (branch_mask & (1 << slot)) == 0 {
continue;
}
let bit_pos = 5 + slot * 41;
let byte_pos = bit_pos / 8;
let bit_offset = bit_pos % 8;
if byte_pos + 6 > 16 {
continue;
}
let mut inst: u64 = 0;
for j in 0..6 {
inst |= (bundle[byte_pos + j] as u64) << (j * 8);
}
inst >>= bit_offset;
let opcode = ((inst >> 37) & 0xF) as u8;
if opcode != 4 && opcode != 5 {
continue;
}
if (inst & (1u64 << 36)) != 0 {
continue;
}
let imm_raw = ((inst >> 13) & 0x1FFFFFF) as u32;
let sign = (imm_raw >> 24) & 1;
let addr = if sign != 0 {
(imm_raw | 0xFE000000) << 4
} else {
(imm_raw & 0x00FFFFFF) << 4
};
let new_addr = addr.wrapping_add(position);
let new_imm = (new_addr >> 4) & 0x1FFFFFF;
let mask = 0x1FFFFFFu64 << 13;
inst = (inst & !mask) | ((new_imm as u64) << 13);
let write_val = inst << bit_offset;
for j in 0..6 {
let orig_mask = if j == 0 {
(1u64 << bit_offset) - 1
} else if j == 5 {
!((1u64 << (bit_offset + 41 - 40)) - 1)
} else {
0
};
bundle[byte_pos + j] = ((bundle[byte_pos + j] as u64 & orig_mask)
| ((write_val >> (j * 8)) & 0xFF & !orig_mask))
as u8;
}
}
}
pub fn try_finish(mut self) -> io::Result<W> {
if !self.buffer.is_empty() {
self.inner.write_all(&self.buffer)?;
}
Ok(self.inner)
}
}
impl<W: Write + Send> Write for BcjIa64Encoder<W> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.buffer.extend_from_slice(buf);
while self.buffer.len() >= 32 {
self.process_buffer()?;
}
Ok(buf.len())
}
fn flush(&mut self) -> io::Result<()> {
self.process_buffer()?;
self.inner.flush()
}
}
impl<W: Write + Send> Encoder for BcjIa64Encoder<W> {
fn method_id(&self) -> &'static [u8] {
method::BCJ_IA64
}
fn finish(mut self: Box<Self>) -> io::Result<()> {
if !self.buffer.is_empty() {
self.inner.write_all(&self.buffer)?;
}
self.inner.flush()
}
}
pub struct BcjRiscvEncoder<W: Write> {
inner: W,
buffer: Vec<u8>,
position: u32,
}
impl<W: Write> std::fmt::Debug for BcjRiscvEncoder<W> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("BcjRiscvEncoder")
.field("position", &self.position)
.finish_non_exhaustive()
}
}
impl<W: Write + Send> BcjRiscvEncoder<W> {
pub fn new(inner: W) -> Self {
Self {
inner,
buffer: Vec::new(),
position: 0,
}
}
fn process_buffer(&mut self) -> io::Result<()> {
if self.buffer.len() < 8 {
return Ok(());
}
let process_len = self.buffer.len() - 6;
let mut i = 0;
while i < process_len {
let b0 = self.buffer[i];
let is_compressed = (b0 & 0x03) != 0x03;
if is_compressed {
if i + 2 <= self.buffer.len() {
let inst16 = u16::from_le_bytes([self.buffer[i], self.buffer[i + 1]]);
if let Some(new_inst) = self.process_compressed(inst16, self.position) {
let bytes = new_inst.to_le_bytes();
self.buffer[i] = bytes[0];
self.buffer[i + 1] = bytes[1];
}
self.position = self.position.wrapping_add(2);
i += 2;
} else {
break;
}
} else {
if i + 4 <= self.buffer.len() {
let inst32 = u32::from_le_bytes([
self.buffer[i],
self.buffer[i + 1],
self.buffer[i + 2],
self.buffer[i + 3],
]);
if let Some(new_inst) = self.process_standard(inst32, self.position) {
let bytes = new_inst.to_le_bytes();
self.buffer[i] = bytes[0];
self.buffer[i + 1] = bytes[1];
self.buffer[i + 2] = bytes[2];
self.buffer[i + 3] = bytes[3];
}
self.position = self.position.wrapping_add(4);
i += 4;
} else {
break;
}
}
}
if i > 0 {
self.inner.write_all(&self.buffer[..i])?;
self.buffer.drain(..i);
}
Ok(())
}
fn process_standard(&self, inst: u32, pos: u32) -> Option<u32> {
let opcode = inst & 0x7F;
match opcode {
0x6F => {
let imm20 = (inst >> 31) & 1;
let imm10_1 = (inst >> 21) & 0x3FF;
let imm11 = (inst >> 20) & 1;
let imm19_12 = (inst >> 12) & 0xFF;
let imm = (imm20 << 20) | (imm19_12 << 12) | (imm11 << 11) | (imm10_1 << 1);
let addr = if (imm & 0x100000) != 0 {
imm | 0xFFE00000
} else {
imm
};
let new_addr = addr.wrapping_add(pos);
let rd = (inst >> 7) & 0x1F;
let new_imm20 = (new_addr >> 20) & 1;
let new_imm10_1 = (new_addr >> 1) & 0x3FF;
let new_imm11 = (new_addr >> 11) & 1;
let new_imm19_12 = (new_addr >> 12) & 0xFF;
let new_inst = (new_imm20 << 31)
| (new_imm10_1 << 21)
| (new_imm11 << 20)
| (new_imm19_12 << 12)
| (rd << 7)
| opcode;
Some(new_inst)
}
0x17 => {
let imm = inst & 0xFFFFF000;
let new_imm = imm.wrapping_add(pos & 0xFFFFF000);
let rd = (inst >> 7) & 0x1F;
let new_inst = (new_imm & 0xFFFFF000) | (rd << 7) | opcode;
Some(new_inst)
}
_ => None,
}
}
fn process_compressed(&self, inst: u16, pos: u32) -> Option<u16> {
let op = inst & 0x03;
let funct3 = (inst >> 13) & 0x07;
if op == 0x01 && (funct3 == 0x05 || funct3 == 0x01) {
let bit12 = (inst >> 12) & 1;
let bit11 = (inst >> 11) & 1;
let bit10 = (inst >> 10) & 1;
let bit9 = (inst >> 9) & 1;
let bit8 = (inst >> 8) & 1;
let bit7 = (inst >> 7) & 1;
let bit6 = (inst >> 6) & 1;
let bit5 = (inst >> 5) & 1;
let bit4 = (inst >> 4) & 1;
let bit3 = (inst >> 3) & 1;
let bit2 = (inst >> 2) & 1;
let imm = ((bit12 as u32) << 11)
| ((bit11 as u32) << 4)
| ((bit10 as u32) << 9)
| ((bit9 as u32) << 8)
| ((bit8 as u32) << 10)
| ((bit7 as u32) << 6)
| ((bit6 as u32) << 7)
| ((bit5 as u32) << 3)
| ((bit4 as u32) << 2)
| ((bit3 as u32) << 1)
| ((bit2 as u32) << 5);
let addr = if (imm & 0x800) != 0 {
imm | 0xFFFFF000
} else {
imm
};
let new_addr = addr.wrapping_add(pos);
let new_bit12 = ((new_addr >> 11) & 1) as u16;
let new_bit11 = ((new_addr >> 4) & 1) as u16;
let new_bit10 = ((new_addr >> 9) & 1) as u16;
let new_bit9 = ((new_addr >> 8) & 1) as u16;
let new_bit8 = ((new_addr >> 10) & 1) as u16;
let new_bit7 = ((new_addr >> 6) & 1) as u16;
let new_bit6 = ((new_addr >> 7) & 1) as u16;
let new_bit5 = ((new_addr >> 3) & 1) as u16;
let new_bit4 = ((new_addr >> 2) & 1) as u16;
let new_bit3 = ((new_addr >> 1) & 1) as u16;
let new_bit2 = ((new_addr >> 5) & 1) as u16;
let new_inst = (funct3 << 13)
| (new_bit12 << 12)
| (new_bit11 << 11)
| (new_bit10 << 10)
| (new_bit9 << 9)
| (new_bit8 << 8)
| (new_bit7 << 7)
| (new_bit6 << 6)
| (new_bit5 << 5)
| (new_bit4 << 4)
| (new_bit3 << 3)
| (new_bit2 << 2)
| op;
return Some(new_inst);
}
None
}
pub fn try_finish(mut self) -> io::Result<W> {
if !self.buffer.is_empty() {
self.inner.write_all(&self.buffer)?;
}
Ok(self.inner)
}
}
impl<W: Write + Send> Write for BcjRiscvEncoder<W> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.buffer.extend_from_slice(buf);
while self.buffer.len() >= 14 {
self.process_buffer()?;
}
Ok(buf.len())
}
fn flush(&mut self) -> io::Result<()> {
self.process_buffer()?;
self.inner.flush()
}
}
impl<W: Write + Send> Encoder for BcjRiscvEncoder<W> {
fn method_id(&self) -> &'static [u8] {
method::BCJ_RISCV
}
fn finish(mut self: Box<Self>) -> io::Result<()> {
if !self.buffer.is_empty() {
self.inner.write_all(&self.buffer)?;
}
self.inner.flush()
}
}
pub struct DeltaEncoder<W: Write> {
inner: W,
delta: u8,
history: Vec<u8>,
}
impl<W: Write> std::fmt::Debug for DeltaEncoder<W> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("DeltaEncoder")
.field("delta", &self.delta)
.finish_non_exhaustive()
}
}
impl<W: Write + Send> DeltaEncoder<W> {
pub fn new(inner: W, delta: u8) -> Self {
let delta_val = if delta == 0 { 1 } else { delta };
Self {
inner,
delta: delta_val,
history: vec![0u8; delta_val as usize],
}
}
pub fn from_properties(inner: W, properties: &[u8]) -> Self {
let delta = if properties.is_empty() {
1
} else {
properties[0].wrapping_add(1)
};
Self::new(inner, delta)
}
pub fn try_finish(self) -> io::Result<W> {
Ok(self.inner)
}
}
impl<W: Write + Send> Write for DeltaEncoder<W> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
let delta = self.delta as usize;
let mut output = Vec::with_capacity(buf.len());
for (i, &byte) in buf.iter().enumerate() {
let hist_idx = i % delta;
let encoded = byte.wrapping_sub(self.history[hist_idx]);
self.history[hist_idx] = byte;
output.push(encoded);
}
self.inner.write_all(&output)?;
Ok(buf.len())
}
fn flush(&mut self) -> io::Result<()> {
self.inner.flush()
}
}
impl<W: Write + Send> Encoder for DeltaEncoder<W> {
fn method_id(&self) -> &'static [u8] {
method::DELTA
}
fn finish(mut self: Box<Self>) -> io::Result<()> {
self.inner.flush()?;
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_bcj_x86_roundtrip() {
let original: Vec<u8> = vec![
0x90, 0x90, 0xe8, 0x01, 0x00, 0x00, 0x00, 0x90, 0x90, 0x90, 0xe8, 0x10, 0x00, 0x00,
0x00, 0x90,
];
let mut encoded = Vec::new();
{
let mut encoder = BcjX86Encoder::new(&mut encoded);
encoder.write_all(&original).unwrap();
encoder.flush().unwrap();
}
assert!(!encoded.is_empty());
}
#[test]
fn test_bcj_arm_roundtrip() {
let original: Vec<u8> = vec![0x00, 0x00, 0x00, 0xeb, 0x01, 0x00, 0x00, 0xeb];
let mut encoded = Vec::new();
{
let mut encoder = BcjArmEncoder::new(&mut encoded);
encoder.write_all(&original).unwrap();
encoder.flush().unwrap();
}
assert_eq!(encoded.len(), original.len());
}
#[test]
fn test_bcj_ppc_basic() {
let original: Vec<u8> = vec![0x48, 0x00, 0x00, 0x01, 0x48, 0x00, 0x00, 0x05];
let mut encoded = Vec::new();
{
let mut encoder = BcjPpcEncoder::new(&mut encoded);
encoder.write_all(&original).unwrap();
encoder.flush().unwrap();
}
assert_eq!(encoded.len(), original.len());
}
#[test]
fn test_delta_roundtrip() {
let original: Vec<u8> = vec![10, 20, 30, 40, 50, 60, 70, 80];
let mut encoded = Vec::new();
{
let mut encoder = DeltaEncoder::new(&mut encoded, 1);
encoder.write_all(&original).unwrap();
encoder.flush().unwrap();
}
assert_eq!(encoded.len(), original.len());
assert_eq!(encoded[0], 10); assert_eq!(encoded[1], 10); }
#[test]
fn test_bcj_ia64_basic() {
let original: Vec<u8> = vec![0u8; 32];
let mut encoded = Vec::new();
{
let mut encoder = BcjIa64Encoder::new(&mut encoded);
encoder.write_all(&original).unwrap();
let _ = encoder.try_finish().unwrap();
}
assert_eq!(encoded.len(), original.len());
}
#[test]
fn test_bcj_ia64_preserves_non_branch() {
let mut original = vec![0u8; 32];
original[0] = 0x00; original[16] = 0x00;
let mut encoded = Vec::new();
{
let mut encoder = BcjIa64Encoder::new(&mut encoded);
encoder.write_all(&original).unwrap();
let _ = encoder.try_finish().unwrap();
}
assert_eq!(encoded, original);
}
#[test]
fn test_bcj_riscv_basic() {
let original: Vec<u8> = vec![0u8; 32];
let mut encoded = Vec::new();
{
let mut encoder = BcjRiscvEncoder::new(&mut encoded);
encoder.write_all(&original).unwrap();
let _ = encoder.try_finish().unwrap();
}
assert_eq!(encoded.len(), original.len());
}
#[test]
fn test_bcj_riscv_jal_encoding() {
let original: Vec<u8> = vec![
0xEF, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, ];
let mut encoded = Vec::new();
{
let mut encoder = BcjRiscvEncoder::new(&mut encoded);
encoder.write_all(&original).unwrap();
let _ = encoder.try_finish().unwrap();
}
assert_eq!(encoded.len(), original.len());
let encoded_jal = u32::from_le_bytes([encoded[0], encoded[1], encoded[2], encoded[3]]);
assert_eq!(encoded_jal & 0x7F, 0x6F); }
#[test]
fn test_bcj_riscv_auipc_encoding() {
let original: Vec<u8> = vec![
0x97, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, ];
let mut encoded = Vec::new();
{
let mut encoder = BcjRiscvEncoder::new(&mut encoded);
encoder.write_all(&original).unwrap();
let _ = encoder.try_finish().unwrap();
}
assert_eq!(encoded.len(), original.len());
let encoded_auipc = u32::from_le_bytes([encoded[0], encoded[1], encoded[2], encoded[3]]);
assert_eq!(encoded_auipc & 0x7F, 0x17); }
#[test]
fn test_bcj_riscv_compressed_passthrough() {
let original: Vec<u8> = vec![
0x05, 0x01, 0x13, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, ];
let mut encoded = Vec::new();
{
let mut encoder = BcjRiscvEncoder::new(&mut encoded);
encoder.write_all(&original).unwrap();
let _ = encoder.try_finish().unwrap();
}
assert_eq!(encoded.len(), original.len());
assert_eq!(encoded[0], original[0]);
assert_eq!(encoded[1], original[1]);
}
}