jsonpiler 0.11.0

a Json syntax programming language for Windows
Documentation
use crate::prelude::*;
impl X64Assembler {
  fn enc_alias(&mut self, insts: &[X64Inst], mut offset: u32) -> ErrOR<Vec<u8>> {
    let mut vec = vec![];
    for inst in insts {
      let bytes = self.enc_inst(offset, inst)?;
      offset += len_u32(&bytes)?;
      vec.extend_from_slice(&bytes);
    }
    Ok(vec)
  }
  fn enc_branch(&self, opc: &[u8], id: LabelId, offset: u32, inst: &X64Inst) -> ErrOR<Vec<u8>> {
    let mut vec = opc.to_vec();
    let inst_size = self.sizeof_inst(inst, Some(offset))?;
    vec.extend_from_slice(&self.get_rel(self.get_rva(id)?, offset, inst_size)?.to_le_bytes());
    Ok(vec)
  }
  pub(crate) fn enc_data_lbl(
    &mut self,
    id: LabelId,
    data_inst: GlobalData,
    data: &mut Vec<u8>,
    rdata: &mut Vec<u8>,
    bss_v_size: &mut u32,
  ) -> ErrOR<()> {
    match data_inst {
      Zeros(size, align) => {
        *bss_v_size = align_up_u32(*bss_v_size, align)?;
        self.insert_lbl(id, BssX, *bss_v_size)?;
        *bss_v_size += size;
      }
      Byte(byte) => {
        self.insert_lbl(id, DataX, len_u32(data)?)?;
        data.push(byte);
      }
      Quad(qword) => {
        data.resize(align_up(data.len(), 8)?, 0);
        self.insert_lbl(id, DataX, len_u32(data)?)?;
        data.extend_from_slice(&qword.to_le_bytes());
      }
      Chars(string) => {
        self.insert_lbl(id, RData, len_u32(rdata)?)?;
        rdata.extend_from_slice(string.as_bytes());
        rdata.push(0x00);
      }
      WChars(w_chars) => {
        rdata.resize(align_up(rdata.len(), 2)?, 0);
        self.insert_lbl(id, RData, len_u32(rdata)?)?;
        for w_char in w_chars.encode_utf16() {
          rdata.extend_from_slice(&w_char.to_le_bytes());
        }
        rdata.extend_from_slice(&[0; 2]);
      }
    }
    Ok(())
  }
  pub(crate) fn enc_inst(&mut self, offset: u32, inst: &X64Inst) -> ErrOR<Vec<u8>> {
    Ok(match inst {
      Repeat(reg_size, rep, kind) => {
        let prefix = *rep as u8;
        let mut opc = *kind as u8;
        if *reg_size == S4 || *reg_size == S8 {
          opc += 1;
        }
        let mut bytes = vec![prefix];
        if *reg_size == S8 {
          bytes.push(0x48);
        }
        bytes.push(opc);
        bytes
      }
      ShiftR(dir, reg, operand) => {
        if let Shift::Ib(imm) = operand
          && *imm >= 64
        {
          return Err(InvalidInst(format!("Shift immediate out of range: {imm}")).into());
        }
        ModRM::Reg(*reg).enc_imm(1, &[operand.opcode()], dir.reg_field(), operand.imm().as_slice())
      }
      MId(reg_size, group, operand, imm) => {
        if *reg_size == S1 {
          return Err(InvalidInst(format!("OId S1 {operand:?}")).into());
        }
        self.o2rm(*operand, offset, inst)?.enc_imm(
          reg_size.rex_w(),
          &[0x81],
          group.reg_field(),
          &imm.to_le_bytes(),
        )
      }
      MovMIb(operand, ib) => self.encode_mov_ib(offset, *operand, *ib)?,
      MovMId(operand, id) => self.encode_mov_id(offset, *operand, *id)?,
      MovRI(dst, imm) => dst.encode_plus_reg(&[], 1, 0xB8, &imm.to_le_bytes()),
      MovRO(reg_size, dst, src) => match reg_size {
        S1 => self.o2rm(src.rb()?, offset, &MovRO(S1, *dst, *src))?.enc(0, &[0x8A], dst.rb()?),
        S4 | S8 => {
          let rm = self.o2rm(*src, offset, &MovRO(*reg_size, *dst, *src))?;
          rm.enc(reg_size.rex_w(), &[0x8B], *dst)
        }
      },
      MovOR(reg_size, dst, src) => match reg_size {
        S1 => self.o2rm(dst.rb()?, offset, &MovOR(S1, *dst, *src))?.enc(0, &[0x88], src.rb()?),
        S4 | S8 => {
          let rm = self.o2rm(*dst, offset, &MovOR(*reg_size, *dst, *src))?;
          rm.enc(reg_size.rex_w(), &[0x89], *src)
        }
      },
      RR(reg_size, lo, dst, src) => match reg_size {
        S1 => ModRM::Reg(dst.rb()?).enc(0, &[*lo as u8], src.rb()?),
        S4 | S8 => ModRM::Reg(*dst).enc(reg_size.rex_w(), &[*lo as u8 + 1], *src),
      },
      MR(reg_size, lo, operand, src) => match reg_size {
        S1 => {
          let rm = self.o2rm(operand.rb()?, offset, &MR(S1, *lo, *operand, *src))?;
          rm.enc(0, &[*lo as u8], src.rb()?)
        }
        S4 | S8 => {
          let rm = self.o2rm(*operand, offset, &MR(*reg_size, *lo, *operand, *src))?;
          rm.enc(reg_size.rex_w(), &[*lo as u8 + 1], *src)
        }
      },
      RM(reg_size, lo, dst, operand) => match reg_size {
        S1 => {
          let rm = self.o2rm(operand.rb()?, offset, &RM(S1, *lo, *dst, *operand))?;
          rm.enc(0, &[*lo as u8 + 2], dst.rb()?)
        }
        S4 | S8 => {
          let rm = self.o2rm(*operand, offset, &RM(*reg_size, *lo, *dst, *operand))?;
          rm.enc(reg_size.rex_w(), &[*lo as u8 + 3], *dst)
        }
      },
      TestRR(reg_size, reg) => match reg_size {
        S1 => ModRM::Reg(reg.rb()?).enc(0, &[0x84], reg.rb()?),
        S4 | S8 => ModRM::Reg(*reg).enc(reg_size.rex_w(), &[0x85], *reg),
      },
      Clear(reg) => ModRM::Reg(*reg).enc(0, &[0x31], *reg),
      CallApiCheck((dll, func)) => self
        .enc_alias(&[CallApi((*dll, *func)), TestRR(S8, Rax), JCc(E, self.handlers.os)], offset)?,
      Push(reg) => reg.encode_plus_reg(&[], 0, 0x50, &[]),
      Pop(reg) => reg.encode_plus_reg(&[], 0, 0x58, &[]),
      MovSxDRMd(reg, addr) => self.mem2rm(*addr, offset, inst)?.enc(1, &[0x63], *reg),
      LeaRM(reg, addr) => self.mem2rm(*addr, offset, inst)?.enc(1, &[0x8D], *reg),
      SetCc(reg, cc) => ModRM::Reg(*reg).enc(0, &two(0x90 + *cc as u8), Rax),
      Call(id) => self.enc_branch(&[0xE8], *id, offset, inst)?,
      Jmp(id) => self.enc_jmp(*id, offset, inst, 0xEB, &[0xE9])?,
      IDivR(reg) => ModRM::Reg(*reg).enc(1, &[0xF7], Rdi),
      IncMd(addr) => self.mem2rm(*addr, offset, inst)?.enc(0, &[0xFF], Rax),
      DecMd(addr) => self.mem2rm(*addr, offset, inst)?.enc(0, &[0xFF], Rcx),
      IncR(reg) => ModRM::Reg(*reg).enc(1, &[0xFF], Rax),
      DecR(reg) => ModRM::Reg(*reg).enc(1, &[0xFF], Rcx),
      CallApi(api) => {
        let inst_size = self.sizeof_inst(inst, Some(offset))?;
        let disp = self.get_rel(self.i_f_rva(*api)?, offset, inst_size)?;
        ModRM::RipRel(disp).enc(0, &[0xFF], Rdx)
      }
      MovSdO(xmm, src) => self.o2rm(*src, offset, inst)?.enc_ex(0xF2, 0, &two(0x10), *xmm, &[]),
      MovOSd(dst, xmm) => self.o2rm(*dst, offset, inst)?.enc_ex(0xF2, 0, &two(0x11), *xmm, &[]),
      CvtSi2Sd(xmm, reg) => ModRM::Reg(*reg).enc_ex(0xF2, 1, &two(0x2A), *xmm, &[]),
      CvtTSd2Si(reg, xmm) => ModRM::Reg(*xmm).enc_ex(0xF2, 1, &two(0x2C), *reg, &[]),
      CMovCc(cc, dst, src) => ModRM::Reg(*src).enc(1, &two(0x40 + *cc as u8), *dst),
      SqrtSd(dst, src) => ModRM::Reg(*dst).enc_ex(0xF2, 0, &two(0x51), *src, &[]),
      ArithSd(kind, xmm, xmm2) => ModRM::Reg(*xmm2).enc_ex(0xF2, 0, &two(*kind as u8), *xmm, &[]),
      UComISd(xmm, xmm2) => ModRM::Reg(*xmm2).enc_ex(0x66, 0, &two(0x2E), *xmm, &[]),
      JCc(cc, id) => self.enc_jmp(*id, offset, inst, 0x70 + *cc as u8, &two(0x80 + *cc as u8))?,
      IMulR2(dst, src) => ModRM::Reg(*src).enc(1, &two(0xAF), *dst),
      Unary(reg_size, kind, reg) => match reg_size {
        S1 => ModRM::Reg(reg.rb()?).enc(0, &[0xF6], kind.reg_field()),
        S4 | S8 => ModRM::Reg(*reg).enc(reg_size.rex_w(), &[0xF7], kind.reg_field()),
      },
      RetX => vec![0xC3],
      Cqo => vec![0x48, 0x99],
      LblX(_) => vec![],
      BitTest(bt_kind, reg, idx) => {
        if *idx >= 64 {
          return Err(InvalidInst(format!("Bit index out of range for BT: {idx}")).into());
        }
        ModRM::Reg(*reg).enc_imm(1, &[0x0F, 0xBA], bt_kind.reg_field(), &[*idx])
      }
      DF(set) => vec![0xFC + u8::from(*set)],
    })
  }
  fn enc_jmp(
    &self,
    id: LabelId,
    offset: u32,
    inst: &X64Inst,
    short: u8,
    long: &[u8],
  ) -> ErrOR<Vec<u8>> {
    if let Some((TextX, lbl_off)) = self.labels.get(&id)
      && let Ok(disp_b) = i8::try_from(i32::try_from(*lbl_off)? - 2 - i32::try_from(offset)?)
    {
      Ok(vec![short, disp_b.cast_unsigned()])
    } else {
      self.enc_branch(long, id, offset, inst)
    }
  }
  fn encode_mov_ib(&mut self, offset: u32, operand: X64Operand, ib: u8) -> ErrOR<Vec<u8>> {
    Ok(match operand {
      Reg(dst) => dst.rb()?.encode_plus_reg(&[], 0, 0xB0, &[ib]),
      Mem(_) | Ref(_) | SibDisp(..) | Args(_) => {
        self.o2rm(operand, offset, &MovMIb(operand, ib))?.enc_imm(0, &[0xC6], Rax, &[ib])
      }
    })
  }
  fn encode_mov_id(&mut self, offset: u32, operand: X64Operand, id: u32) -> ErrOR<Vec<u8>> {
    let bytes = &id.to_le_bytes();
    Ok(match operand {
      Reg(dst) => dst.encode_plus_reg(&[], 0, 0xB8, bytes),
      Mem(_) | Ref(_) | SibDisp(..) | Args(_) => {
        self.o2rm(operand, offset, &MovMId(operand, id))?.enc_imm(0, &[0xC7], Rax, bytes)
      }
    })
  }
  pub(crate) fn mem2rm(&self, addr: Address, offset: u32, inst: &X64Inst) -> ErrOR<ModRM> {
    Ok(match addr {
      Global(id) => {
        let inst_size = self.sizeof_inst(inst, Some(offset))?;
        ModRM::RipRel(self.get_rel(self.get_rva(id)?, offset, inst_size)?)
      }
      Local(_, off) => ModRM::Base(Rbp, Disp::from(off)),
    })
  }
}
fn two(opc: u8) -> [u8; 2] {
  [0x0F, opc]
}