aboutsummaryrefslogblamecommitdiffhomepage
path: root/src/reg.rs
blob: 15417c4015a6f569f2260b9e1480be282f9cd1d4 (plain) (tree)
1
2
3
4
5
6
7

                                                                                      




                                             






                                                       


                                                    
                                    




















                                                                                                  


                                                               














                                                               
 
 


                                                                          






                                              

                                                             





                     











                                                                                                            
                                               












                                      


                                                     


















































                                                                                                 
                               

                                   
                                                                                                               


                                          
                                                   


                                                  
                                                   






























                                           
                               

                                   
                                                                                       


                                          
                                             


                                                  
                                             






























                                           
                               

                                   
                                                                                       


                                          
                                              


                                                  
                                              






























                                           
                              

                                   
                                  

                                   
                                             


                                                  
                                             



                                           
//! Definition of registers which are used as input operands for various instructions.

/// Trait to interact with register operands.
pub(crate) trait Reg {
    /// Get the raw x64 register code.
    fn idx(&self) -> u8;

    /// Check if the registers needs the `REX.W` bit.
    fn rexw(&self) -> bool;

    /// Check if the register is an extended registers.
    fn is_ext(&self) -> bool {
        self.idx() > 7
    }

    /// Check if the register requires a `REX` byte.
    fn need_rex(&self) -> bool {
        self.is_ext() || self.rexw()
    }

    /// Check if the register requires a `SIB` byte if used as addressing operand.
    ///
    /// See [64 bit
    /// addressing](https://wiki.osdev.org/X86-64_Instruction_Encoding#32.2F64-bit_addressing) for
    /// further details.
    fn need_sib(&self) -> bool {
        self.idx() == 4 || self.idx() == 12
    }

    /// Check if the register is interpreted as `PC` relative if used as addressing operand.
    ///
    /// See [64 bit
    /// addressing](https://wiki.osdev.org/X86-64_Instruction_Encoding#32.2F64-bit_addressing) for
    /// further details.
    fn is_pc_rel(&self) -> bool {
        self.idx() == 5 || self.idx() == 13
    }
}

macro_rules! enum_reg {
    (#[$doc:meta]  $name:ident, { $($reg:ident),+ $(,)? }) => {
        #[$doc]
        #[allow(non_camel_case_types)]
        #[derive(Copy, Clone)]
        #[repr(u8)]
        pub enum $name {
            $( $reg, )+
        }

        #[cfg(test)]
        impl $name {
            fn iter() -> impl Iterator<Item = &'static $name> {
                use $name::*;
                [$( $reg, )+].iter()
            }
        }
    };
}

