コード例 #1
0
        /// <summary>
        /// Gets the virtual address of a memory operand
        /// </summary>
        /// <param name="operand">Operand number, must be a memory operand</param>
        /// <param name="elementIndex">Only used if it's a vsib memory operand. This is the element index of the vector index register.</param>
        /// <param name="registerValueProvider">Returns values of registers and segment base addresses</param>
        /// <param name="result">Result if this method returns <see langword="true"/></param>
        /// <returns></returns>
        public readonly bool TryGetVirtualAddress(int operand, int elementIndex, IVATryGetRegisterValueProvider registerValueProvider, out ulong result)
        {
            if (registerValueProvider is null)
            {
                throw new ArgumentNullException(nameof(registerValueProvider));
            }
            ulong seg, @base;

            switch (GetOpKind(operand))
            {
            case OpKind.Register:
            case OpKind.NearBranch16:
            case OpKind.NearBranch32:
            case OpKind.NearBranch64:
            case OpKind.FarBranch16:
            case OpKind.FarBranch32:
            case OpKind.Immediate8:
            case OpKind.Immediate8_2nd:
            case OpKind.Immediate16:
            case OpKind.Immediate32:
            case OpKind.Immediate64:
            case OpKind.Immediate8to16:
            case OpKind.Immediate8to32:
            case OpKind.Immediate8to64:
            case OpKind.Immediate32to64:
                result = 0;
                return(true);

            case OpKind.MemorySegSI:
                if (registerValueProvider.TryGetRegisterValue(MemorySegment, 0, 0, out seg) &&
                    registerValueProvider.TryGetRegisterValue(Register.SI, 0, 0, out @base))
                {
                    result = seg + (ushort)@base;
                    return(true);
                }
                break;

            case OpKind.MemorySegESI:
                if (registerValueProvider.TryGetRegisterValue(MemorySegment, 0, 0, out seg) &&
                    registerValueProvider.TryGetRegisterValue(Register.ESI, 0, 0, out @base))
                {
                    result = seg + (uint)@base;
                    return(true);
                }
                break;

            case OpKind.MemorySegRSI:
                if (registerValueProvider.TryGetRegisterValue(MemorySegment, 0, 0, out seg) &&
                    registerValueProvider.TryGetRegisterValue(Register.RSI, 0, 0, out @base))
                {
                    result = seg + @base;
                    return(true);
                }
                break;

            case OpKind.MemorySegDI:
                if (registerValueProvider.TryGetRegisterValue(MemorySegment, 0, 0, out seg) &&
                    registerValueProvider.TryGetRegisterValue(Register.DI, 0, 0, out @base))
                {
                    result = seg + (ushort)@base;
                    return(true);
                }
                break;

            case OpKind.MemorySegEDI:
                if (registerValueProvider.TryGetRegisterValue(MemorySegment, 0, 0, out seg) &&
                    registerValueProvider.TryGetRegisterValue(Register.EDI, 0, 0, out @base))
                {
                    result = seg + (uint)@base;
                    return(true);
                }
                break;

            case OpKind.MemorySegRDI:
                if (registerValueProvider.TryGetRegisterValue(MemorySegment, 0, 0, out seg) &&
                    registerValueProvider.TryGetRegisterValue(Register.RDI, 0, 0, out @base))
                {
                    result = seg + @base;
                    return(true);
                }
                break;

            case OpKind.MemoryESDI:
                if (registerValueProvider.TryGetRegisterValue(Register.ES, 0, 0, out seg) &&
                    registerValueProvider.TryGetRegisterValue(Register.DI, 0, 0, out @base))
                {
                    result = seg + (ushort)@base;
                    return(true);
                }
                break;

            case OpKind.MemoryESEDI:
                if (registerValueProvider.TryGetRegisterValue(Register.ES, 0, 0, out seg) &&
                    registerValueProvider.TryGetRegisterValue(Register.EDI, 0, 0, out @base))
                {
                    result = seg + (uint)@base;
                    return(true);
                }
                break;

            case OpKind.MemoryESRDI:
                if (registerValueProvider.TryGetRegisterValue(Register.ES, 0, 0, out seg) &&
                    registerValueProvider.TryGetRegisterValue(Register.RDI, 0, 0, out @base))
                {
                    result = seg + @base;
                    return(true);
                }
                break;

            case OpKind.Memory:
                var   baseReg  = MemoryBase;
                var   indexReg = MemoryIndex;
                int   addrSize = InstructionUtils.GetAddressSizeInBytes(baseReg, indexReg, MemoryDisplSize, CodeSize);
                ulong offset   = MemoryDisplacement64;
                ulong offsetMask;
                if (addrSize == 8)
                {
                    offsetMask = ulong.MaxValue;
                }
                else if (addrSize == 4)
                {
                    offsetMask = uint.MaxValue;
                }
                else
                {
                    Debug.Assert(addrSize == 2);
                    offsetMask = ushort.MaxValue;
                }
                if (baseReg != Register.None && baseReg != Register.RIP && baseReg != Register.EIP)
                {
                    if (!registerValueProvider.TryGetRegisterValue(baseReg, 0, 0, out @base))
                    {
                        break;
                    }
                    offset += @base;
                }
                var code = Code;
                if (indexReg != Register.None && !code.IgnoresIndex() && !code.IsTileStrideIndex())
                {
                    if (TryGetVsib64(out bool vsib64))
                    {
                        bool b;
                        if (vsib64)
                        {
                            b = registerValueProvider.TryGetRegisterValue(indexReg, elementIndex, 8, out @base);
                        }
                        else
                        {
                            b     = registerValueProvider.TryGetRegisterValue(indexReg, elementIndex, 4, out @base);
                            @base = (ulong)(int)@base;
                        }
                        if (!b)
                        {
                            break;
                        }
                        offset += @base << InternalMemoryIndexScale;
                    }
                    else
                    {
                        if (!registerValueProvider.TryGetRegisterValue(indexReg, 0, 0, out @base))
                        {
                            break;
                        }
                        offset += @base << InternalMemoryIndexScale;
                    }
                }
#if MVEX
                Static.Assert(Code.MVEX_Vloadunpackhd_zmm_k1_mt + 1 == Code.MVEX_Vloadunpackhq_zmm_k1_mt ? 0 : -1);
                Static.Assert(Code.MVEX_Vloadunpackhd_zmm_k1_mt + 2 == Code.MVEX_Vpackstorehd_mt_k1_zmm ? 0 : -1);
                Static.Assert(Code.MVEX_Vloadunpackhd_zmm_k1_mt + 3 == Code.MVEX_Vpackstorehq_mt_k1_zmm ? 0 : -1);
                Static.Assert(Code.MVEX_Vloadunpackhd_zmm_k1_mt + 4 == Code.MVEX_Vloadunpackhps_zmm_k1_mt ? 0 : -1);
                Static.Assert(Code.MVEX_Vloadunpackhd_zmm_k1_mt + 5 == Code.MVEX_Vloadunpackhpd_zmm_k1_mt ? 0 : -1);
                Static.Assert(Code.MVEX_Vloadunpackhd_zmm_k1_mt + 6 == Code.MVEX_Vpackstorehps_mt_k1_zmm ? 0 : -1);
                Static.Assert(Code.MVEX_Vloadunpackhd_zmm_k1_mt + 7 == Code.MVEX_Vpackstorehpd_mt_k1_zmm ? 0 : -1);
                if (code >= Code.MVEX_Vloadunpackhd_zmm_k1_mt && code <= Code.MVEX_Vpackstorehpd_mt_k1_zmm)
                {
                    offset -= 0x40;
                }
#endif
                offset &= offsetMask;
                if (!code.IgnoresSegment())
                {
                    if (!registerValueProvider.TryGetRegisterValue(MemorySegment, 0, 0, out seg))
                    {
                        break;
                    }
                    offset += seg;
                }
                result = offset;
                return(true);

            default:
                throw new InvalidOperationException();
            }

            result = 0;
            return(false);
        }