decode_operand(ref ud u, ref ud_operand operand, ud_operand_code type, ud_operand_size size) { operand.type = ud_type.UD_NONE; operand._oprcode = type; switch (type) { case ud_operand_code.OP_A: decode_a(ref u, ref operand); break; case ud_operand_code.OP_MR: decode_modrm_rm(ref u, ref operand, (byte)reg_class.REGCLASS_GPR, BitOps.MODRM_MOD(modrm(ref u)) == 3 ? size.Mx_reg_size() : size.Mx_mem_size()); break; case ud_operand_code.OP_F: u.br_far = 1; if (BitOps.MODRM_MOD(modrm(ref u)) == 3) { u.error = 1; u.errorMessage = "expected modrm.mod != 3\n"; } decode_modrm_rm(ref u, ref operand, reg_class.REGCLASS_GPR, size); break; case ud_operand_code.OP_M: if (BitOps.MODRM_MOD(modrm(ref u)) == 3) { u.error = 1; u.errorMessage = "expected modrm.mod != 3\n"; } decode_modrm_rm(ref u, ref operand, reg_class.REGCLASS_GPR, size); break; case ud_operand_code.OP_E: decode_modrm_rm(ref u, ref operand, reg_class.REGCLASS_GPR, size); break; case ud_operand_code.OP_G: decode_modrm_reg(ref u, ref operand, reg_class.REGCLASS_GPR, size); break; case ud_operand_code.OP_sI: case ud_operand_code.OP_I: decode_imm(ref u, size, ref operand); break; case ud_operand_code.OP_I1: operand.type = ud_type.UD_OP_CONST; operand.lval.udword = 1; break; case ud_operand_code.OP_N: if (BitOps.MODRM_MOD(modrm(ref u)) != 3) { u.error = 1; u.errorMessage = "expected modrm.mod == 3\n"; } decode_modrm_rm(ref u, ref operand, reg_class.REGCLASS_MMX, size); break; case ud_operand_code.OP_Q: decode_modrm_rm(ref u, ref operand, reg_class.REGCLASS_MMX, size); break; case ud_operand_code.OP_P: decode_modrm_reg(ref u, ref operand, reg_class.REGCLASS_MMX, size); break; case ud_operand_code.OP_U: if (BitOps.MODRM_MOD(modrm(ref u)) != 3) { u.error = 1; u.errorMessage = "expected modrm.mod == 3\n"; } decode_modrm_rm(ref u, ref operand, reg_class.REGCLASS_XMM, size); break; case ud_operand_code.OP_W: decode_modrm_rm(ref u, ref operand, reg_class.REGCLASS_XMM, size); break; case ud_operand_code.OP_V: decode_modrm_reg(ref u, ref operand, reg_class.REGCLASS_XMM, size); break; case ud_operand_code.OP_H: decode_vex_vvvv(ref u, ref operand, size); break; case ud_operand_code.OP_MU: decode_modrm_rm(ref u, ref operand, reg_class.REGCLASS_XMM, BitOps.MODRM_MOD(modrm(ref u)) == 3 ? size.Mx_reg_size() : size.Mx_mem_size()); break; case ud_operand_code.OP_S: decode_modrm_reg(ref u, ref operand, reg_class.REGCLASS_SEG, size); break; case ud_operand_code.OP_O: decode_moffset(ref u, size, ref operand); break; case ud_operand_code.OP_R0: case ud_operand_code.OP_R1: case ud_operand_code.OP_R2: case ud_operand_code.OP_R3: case ud_operand_code.OP_R4: case ud_operand_code.OP_R5: case ud_operand_code.OP_R6: case ud_operand_code.OP_R7: decode_reg(ref u, ref operand, reg_class.REGCLASS_GPR, (byte)((BitOps.REX_B(u._rex) << 3) | (type - ud_operand_code.OP_R0)), size); break; case ud_operand_code.OP_AL: case ud_operand_code.OP_AX: case ud_operand_code.OP_eAX: case ud_operand_code.OP_rAX: decode_reg(ref u, ref operand, reg_class.REGCLASS_GPR, 0, size); break; case ud_operand_code.OP_CL: case ud_operand_code.OP_CX: case ud_operand_code.OP_eCX: decode_reg(ref u, ref operand, reg_class.REGCLASS_GPR, 1, size); break; case ud_operand_code.OP_DL: case ud_operand_code.OP_DX: case ud_operand_code.OP_eDX: decode_reg(ref u, ref operand, reg_class.REGCLASS_GPR, 2, size); break; case ud_operand_code.OP_ES: case ud_operand_code.OP_CS: case ud_operand_code.OP_DS: case ud_operand_code.OP_SS: case ud_operand_code.OP_FS: case ud_operand_code.OP_GS: /* in 64bits mode, only fs and gs are allowed */ if (u.dis_mode == 64) { if (type != ud_operand_code.OP_FS && type != ud_operand_code.OP_GS) { u.error = 1; u.errorMessage = "invalid segment register in 64bits\n"; } } operand.type = ud_type.UD_OP_REG; operand.@base = (type - ud_operand_code.OP_ES) + ud_type.UD_R_ES; operand.size = 16; break; case ud_operand_code.OP_J: decode_imm(ref u, size, ref operand); operand.type = ud_type.UD_OP_JIMM; break; case ud_operand_code.OP_R: if (BitOps.MODRM_MOD(modrm(ref u)) != 3) { u.error = 1; u.errorMessage = "expected modrm.mod == 3\n"; } decode_modrm_rm(ref u, ref operand, reg_class.REGCLASS_GPR, size); break; case ud_operand_code.OP_C: decode_modrm_reg(ref u, ref operand, reg_class.REGCLASS_CR, size); break; case ud_operand_code.OP_D: decode_modrm_reg(ref u, ref operand, reg_class.REGCLASS_DB, size); break; case ud_operand_code.OP_I3: operand.type = ud_type.UD_OP_CONST; operand.lval.@sbyte = 3; break; case ud_operand_code.OP_ST0: case ud_operand_code.OP_ST1: case ud_operand_code.OP_ST2: case ud_operand_code.OP_ST3: case ud_operand_code.OP_ST4: case ud_operand_code.OP_ST5: case ud_operand_code.OP_ST6: case ud_operand_code.OP_ST7: operand.type = ud_type.UD_OP_REG; operand.@base = (type - ud_operand_code.OP_ST0) + ud_type.UD_R_ST0; operand.size = 80; break; case ud_operand_code.OP_L: decode_vex_immreg(ref u, ref operand, size); break; default: operand.type = ud_type.UD_NONE; break; } return(operand.type); }
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; } }