macro_rules! impl_reg {
    (#[$doc:meta] $name:ident, $rexw:expr, { $($reg:ident),+ $(,)? }) => {
        enum_reg!(#[$doc] $name, { $( $reg, )+ });

        impl Reg for $name {
            /// Get the raw x64 register code.
            fn idx(&self) -> u8 {
                *self as u8
            }

            /// Check if the registers needs the `REX.W` bit.
            fn rexw(&self) -> bool {
                $rexw
            }
        }
    }
}

impl_reg!(
    /// Definition of 64 bit registers.
    Reg64, true,  { rax, rcx, rdx, rbx, rsp, rbp, rsi, rdi, r8,  r9,  r10,  r11,  r12,  r13,  r14,  r15  });
impl_reg!(
    /// Definition of 32 bit registers.
    Reg32, false, { eax, ecx, edx, ebx, esp, ebp, esi, edi, r8d, r9d, r10d, r11d, r12d, r13d, r14d, r15d });
impl_reg!(
    /// Definition of 16 bit registers.
    Reg16, false, { ax,  cx,  dx,  bx,  sp,  bp,  si,  di,  r8w, r9w, r10w, r11w, r12w, r13w, r14w, r15w });
enum_reg!(
    /// Definition of 8 bit registers.
    Reg8,         { al,  cl,  dl,  bl,  spl, bpl, sil, dil, r8l, r9l, r10l, r11l, r12l, r13l, r14l, r15l,
                          ah,  ch,  dh,  bh });

impl Reg for Reg8 {
    /// Get the raw x64 register code.
    fn idx(&self) -> u8 {
        match self {
            Reg8::ah => 4,
            Reg8::ch => 5,
            Reg8::dh => 6,
            Reg8::bh => 7,
            _ => *self as u8,
        }
    }

    /// Check if the registers needs the `REX.W` bit.
    fn rexw(&self) -> bool {
        false
    }

    /// Check whether the gp register needs a `REX` prefix
    /// Check if the register requires a `REX` byte.
    ///
    /// For 1 byte addressing, register indexes `[4:7]` require a `REX` prefix, or else they will
    /// be decoded as `{AH, CH, DH, BH}` accordingly.
    ///
    /// See [Registers](https://wiki.osdev.org/X86-64_Instruction_Encoding#Registers) for
    /// further details or conduct `Table 3-1. Register Codes` in the *Intel Software Developers
    /// Manual - Volume 2*.
    fn need_rex(&self) -> bool {
        self.idx() > 7 || matches!(self, Reg8::spl | Reg8::bpl | Reg8::sil | Reg8::dil)
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_reg8() {
        use Reg8::*;

        for r in Reg8::iter() {
            // Check register index.
            let idx = match r {
                al => 0,
                cl => 1,
                dl => 2,
                bl => 3,
                spl => 4,
                bpl => 5,
                sil => 6,
                dil => 7,
                r8l => 8,
                r9l => 9,
                r10l => 10,
                r11l => 11,
                r12l => 12,
                r13l => 13,
                r14l => 14,
                r15l => 15,
                ah => 4,
                ch => 5,
                dh => 6,
                bh => 7,
            };
            assert_eq!(r.idx(), idx);

            // Check REX.W bit.
            assert!(!r.rexw());

            // Check need REX byte.
            let rex = matches!(r, r8l | r9l | r10l | r11l | r12l | r13l | r14l | r15l | spl | bpl | sil | dil);
            assert_eq!(r.need_rex(), rex);

            // Check need SIB byte.
            let sib = matches!(r, spl | r12l | ah);
            assert_eq!(r.need_sib(), sib);

            // Check if is PC relative addressing.
            let rel = matches!(r, bpl | r13l | ch);
            assert_eq!(r.is_pc_rel(), rel);
        }
    }

    #[test]
    fn test_reg16() {
        use Reg16::*;

        for r in Reg16::iter() {
            // Check register index.
            let idx = match r {
                ax => 0,
                cx => 1,
                dx => 2,
                bx => 3,
                sp => 4,
                bp => 5,
                si => 6,
                di => 7,
                r8w => 8,
                r9w => 9,
                r10w => 10,
                r11w => 11,
                r12w => 12,
                r13w => 13,
                r14w => 14,
                r15w => 15,
            };
            assert_eq!(r.idx(), idx);

            // Check REX.W bit.
            assert!(!r.rexw());

            // Check need REX byte.
            let rex = matches!(r, r8w | r9w | r10w | r11w | r12w | r13w | r14w | r15w);
            assert_eq!(r.need_rex(), rex);

            // Check need SIB byte.
            let sib = matches!(r, sp | r12w);
            assert_eq!(r.need_sib(), sib);

            // Check if is PC relative addressing.
            let rel = matches!(r, bp | r13w);
            assert_eq!(r.is_pc_rel(), rel);
        }
    }

    #[test]
    fn test_reg32() {
        use Reg32::*;

        for r in Reg32::iter() {
            // Check register index.
            let idx = match r {
                eax => 0,
                ecx => 1,
                edx => 2,
                ebx => 3,
                esp => 4,
                ebp => 5,
                esi => 6,
                edi => 7,
                r8d => 8,
                r9d => 9,
                r10d => 10,
                r11d => 11,
                r12d => 12,
                r13d => 13,
                r14d => 14,
                r15d => 15,
            };
            assert_eq!(r.idx(), idx);

            // Check REX.W bit.
            assert!(!r.rexw());

            // Check need REX byte.
            let rex = matches!(r, r8d | r9d | r10d | r11d | r12d | r13d | r14d | r15d);
            assert_eq!(r.need_rex(), rex);

            // Check need SIB byte.
            let sib = matches!(r, esp | r12d);
            assert_eq!(r.need_sib(), sib);

            // Check if is PC relative addressing.
            let rel = matches!(r, ebp | r13d);
            assert_eq!(r.is_pc_rel(), rel);
        }
    }

    #[test]
    fn test_reg64() {
        use Reg64::*;

        for r in Reg64::iter() {
            // Check register index.
            let idx = match r {
                rax => 0,
                rcx => 1,
                rdx => 2,
                rbx => 3,
                rsp => 4,
                rbp => 5,
                rsi => 6,
                rdi => 7,
                r8 => 8,
                r9 => 9,
                r10 => 10,
                r11 => 11,
                r12 => 12,
                r13 => 13,
                r14 => 14,
                r15 => 15,
            };
            assert_eq!(r.idx(), idx);

            // Check REX.W bit.
            assert!(r.rexw());

            // Check need REX byte.
            assert!(r.need_rex());

            // Check need SIB byte.
            let sib = matches!(r, rsp | r12);
            assert_eq!(r.need_sib(), sib);

            // Check if is PC relative addressing.
            let rel = matches!(r, rbp | r13);
            assert_eq!(r.is_pc_rel(), rel);
        }
    }
}