diff --git a/src/asm/amd64.rs b/src/asm/amd64.rs new file mode 100644 index 0000000..545f22e --- /dev/null +++ b/src/asm/amd64.rs @@ -0,0 +1,423 @@ +#[allow(non_camel_case_types)] +pub enum Mnemonic { + /// add with carry + /// two operands + adc, + /// integer add + /// two operands + add, + /// signed multiply + /// two operands + imul, + /// two operands + mov, + /// multiply + /// two operands + mul, + /// one operand + pop, + /// one operand + push, + ret, + /// subtract + /// two operands + sub, + jmp, + /// swap registers + /// two operands + xchg, + /// interrupt + int, + /// bitwise shift left + /// two operands + shl, + /// bitwise shift right + /// two operands + shr, + /// arithmetic bitwise shift left + /// two operands + sal, + /// arithmetic bitwise shift right + /// two operands + sar, + + // pseudo instructions + /// one operand + alloca, +} + +#[allow(non_camel_case_types)] +#[cfg_attr(rustfmt, rustfmt_skip)] +#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy, PartialOrd, Ord)] +#[repr(u8)] +pub enum Register { + rax,eax,ax,al,ah, + rbx,ebx,bx,bl,bh, + rcx,ecx,cx,cl,ch, + rdx,edx,dx,dl,dh, + rsi,esi,si,sil, + rdi,edi,di,dil, + + rsp,esp,sp,spl, + rbp,ebp,bp,bpl, + + r8,r8d,r8w,r8b, + r9,r9d,r9w,r9b, + r10,r10d,r10w,r10b, + r11,r11d,r11w,r11b, + r12,r12d,r12w,r12b, + r13,r13d,r13w,r13b, + r14,r14d,r14w,r14b, + r15,r15d,r15w,r15b, + + rip,eip,ip,__ipl, + + st0,st1,st2,st3,st4,st5,st6,st7, + + mm0,mm1,mm2,mm3,mm4,mm5,mm6,mm7, + + xmm0,xmm1,xmm2,xmm3,xmm4,xmm5,xmm6,xmm7, + xmm8,xmm9,xmm10,xmm11,xmm12,xmm13,xmm14,xmm15, + + ymm0,ymm1,ymm2,ymm3,ymm4,ymm5,ymm6,ymm7, + ymm8,ymm9,ymm10,ymm11,ymm12,ymm13,ymm14,ymm15, + + // zmm0,zmm1,zmm2,zmm3,zmm4,zmm5,zmm6,zmm7, + // zmm8,zmm9,zmm10,zmm11,zmm12,zmm13,zmm14,zmm15, +} + +impl core::fmt::Display for Register { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let name = match self { + Register::rax => "rax", + Register::eax => "eax", + Register::ax => "ax", + Register::al => "al", + Register::ah => "ah", + Register::rbx => "rbx", + Register::ebx => "ebx", + Register::bx => "bx", + Register::bl => "bl", + Register::bh => "bh", + Register::rcx => "rcx", + Register::ecx => "ecx", + Register::cx => "cx", + Register::cl => "cl", + Register::ch => "ch", + Register::rdx => "rdx", + Register::edx => "edx", + Register::dx => "dx", + Register::dl => "dl", + Register::dh => "dh", + Register::rsi => "rsi", + Register::esi => "esi", + Register::si => "si", + Register::sil => "sil", + Register::rdi => "rdi", + Register::edi => "edi", + Register::di => "di", + Register::dil => "dil", + Register::rsp => "rsp", + Register::esp => "esp", + Register::sp => "sp", + Register::spl => "spl", + Register::rbp => "rbp", + Register::ebp => "ebp", + Register::bp => "bp", + Register::bpl => "bpl", + Register::r8 => "r8", + Register::r8d => "r8d", + Register::r8w => "r8w", + Register::r8b => "r8b", + Register::r9 => "r9", + Register::r9d => "r9d", + Register::r9w => "r9w", + Register::r9b => "r9b", + Register::r10 => "r10", + Register::r10d => "r10d", + Register::r10w => "r10w", + Register::r10b => "r10b", + Register::r11 => "r11", + Register::r11d => "r11d", + Register::r11w => "r11w", + Register::r11b => "r11b", + Register::r12 => "r12", + Register::r12d => "r12d", + Register::r12w => "r12w", + Register::r12b => "r12b", + Register::r13 => "r13", + Register::r13d => "r13d", + Register::r13w => "r13w", + Register::r13b => "r13b", + Register::r14 => "r14", + Register::r14d => "r14d", + Register::r14w => "r14w", + Register::r14b => "r14b", + Register::r15 => "r15", + Register::r15d => "r15d", + Register::r15w => "r15w", + Register::r15b => "r15b", + Register::rip => "rip", + Register::eip => "eip", + Register::ip => "ip", + Register::__ipl => "__ipl", + Register::st0 => "st0", + Register::st1 => "st1", + Register::st2 => "st2", + Register::st3 => "st3", + Register::st4 => "st4", + Register::st5 => "st5", + Register::st6 => "st6", + Register::st7 => "st7", + Register::mm0 => "mm0", + Register::mm1 => "mm1", + Register::mm2 => "mm2", + Register::mm3 => "mm3", + Register::mm4 => "mm4", + Register::mm5 => "mm5", + Register::mm6 => "mm6", + Register::mm7 => "mm7", + Register::xmm0 => "xmm0", + Register::xmm1 => "xmm1", + Register::xmm2 => "xmm2", + Register::xmm3 => "xmm3", + Register::xmm4 => "xmm4", + Register::xmm5 => "xmm5", + Register::xmm6 => "xmm6", + Register::xmm7 => "xmm7", + Register::xmm8 => "xmm8", + Register::xmm9 => "xmm9", + Register::xmm10 => "xmm10", + Register::xmm11 => "xmm11", + Register::xmm12 => "xmm12", + Register::xmm13 => "xmm13", + Register::xmm14 => "xmm14", + Register::xmm15 => "xmm15", + Register::ymm0 => "ymm0", + Register::ymm1 => "ymm1", + Register::ymm2 => "ymm2", + Register::ymm3 => "ymm3", + Register::ymm4 => "ymm4", + Register::ymm5 => "ymm5", + Register::ymm6 => "ymm6", + Register::ymm7 => "ymm7", + Register::ymm8 => "ymm8", + Register::ymm9 => "ymm9", + Register::ymm10 => "ymm10", + Register::ymm11 => "ymm11", + Register::ymm12 => "ymm12", + Register::ymm13 => "ymm13", + Register::ymm14 => "ymm14", + Register::ymm15 => "ymm15", + }; + write!(f, "{name}") + } +} + +impl Register { + const fn bit_size(self) -> u32 { + use Register::*; + match self { + ah | bh | ch | dh | al | bl | cl | dl | sil | dil | spl | bpl | r8b | r9b | r10b + | r11b | r12b | r13b | r14b | r15b => 8, + + ax | bx | cx | dx | si | di | sp | bp | ip | r8w | r9w | r10w | r11w | r12w | r13w + | r14w | r15w => 16, + + eax | ebx | ecx | edx | esi | edi | esp | ebp | eip | r8d | r9d | r10d | r11d + | r12d | r13d | r14d | r15d => 32, + + rax | rbx | rcx | rdx | rsi | rdi | rsp | rbp | rip | r8 | r9 | r10 | r11 | r12 + | r13 | r14 | r15 => 64, + + mm0 | mm1 | mm2 | mm3 | mm4 | mm5 | mm6 | mm7 => 64, + + st0 | st1 | st2 | st3 | st4 | st5 | st6 | st7 => 80, + + xmm0 | xmm1 | xmm2 | xmm3 | xmm4 | xmm5 | xmm6 | xmm7 | xmm8 | xmm9 | xmm10 | xmm11 + | xmm12 | xmm13 | xmm14 | xmm15 => 128, + + ymm0 | ymm1 | ymm2 | ymm3 | ymm4 | ymm5 | ymm6 | ymm7 | ymm8 | ymm9 | ymm10 | ymm11 + | ymm12 | ymm13 | ymm14 | ymm15 => 256, + _ => unreachable!(), + } + } + + const fn byte_size(self) -> u32 { + self.bit_size().div_ceil(8) + } + + const fn into_parent_register(self) -> Self { + use Register::*; + match self { + rax | eax | ax | ah | al => rax, + rbx | ebx | bx | bh | bl => rbx, + rcx | ecx | cx | ch | cl => rcx, + rdx | edx | dx | dh | dl => rdx, + rsi | esi | si | sil => rsi, + rdi | edi | di | dil => rdi, + rsp | esp | sp | spl => rsp, + rbp | ebp | bp | bpl => rbp, + + rip | eip | ip => rip, + + r8 | r8d | r8w | r8b => r8, + r9 | r9d | r9w | r9b => r9, + r10 | r10d | r10w | r10b => r10, + r11 | r11d | r11w | r11b => r11, + r12 | r12d | r12w | r12b => r12, + r13 | r13d | r13w | r13b => r13, + r14 | r14d | r14w | r14b => r14, + r15 | r15d | r15w | r15b => r15, + reg => reg, + } + } + + const fn from_u8(val: u8) -> Self { + unsafe { *(&val as *const u8 as *const Self) } + } + + const fn into_qword(self) -> Self { + Self::from_u8(self.into_parent_register() as u8) + } + + const fn into_dword(self) -> Self { + Self::from_u8(self.into_parent_register() as u8 + 1) + } + + const fn into_word(self) -> Self { + Self::from_u8(self.into_parent_register() as u8 + 2) + } + + const fn into_byte(self) -> Self { + Self::from_u8(self.into_parent_register() as u8 + 3) + } + + fn into_bitsize(self, size: u32) -> Self { + assert!(self < Self::__ipl); + match size { + 8 => self.into_byte(), + 16 => self.into_word(), + 32 => self.into_dword(), + 64 => self.into_qword(), + _ => panic!("unsupported bitsize {size}"), + } + } + + pub const GPR: [Register; 14] = { + use Register::*; + [ + rax, rbx, rcx, rdx, rsi, rdi, r8, r9, r10, r11, r12, r13, r14, r15, + ] + }; + pub const SSE: [Register; 16] = { + use Register::*; + [ + xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, + xmm14, xmm15, + ] + }; + + const fn is_gp(self) -> bool { + use Register::*; + match self { + rax | eax | ax | ah | al | rbx | ebx | bx | bh | bl | rcx | ecx | cx | ch | cl + | rdx | edx | dx | dh | dl | rsi | esi | si | sil | rdi | edi | di | dil | r8 | r8d + | r8w | r8b | r9 | r9d | r9w | r9b | r10 | r10d | r10w | r10b | r11 | r11d | r11w + | r11b | r12 | r12d | r12w | r12b | r13 | r13d | r13w | r13b | r14 | r14d | r14w + | r14b | r15 | r15d | r15w | r15b => true, + _ => false, + } + } +} + +pub enum Operands { + One(Operand), + Two(Operand, Operand), + Three(Operand, Operand, Operand), +} + +#[allow(non_camel_case_types)] +pub enum Operand { + imm8(u8), + imm16(u16), + imm32(u32), + imm64(u64), + reg8(u32), + reg16(u32), + reg32(u32), + reg64(u32), + mem8(u32), + mem16(u32), + mem32(u32), + mem64(u32), + moffset64(u64), +} + +impl Operand { + pub fn imm8(i: u8) -> Self { + Operand::imm8(i) + } + pub fn imm16(i: u16) -> Self { + Operand::imm16(i) + } + pub fn imm32(i: u32) -> Self { + Operand::imm32(i) + } + pub fn imm64(i: u64) -> Self { + Operand::imm64(i) + } + pub fn reg8(i: u32) -> Self { + Operand::reg8(i) + } + pub fn reg16(i: u32) -> Self { + Operand::reg16(i) + } + pub fn reg32(i: u32) -> Self { + Operand::reg32(i) + } + pub fn reg64(i: u32) -> Self { + Operand::reg64(i) + } + pub fn mem8(i: u32) -> Self { + Operand::mem8(i) + } + pub fn mem16(i: u32) -> Self { + Operand::mem16(i) + } + pub fn mem32(i: u32) -> Self { + Operand::mem32(i) + } + pub fn mem64(i: u32) -> Self { + Operand::mem64(i) + } + pub fn moffset64(i: u64) -> Self { + Operand::moffset64(i) + } +} + +pub enum Imm { + Byte(u8), + Word(u16), + DWord(u32), + /// only allowed for `mov` + QWord(u64), +} + +enum ModRM { + register, + displacement, +} + +pub enum Memory {} + +/// r := register, m := memory, i := immediate +#[allow(non_camel_case_types)] +pub enum Payload { + rr(Register, Register), + rm, + ri, + r(Register), + m, + i, +} diff --git a/src/asm/mod.rs b/src/asm/mod.rs new file mode 100644 index 0000000..054d252 --- /dev/null +++ b/src/asm/mod.rs @@ -0,0 +1 @@ +pub mod amd64;