Ejemplo n.º 1
0
 public byte[] this[RegisterTable table, RegisterCapacity cap, XRegCode register]
 {
     // An easy way to fetch a register given its information.
     // Returns a byte[] of length $cap consisting of the bottom $cap bytes of $Registers[$table+$register]
     // Access to upper byte registers such as AH can be done artifically by fetching AX then using $AX[1] as the upper byte.
     get
     {
         byte[] Output = new byte[(int)cap];
         for (int i = 0; i < Output.Length; i++)
         {
             Output[i] = Registers[(int)register + (int)table][i];
         }
         return(Output);
     }
     set
     {
         // If the length of the input byte array is greater than the capacity, data would be lost. Something wrong here would most likely be on my part.
         if (value.Length > ((int)cap))
         {
             throw new Exception("RegisterGroup.cs Attempt to overflow register in base class");
         }
         // Overwrite the bytes in $Registers[] with $value[]
         for (int i = 0; i < value.Length; i++)
         {
             Registers[(int)register + (int)table][i] = value[i];
         }
     }
 }
Ejemplo n.º 2
0
 public SplitRegisterHandle(XRegCode lower, XRegCode upper, SplitRegisterHandleSettings settings = SplitRegisterHandleSettings.NONE)
 {
     // Create the handles for the two registers ready so they do not have to be created more than once.
     Upper    = new ControlUnit.RegisterHandle(upper, RegisterTable.GP);
     Lower    = new ControlUnit.RegisterHandle(lower, RegisterTable.GP);
     Settings = settings;
 }
Ejemplo n.º 3
0
            public RegisterHandle(XRegCode registerCode, RegisterTable table, RegisterCapacity size = RegisterCapacity.NONE, RegisterHandleSettings settings = RegisterHandleSettings.NONE)
            {
                // A constructor for infering a register from a set of arguments.
                // Strictly this isnt done here, rather in the Fetch() and Set() methods
                Code     = registerCode;
                Table    = table;
                Settings = settings;

                // If the input register capacity is NONE(or there wasn't one passed in the arguments), do not initialise the size.
                // This means that attempting to use the register handle before it is initialised will consistently throw the same exception.
                if (size != RegisterCapacity.NONE)
                {
                    Size = size;
                }

                // If $size was NONE, and the register handle has NO_INIT set, there would never be a possibility of the register handle being used, so throw an exception now.
                // This rounds down the problem a little more than a "variable not initialised" exception or alike, as it would be a typo or improper class usage.
                else if ((Settings | RegisterHandleSettings.NO_INIT) == Settings)
                {
                    throw new System.Exception("Must be a possibility of register size initialising.");
                }
            }
Ejemplo n.º 4
0
 public byte GetUpperByte(XRegCode reg) => Registers[(int)reg][1];
Ejemplo n.º 5
0
        public StringOperation(string mnemonic, XRegCode destination, XRegCode source, StringOpSettings settings)
        {
            Settings = settings;

            // Determine capacity as well as an informal mnemonic convention. I haven't seen it defined anywhere, but
            // in many programs such as GDB and GCC, this is used/accepted.
            // BYTE => append "B"
            // WORD => append "W"
            // DWORD => append "D"
            // QWORD => append "Q"
            // E.g,
            // SCAS RAX, QWORD PTR [RSI] => SCASQ
            // CMPS BYTE PTR [RDI], BYTE PTR[RSI] => CMPSB
            // However in my program(as with numerous others), the operands will remain but
            // without BYTE PTR or equivalent. This does slightly contradict the purpose of
            // this convention, but I don't expect everyone using the program to know the
            // operands of every string operation off by heart(as each has a constant set of operands).
            if ((Settings | StringOpSettings.BYTEMODE) == Settings)
            {
                Capacity  = RegisterCapacity.BYTE;
                mnemonic += 'B';
            }
            else if ((ControlUnit.RexByte | REX.W) == ControlUnit.RexByte)
            {
                Capacity  = RegisterCapacity.QWORD;
                mnemonic += 'Q';
            }
            else if (ControlUnit.LPrefixBuffer.Contains(PrefixByte.SIZEOVR))
            {
                Capacity  = RegisterCapacity.WORD;
                mnemonic += 'W';
            }
            else
            {
                Capacity  = RegisterCapacity.DWORD;
                mnemonic += 'D';
            }

            Mnemonic = mnemonic;

            // Determine and store the pointer size(There will always be at least one). E.g [RSI] or [ESI].
            PtrSize = ControlUnit.LPrefixBuffer.Contains(PrefixByte.ADDROVR) ? RegisterCapacity.DWORD : RegisterCapacity.QWORD;

            // Create a handle to the destination. If the destination is DI, treat it as a pointer, as DI is always a pointer in a
            // string operation. destination == XRegCode.DI will also be checked later to mimic the same behaviour.
            Destination = new ControlUnit.RegisterHandle(destination, RegisterTable.GP, (destination == XRegCode.DI) ? PtrSize : Capacity);

            // Same as the above
            Source = new ControlUnit.RegisterHandle(source, RegisterTable.GP, (source == XRegCode.SI) ? PtrSize : Capacity);

            // Convert the two operands into pointers. These will only be used if their XRegCode is SI or DI, but stored regardless.
            // Saving these to a variable means that the registers themselves do not have to be operated on until the execution of
            // the opcode has finished.
            DestPtr = BitConverter.ToUInt64(Bitwise.ZeroExtend(Destination.FetchOnce(), 8), 0);
            SrcPtr  = BitConverter.ToUInt64(Bitwise.ZeroExtend(Source.FetchOnce(), 8), 0);

            // Fetch and store the value operand. This will only be ever used if one operand is the A register. This is because
            // the value of the register is only needed to form the pointers above if the register is SI/DI. There can only
            // be one operand that is the A register, therefore only the value of that operand needs to be stored. If there
            // is no A register, SI will be stored in ValueOperand.
            ValueOperand = (Destination.Code == XRegCode.A) ? Destination.FetchAs(Capacity) : Source.FetchAs(Capacity);

            OnInitialise();
        }