#[derive(Debug, PartialOrd, PartialEq, Ord, Eq, Hash, Clone, Copy)]
pub enum Size {
BYTE = 1,
WORD = 2,
DWORD = 4,
FWORD = 6,
QWORD = 8,
PWORD = 10,
OWORD = 16,
HWORD = 32,
}
#[derive(Debug, PartialOrd, PartialEq, Ord, Eq, Hash, Clone, Copy)]
pub struct NumericRepr {
pub size: Size,
pub signed: bool,
}
#[derive(Debug, PartialOrd, PartialEq, Ord, Eq, Hash, Clone, Copy)]
pub struct Number {
value: u64,
repr: NumericRepr,
}
impl Size {
pub const fn in_bytes(self) -> u8 {
self as u8
}
pub fn as_literal(self) -> &'static str {
match self {
Size::BYTE => "i8",
Size::WORD => "i16",
Size::DWORD => "i32",
Size::FWORD => "i48",
Size::QWORD => "i64",
Size::PWORD => "i80",
Size::OWORD => "i128",
Size::HWORD => "i256",
}
}
}
impl NumericRepr {
pub const U8: NumericRepr = NumericRepr::unsigned(Size::BYTE);
pub const I8: NumericRepr = NumericRepr::signed(Size::BYTE);
pub const U16: NumericRepr = NumericRepr::unsigned(Size::WORD);
pub const I16: NumericRepr = NumericRepr::signed(Size::WORD);
pub const U32: NumericRepr = NumericRepr::unsigned(Size::DWORD);
pub const I32: NumericRepr = NumericRepr::signed(Size::DWORD);
pub const U64: NumericRepr = NumericRepr::unsigned(Size::QWORD);
pub const I64: NumericRepr = NumericRepr::signed(Size::QWORD);
pub const fn signed(size: Size) -> Self {
NumericRepr { size, signed: true }
}
pub const fn unsigned(size: Size) -> Self {
NumericRepr { size, signed: false }
}
}
impl Number {
pub const fn from_u64_and_size(val: u64, size: Size) -> Self {
Self::from_u64_and_repr(val, NumericRepr::unsigned(size))
}
pub const fn from_u64_and_repr(value: u64, repr: NumericRepr) -> Self {
Number { value, repr }
}
pub const fn repr(self) -> NumericRepr {
self.repr
}
pub fn byte(val: u8) -> Self {
Self::from_u64_and_size(val.into(), Size::BYTE)
}
pub fn word(val: u16) -> Self {
Self::from_u64_and_size(val.into(), Size::WORD)
}
pub fn dword(val: u32) -> Self {
Self::from_u64_and_size(val.into(), Size::DWORD)
}
pub fn qword(val: u64) -> Self {
Self::from_u64_and_size(val.into(), Size::QWORD)
}
pub fn as_u8(self) -> u8 {
self.cast_as(NumericRepr::unsigned(Size::BYTE)).value as u8
}
pub fn as_i8(self) -> i8 {
self.cast_as(NumericRepr::signed(Size::BYTE)).value as i8
}
pub fn as_u16(self) -> u16 {
self.cast_as(NumericRepr::unsigned(Size::WORD)).value as u16
}
pub fn as_i16(self) -> i16 {
self.cast_as(NumericRepr::signed(Size::WORD)).value as i16
}
pub fn as_u32(self) -> u32 {
self.cast_as(NumericRepr::unsigned(Size::DWORD)).value as u32
}
pub fn as_i32(self) -> i32 {
self.cast_as(NumericRepr::signed(Size::DWORD)).value as i32
}
pub fn as_u64(self) -> u64 {
self.cast_as(NumericRepr::unsigned(Size::QWORD)).value as u64
}
pub fn as_i64(self) -> i64 {
self.cast_as(NumericRepr::signed(Size::DWORD)).value as i64
}
pub fn cast_as(mut self, repr: NumericRepr) -> Number {
self.repr = repr;
self.correct_extension_bits_for_sign();
self
}
pub fn convert(self, repr: NumericRepr) -> Option<Number> {
let cast = self.cast_as(repr);
let max = self.repr_of_max().min(cast.repr_of_max());
let below_min = self.repr_below_min().max(cast.repr_below_min());
if cast.value <= max && cast.value > below_min {
Some(cast)
} else {
None
}
}
pub fn make_signed(mut self, signed: bool) -> Number {
self.repr.signed = signed;
self.correct_extension_bits_for_sign();
self
}
pub const fn resize(self, size: Size) -> Number {
Number {
value: self.value,
repr: NumericRepr { size, signed: self.repr.signed },
}
}
pub fn write_le_bytes(self, buf: &mut Vec<u8>) {
let bytes = (0..self.repr.size.in_bytes())
.scan(self.value, |value, _| {
let byte = *value & 0xff;
*value >>= 8;
Some(byte as u8)
});
buf.extend(bytes)
}
pub fn to_le_bytes(self) -> Vec<u8> {
let mut out = vec![];
self.write_le_bytes(&mut out);
out
}
fn mask(self) -> u64 {
use core::convert::TryInto;
#[allow(non_snake_case)]
let ALL_BITS: u8 = core::mem::size_of::<u64>().try_into().unwrap();
let len: u8 = self.byte_len() * 8;
(!0u64) >> ALL_BITS.checked_sub(len).unwrap()
}
fn byte_len(self) -> u8 {
self.repr.size.in_bytes()
}
fn repr_of_max(self) -> u64 {
self.mask() ^ (if self.repr.signed { self.sign_bit() } else { 0 })
}
fn repr_below_min(self) -> u64 {
if self.repr.signed {
((!0u64) ^ self.repr_of_max()) - 1
} else {
0
}
}
fn sign_bit(self) -> u64 {
let right_shift = (self.byte_len() * 8) - 1;
1 << right_shift
}
fn is_sign_bit_set(self) -> bool {
self.value & self.sign_bit() != 0
}
fn correct_extension_bits_for_sign(&mut self) {
if self.repr.signed && self.is_sign_bit_set() {
self.value |= !self.mask();
} else {
self.value &= self.mask();
}
}
}
#[derive(Debug, Clone)]
pub enum Const {
Relocate(Jump),
Value(Expr),
}
#[derive(Debug, Clone)]
pub struct Jump {
pub kind: JumpKind,
pub offset: Option<Expr>,
}
#[derive(Debug, Clone)]
pub enum JumpKind {
Global(Ident), Backward(Ident), Forward(Ident), Dynamic(Expr), Bare(Value) }
impl Jump {
pub fn new(kind: JumpKind, offset: Option<Expr>) -> Jump {
Jump {
kind,
offset,
}
}
pub fn encode(self, data: &[u8]) -> Stmt {
let offset = self.offset.into();
let data = data.to_vec();
match self.kind {
JumpKind::Global(ident) => Stmt::GlobalJumpTarget(ident, offset, data),
JumpKind::Backward(ident) => Stmt::BackwardJumpTarget(ident, offset, data),
JumpKind::Forward(ident) => Stmt::ForwardJumpTarget(ident, offset, data),
JumpKind::Dynamic(expr) => Stmt::DynamicJumpTarget(expr.into(), offset, data),
JumpKind::Bare(expr) => Stmt::BareJumpTarget(expr.into(), data),
}
}
}
#[derive(Debug, Clone)]
pub enum Stmt {
Const(Value),
Extend(Vec<u8>),
ExprExtend(Value),
Align(Expr, Value),
GlobalLabel(Ident),
LocalLabel(Ident),
DynamicLabel(Expr),
GlobalJumpTarget(Ident, JumpOffset, Vec<u8>),
ForwardJumpTarget(Ident, JumpOffset, Vec<u8>),
BackwardJumpTarget(Ident, JumpOffset, Vec<u8>),
DynamicJumpTarget(JumpOffset, JumpOffset, Vec<u8>),
BareJumpTarget(JumpOffset, Vec<u8>),
Stmt(Expr),
}
#[derive(Debug, Clone, Copy)]
pub enum JumpOffset {
Zero,
Injected(Value),
}
#[derive(Debug, Clone)]
pub struct Ident {
pub name: String,
}
#[derive(Debug, Clone, Copy)]
pub struct Expr {
pub idx: usize,
pub repr: NumericRepr,
}
#[derive(Debug, Clone, Copy)]
pub enum Value {
Number(Number),
Expr(Expr),
}
impl Stmt {
pub fn u8(value: u8) -> Stmt {
Stmt::Const(Value::Byte(value))
}
pub fn u16(value: u16) -> Stmt {
Stmt::Const(Value::Word(value))
}
pub fn u32(value: u32) -> Stmt {
Stmt::Const(Value::Dword(value))
}
pub fn u64(value: u64) -> Stmt {
Stmt::Const(Value::Qword(value))
}
pub fn zeroed(size: Size) -> Self {
let nr = Number::from_u64_and_size(0, size);
Stmt::Const(Value::Number(nr))
}
}
impl Ident {
pub fn to_string(self) -> String {
self.name
}
}
impl Value {
pub fn Byte(val: u8) -> Self {
Value::Number(Number::byte(val))
}
pub fn Word(val: u16) -> Self {
Value::Number(Number::word(val))
}
pub fn Dword(val: u32) -> Self {
Value::Number(Number::dword(val))
}
pub fn Qword(val: u64) -> Self {
Value::Number(Number::qword(val))
}
pub fn repr(self) -> NumericRepr {
match self {
Value::Number(nr) => nr.repr,
Value::Expr(expr) => expr.repr,
}
}
pub fn convert(self, repr: NumericRepr) -> Option<Self> {
Some(match self {
Value::Number(nr) => Value::Number(nr.convert(repr)?),
Value::Expr(expr) => Value::Expr(Expr { idx: expr.idx, repr }),
})
}
pub fn size(self) -> Size {
self.repr().size
}
}
pub fn bitmask(scale: u8) -> u32 {
1u32.checked_shl(u32::from(scale)).unwrap_or(0).wrapping_sub(1)
}
pub fn bitmask64(scale: u8) -> u64 {
1u64.checked_shl(u32::from(scale)).unwrap_or(0).wrapping_sub(1)
}
impl From<Option<Expr>> for JumpOffset {
fn from(val: Option<Expr>) -> JumpOffset {
match val {
None => JumpOffset::Zero,
Some(expr) => JumpOffset::Injected(expr.into()),
}
}
}
impl From<Expr> for JumpOffset {
fn from(expr: Expr) -> JumpOffset {
JumpOffset::Injected(expr.into())
}
}
impl From<Value> for JumpOffset {
fn from(val: Value) -> JumpOffset {
JumpOffset::Injected(val)
}
}
impl From<&'_ Expr> for JumpOffset {
fn from(expr: &'_ Expr) -> JumpOffset {
JumpOffset::Injected((*expr).into())
}
}
impl From<u8> for Value {
fn from(val: u8) -> Value {
Value::Byte(val)
}
}
impl From<Expr> for Value {
fn from(expr: Expr) -> Value {
Value::Expr(expr)
}
}
impl From<&'_ Expr> for Value {
fn from(expr: &'_ Expr) -> Value {
Value::Expr(*expr)
}
}
impl From<Value> for Stmt {
fn from(val: Value) -> Self {
Stmt::Const(val)
}
}
impl From<&'_ Value> for Stmt {
fn from(val: &'_ Value) -> Self {
Stmt::Const(*val)
}
}