/* * decode_modrm_reg * * Decodes reg field of mod/rm byte * */ void decode_modrm_reg(ref ud u, ref ud_operand operand, reg_class type, ud_operand_size size) { byte reg = (byte)((BitOps.REX_R(u._rex) << 3) | BitOps.MODRM_REG(modrm(ref u))); decode_reg(ref u, ref operand, type, reg, size); }
decode_reg(ref ud u, ref ud_operand opr, reg_class type, byte num, ud_operand_size size) { int reg; size = resolve_operand_size(ref u, size); switch (type) { case reg_class.REGCLASS_GPR: reg = (int)decode_gpr(ref u, size, (byte)num); break; case reg_class.REGCLASS_MMX: reg = (int)ud_type.UD_R_MM0 + (num & 7); break; case reg_class.REGCLASS_XMM: reg = num + (int)(size == ud_operand_size.SZ_QQ ? ud_type.UD_R_YMM0 : ud_type.UD_R_XMM0); break; case reg_class.REGCLASS_CR: reg = (int)ud_type.UD_R_CR0 + num; break; case reg_class.REGCLASS_DB: reg = (int)ud_type.UD_R_DR0 + num; break; case reg_class.REGCLASS_SEG: { /* * Only 6 segment registers, anything else is an error. */ if ((num & 7) > 5) { u.error = 1; u.errorMessage = "invalid segment register value\n"; return; } else { reg = (int)ud_type.UD_R_ES + (num & 7); } break; } default: Debug.Assert(false, "invalid register type"); return; } opr.type = ud_type.UD_OP_REG; opr.@base = (ud_type)reg; opr.size = (byte)size; }
decode_modrm_rm(ref ud u, ref ud_operand op, reg_class type, /* register type */ ud_operand_size size) /* operand size */ { int offset = 0; byte mod, rm; /* get mod, r/m and reg fields */ mod = BitOps.MODRM_MOD(modrm(ref u)); rm = (byte)((BitOps.REX_B(u._rex) << 3) | BitOps.MODRM_RM(modrm(ref u))); /* * If mod is 11b, then the modrm.rm specifies a register. * */ if (mod == 3) { decode_reg(ref u, ref op, type, rm, size); return; } /* * !11b => Memory Address */ op.type = ud_type.UD_OP_MEM; op.size = (byte)resolve_operand_size(ref u, size); if (u.adr_mode == 64) { op.@base = ud_type.UD_R_RAX + rm; if (mod == 1) { offset = 8; } else if (mod == 2) { offset = 32; } else if (mod == 0 && (rm & 7) == 5) { op.@base = ud_type.UD_R_RIP; offset = 32; } else { offset = 0; } /* * Scale-Index-Base (SIB) */ if ((rm & 7) == 4) { inp_next(ref u); op.@base = ud_type.UD_R_RAX + (BitOps.SIB_B(inp_curr(ref u)) | (BitOps.REX_B(u._rex) << 3)); op.index = ud_type.UD_R_RAX + (BitOps.SIB_I(inp_curr(ref u)) | (BitOps.REX_X(u._rex) << 3)); /* special conditions for base reference */ if (op.index == ud_type.UD_R_RSP) { op.index = ud_type.UD_NONE; op.scale = (byte)ud_type.UD_NONE; } else { op.scale = (byte)((1 << BitOps.SIB_S(inp_curr(ref u))) & ~1); } if (op.@base == ud_type.UD_R_RBP || op.@base == ud_type.UD_R_R13) { if (mod == 0) { op.@base = ud_type.UD_NONE; } if (mod == 1) { offset = 8; } else { offset = 32; } } } else { op.scale = 0; op.index = ud_type.UD_NONE; } } else if (u.adr_mode == 32) { op.@base = ud_type.UD_R_EAX + rm; if (mod == 1) { offset = 8; } else if (mod == 2) { offset = 32; } else if (mod == 0 && rm == 5) { op.@base = ud_type.UD_NONE; offset = 32; } else { offset = 0; } /* Scale-Index-Base (SIB) */ if ((rm & 7) == 4) { inp_next(ref u); op.scale = (byte)((1 << BitOps.SIB_S(inp_curr(ref u))) & ~1); op.index = ud_type.UD_R_EAX + (BitOps.SIB_I(inp_curr(ref u)) | (BitOps.REX_X(u.pfx_rex) << 3)); op.@base = ud_type.UD_R_EAX + (BitOps.SIB_B(inp_curr(ref u)) | (BitOps.REX_B(u.pfx_rex) << 3)); if (op.index == ud_type.UD_R_ESP) { op.index = ud_type.UD_NONE; op.scale = (byte)ud_type.UD_NONE; } /* special condition for base reference */ if (op.@base == ud_type.UD_R_EBP) { if (mod == 0) { op.@base = ud_type.UD_NONE; } if (mod == 1) { offset = 8; } else { offset = 32; } } } else { op.scale = 0; op.index = ud_type.UD_NONE; } } else { ud_type[] bases = { ud_type.UD_R_BX, ud_type.UD_R_BX, ud_type.UD_R_BP, ud_type.UD_R_BP, ud_type.UD_R_SI, ud_type.UD_R_DI, ud_type.UD_R_BP, ud_type.UD_R_BX }; ud_type[] indices = { ud_type.UD_R_SI, ud_type.UD_R_DI, ud_type.UD_R_SI, ud_type.UD_R_DI, ud_type.UD_NONE, ud_type.UD_NONE, ud_type.UD_NONE, ud_type.UD_NONE }; op.@base = bases[rm & 7]; op.index = indices[rm & 7]; op.scale = 0; if (mod == 0 && rm == 6) { offset = 16; op.@base = ud_type.UD_NONE; } else if (mod == 1) { offset = 8; } else if (mod == 2) { offset = 16; } } if (offset > 0) { decode_mem_disp(ref u, offset, ref op); } else { op.offset = 0; } }