12b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org#include "ia32_modrm.h" 22b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org#include "ia32_reg.h" 32b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org#include "x86_imm.h" 42b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org 52b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org/* NOTE: when decoding ModR/M and SIB, we have to add 1 to all register 62b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org * values obtained from decoding the ModR/M or SIB byte, since they 72b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org * are encoded with eAX = 0 and the tables in ia32_reg.c use eAX = 1. 82b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org * ADDENDUM: this is only the case when the register value is used 92b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org * directly as an index into the register table, not when it is added to 102b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org * a genregs offset. */ 112b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org 122b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org/* -------------------------------- ModR/M, SIB */ 132b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org/* ModR/M flags */ 142b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org#define MODRM_RM_SIB 0x04 /* R/M == 100 */ 152b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org#define MODRM_RM_NOREG 0x05 /* R/B == 101 */ 162b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org 172b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org/* if (MODRM.MOD_NODISP && MODRM.RM_NOREG) then just disp32 */ 182b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org#define MODRM_MOD_NODISP 0x00 /* mod == 00 */ 192b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org#define MODRM_MOD_DISP8 0x01 /* mod == 01 */ 202b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org#define MODRM_MOD_DISP32 0x02 /* mod == 10 */ 212b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org#define MODRM_MOD_NOEA 0x03 /* mod == 11 */ 222b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org 232b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org/* 16-bit modrm flags */ 242b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org#define MOD16_MOD_NODISP 0 252b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org#define MOD16_MOD_DISP8 1 262b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org#define MOD16_MOD_DISP16 2 272b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org#define MOD16_MOD_REG 3 282b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org 292b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org#define MOD16_RM_BXSI 0 302b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org#define MOD16_RM_BXDI 1 312b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org#define MOD16_RM_BPSI 2 322b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org#define MOD16_RM_BPDI 3 332b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org#define MOD16_RM_SI 4 342b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org#define MOD16_RM_DI 5 352b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org#define MOD16_RM_BP 6 362b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org#define MOD16_RM_BX 7 372b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org 382b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org/* SIB flags */ 392b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org#define SIB_INDEX_NONE 0x04 402b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org#define SIB_BASE_EBP 0x05 412b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org#define SIB_SCALE_NOBASE 0x00 422b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org 432b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org/* Convenience struct for modR/M bitfield */ 442b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.orgstruct modRM_byte { 452b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org unsigned int mod : 2; 462b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org unsigned int reg : 3; 472b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org unsigned int rm : 3; 482b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org}; 492b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org 502b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org/* Convenience struct for SIB bitfield */ 512b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.orgstruct SIB_byte { 522b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org unsigned int scale : 2; 532b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org unsigned int index : 3; 542b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org unsigned int base : 3; 552b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org}; 562b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org 572b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org 582b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org#if 0 592b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.orgint modrm_rm[] = {0,1,2,3,MODRM_RM_SIB,MODRM_MOD_DISP32,6,7}; 602b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.orgint modrm_reg[] = {0, 1, 2, 3, 4, 5, 6, 7}; 612b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.orgint modrm_mod[] = {0, MODRM_MOD_DISP8, MODRM_MOD_DISP32, MODRM_MOD_NOEA}; 622b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.orgint sib_scl[] = {0, 2, 4, 8}; 632b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.orgint sib_idx[] = {0, 1, 2, 3, SIB_INDEX_NONE, 5, 6, 7 }; 642b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.orgint sib_bas[] = {0, 1, 2, 3, 4, SIB_SCALE_NOBASE, 6, 7 }; 652b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org#endif 662b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org 672b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org/* this is needed to replace x86_imm_signsized() which does not sign-extend 682b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org * to dest */ 692b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.orgstatic unsigned int imm32_signsized( unsigned char *buf, size_t buf_len, 702b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org int32_t *dest, unsigned int size ) { 712b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org if ( size > buf_len ) { 722b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org return 0; 732b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org } 742b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org 752b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org switch (size) { 762b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org case 1: 772b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org *dest = *((signed char *) buf); 782b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org break; 792b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org case 2: 802b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org *dest = *((signed short *) buf); 812b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org break; 822b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org case 4: 832b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org default: 842b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org *dest = *((signed int *) buf); 852b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org break; 862b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org } 872b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org 882b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org return size; 892b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org} 902b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org 912b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org 922b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org 932b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.orgstatic void byte_decode(unsigned char b, struct modRM_byte *modrm) { 942b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org /* generic bitfield-packing routine */ 952b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org 962b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org modrm->mod = b >> 6; /* top 2 bits */ 972b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org modrm->reg = (b & 56) >> 3; /* middle 3 bits */ 982b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org modrm->rm = b & 7; /* bottom 3 bits */ 992b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org} 1002b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org 1012b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org 1022b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.orgstatic size_t sib_decode( unsigned char *buf, size_t buf_len, x86_ea_t *ea, 1032b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org unsigned int mod ) { 1042b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org /* set Address Expression fields (scale, index, base, disp) 1052b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org * according to the contents of the SIB byte. 1062b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org * b points to the SIB byte in the instruction-stream buffer; the 1072b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org * byte after b[0] is therefore the byte after the SIB 1082b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org * returns number of bytes 'used', including the SIB byte */ 1092b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org size_t size = 1; /* start at 1 for SIB byte */ 1102b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org struct SIB_byte sib; 1112b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org 1122b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org if ( buf_len < 1 ) { 1132b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org return 0; 1142b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org } 1152b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org 1162b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org byte_decode( *buf, (struct modRM_byte *)(void*)&sib ); /* get bit-fields */ 1172b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org 1182b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org if ( sib.base == SIB_BASE_EBP && ! mod ) { /* if base == 101 (ebp) */ 1192b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org /* IF BASE == EBP, deal with exception */ 1202b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org /* IF (ModR/M did not create a Disp */ 1212b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org /* ... create a 32-bit Displacement */ 1222b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org imm32_signsized( &buf[1], buf_len, &ea->disp, sizeof(int32_t)); 1232b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org ea->disp_size = sizeof(int32_t); 1242b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org ea->disp_sign = (ea->disp < 0) ? 1 : 0; 1252b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org size += 4; /* add sizeof disp to count */ 1262b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org 1272b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org } else { 1282b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org /* ELSE BASE refers to a General Register */ 1292b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org ia32_handle_register( &ea->base, sib.base + 1 ); 1302b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org } 1312b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org 1322b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org /* set scale to 1, 2, 4, 8 */ 1332b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org ea->scale = 1 << sib.scale; 1342b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org 1352b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org if (sib.index != SIB_INDEX_NONE) { 1362b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org /* IF INDEX is not 'ESP' (100) */ 1372b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org ia32_handle_register( &ea->index, sib.index + 1 ); 1382b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org } 1392b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org 1402b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org return (size); /* return number of bytes processed */ 1412b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org} 1422b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org 1432b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.orgstatic size_t modrm_decode16( unsigned char *buf, unsigned int buf_len, 1442b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org x86_op_t *op, struct modRM_byte *modrm ) { 1452b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org /* 16-bit mode: hackish, but not as hackish as 32-bit mode ;) */ 1462b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org size_t size = 1; /* # of bytes decoded [1 for modR/M byte] */ 1472b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org x86_ea_t * ea = &op->data.expression; 1482b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org 1492b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org switch( modrm->rm ) { 1502b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org case MOD16_RM_BXSI: 1512b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org ia32_handle_register(&ea->base, REG_WORD_OFFSET + 3); 1522b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org ia32_handle_register(&ea->index, REG_WORD_OFFSET + 6); 1532b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org break; 1542b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org case MOD16_RM_BXDI: 1552b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org ia32_handle_register(&ea->base, REG_WORD_OFFSET + 3); 1562b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org ia32_handle_register(&ea->index, REG_WORD_OFFSET + 7); 1572b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org case MOD16_RM_BPSI: 1582b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org op->flags |= op_ss_seg; 1592b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org ia32_handle_register(&ea->base, REG_WORD_OFFSET + 5); 1602b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org ia32_handle_register(&ea->index, REG_WORD_OFFSET + 6); 1612b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org break; 1622b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org case MOD16_RM_BPDI: 1632b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org op->flags |= op_ss_seg; 1642b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org ia32_handle_register(&ea->base, REG_WORD_OFFSET + 5); 1652b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org ia32_handle_register(&ea->index, REG_WORD_OFFSET + 7); 1662b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org break; 1672b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org case MOD16_RM_SI: 1682b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org ia32_handle_register(&ea->base, REG_WORD_OFFSET + 6); 1692b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org break; 1702b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org case MOD16_RM_DI: 1712b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org ia32_handle_register(&ea->base, REG_WORD_OFFSET + 7); 1722b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org break; 1732b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org case MOD16_RM_BP: 1742b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org if ( modrm->mod != MOD16_MOD_NODISP ) { 1752b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org op->flags |= op_ss_seg; 1762b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org ia32_handle_register(&ea->base, 1772b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org REG_WORD_OFFSET + 5); 1782b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org } 1792b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org break; 1802b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org case MOD16_RM_BX: 1812b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org ia32_handle_register(&ea->base, REG_WORD_OFFSET + 3); 1822b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org break; 1832b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org } 1842b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org 1852b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org /* move to byte after ModR/M */ 1862b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org ++buf; 1872b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org --buf_len; 1882b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org 1892b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org if ( modrm->mod == MOD16_MOD_DISP8 ) { 1902b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org imm32_signsized( buf, buf_len, &ea->disp, sizeof(char) ); 1912b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org ea->disp_sign = (ea->disp < 0) ? 1 : 0; 1922b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org ea->disp_size = sizeof(char); 1932b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org size += sizeof(char); 1942b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org } else if ( modrm->mod == MOD16_MOD_DISP16 ) { 1952b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org imm32_signsized( buf, buf_len, &ea->disp, sizeof(short) ); 1962b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org ea->disp_sign = (ea->disp < 0) ? 1 : 0; 1972b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org ea->disp_size = sizeof(short); 1982b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org size += sizeof(short); 1992b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org } 2002b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org 2012b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org return size; 2022b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org} 2032b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org 2042b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org/* TODO : Mark index modes 2052b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org Use addressing mode flags to imply arrays (index), structure (disp), 2062b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org two-dimensional arrays [disp + index], classes [ea reg], and so on. 2072b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org*/ 2082b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.orgsize_t ia32_modrm_decode( unsigned char *buf, unsigned int buf_len, 2092b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org x86_op_t *op, x86_insn_t *insn, size_t gen_regs ) { 2102b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org /* create address expression and/or fill operand based on value of 2112b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org * ModR/M byte. Calls sib_decode as appropriate. 2122b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org * flags specifies whether Reg or mod+R/M fields are being decoded 2132b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org * returns the number of bytes in the instruction, including modR/M */ 2142b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org struct modRM_byte modrm; 2152b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org size_t size = 1; /* # of bytes decoded [1 for modR/M byte] */ 2162b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org x86_ea_t * ea; 2172b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org 2182b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org 2192b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org byte_decode(*buf, &modrm); /* get bitfields */ 2202b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org 2212b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org /* first, handle the case where the mod field is a register only */ 2222b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org if ( modrm.mod == MODRM_MOD_NOEA ) { 2232b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org op->type = op_register; 2242b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org ia32_handle_register(&op->data.reg, modrm.rm + gen_regs); 2252b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org /* increase insn size by 1 for modrm byte */ 2262b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org return 1; 2272b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org } 2282b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org 2292b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org /* then deal with cases where there is an effective address */ 2302b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org ea = &op->data.expression; 2312b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org op->type = op_expression; 2322b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org op->flags |= op_pointer; 2332b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org 2342b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org if ( insn->addr_size == 2 ) { 2352b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org /* gah! 16 bit mode! */ 2362b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org return modrm_decode16( buf, buf_len, op, &modrm); 2372b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org } 2382b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org 2392b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org /* move to byte after ModR/M */ 2402b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org ++buf; 2412b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org --buf_len; 2422b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org 2432b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org if (modrm.mod == MODRM_MOD_NODISP) { /* if mod == 00 */ 2442b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org 2452b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org /* IF MOD == No displacement, just Indirect Register */ 2462b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org if (modrm.rm == MODRM_RM_NOREG) { /* if r/m == 101 */ 2472b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org /* IF RM == No Register, just Displacement */ 2482b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org /* This is an Intel Moronic Exception TM */ 2492b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org imm32_signsized( buf, buf_len, &ea->disp, 2502b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org sizeof(int32_t) ); 2512b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org ea->disp_size = sizeof(int32_t); 2522b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org ea->disp_sign = (ea->disp < 0) ? 1 : 0; 2532b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org size += 4; /* add sizeof disp to count */ 2542b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org 2552b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org } else if (modrm.rm == MODRM_RM_SIB) { /* if r/m == 100 */ 2562b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org /* ELSE IF an SIB byte is present */ 2572b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org /* TODO: check for 0 retval */ 2582b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org size += sib_decode( buf, buf_len, ea, modrm.mod); 2592b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org /* move to byte after SIB for displacement */ 2602b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org ++buf; 2612b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org --buf_len; 2622b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org } else { /* modR/M specifies base register */ 2632b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org /* ELSE RM encodes a general register */ 2642b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org ia32_handle_register( &ea->base, modrm.rm + 1 ); 2652b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org } 2662b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org } else { /* mod is 01 or 10 */ 2672b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org if (modrm.rm == MODRM_RM_SIB) { /* rm == 100 */ 2682b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org /* IF base is an AddrExpr specified by an SIB byte */ 2692b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org /* TODO: check for 0 retval */ 2702b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org size += sib_decode( buf, buf_len, ea, modrm.mod); 2712b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org /* move to byte after SIB for displacement */ 2722b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org ++buf; 2732b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org --buf_len; 2742b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org } else { 2752b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org /* ELSE base is a general register */ 2762b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org ia32_handle_register( &ea->base, modrm.rm + 1 ); 2772b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org } 2782b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org 2792b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org /* ELSE mod + r/m specify a disp##[base] or disp##(SIB) */ 2802b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org if (modrm.mod == MODRM_MOD_DISP8) { /* mod == 01 */ 2812b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org /* If this is an 8-bit displacement */ 2822b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org imm32_signsized( buf, buf_len, &ea->disp, 2832b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org sizeof(char)); 2842b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org ea->disp_size = sizeof(char); 2852b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org ea->disp_sign = (ea->disp < 0) ? 1 : 0; 2862b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org size += 1; /* add sizeof disp to count */ 2872b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org 2882b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org } else { 2892b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org /* Displacement is dependent on address size */ 2902b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org imm32_signsized( buf, buf_len, &ea->disp, 2912b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org insn->addr_size); 2922b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org ea->disp_size = insn->addr_size; 2932b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org ea->disp_sign = (ea->disp < 0) ? 1 : 0; 2942b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org size += 4; 2952b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org } 2962b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org } 2972b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org 2982b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org return size; /* number of bytes found in instruction */ 2992b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org} 3002b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org 3012b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.orgvoid ia32_reg_decode( unsigned char byte, x86_op_t *op, size_t gen_regs ) { 3022b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org struct modRM_byte modrm; 3032b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org byte_decode( byte, &modrm ); /* get bitfields */ 3042b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org 3052b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org /* set operand to register ID */ 3062b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org op->type = op_register; 3072b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org ia32_handle_register(&op->data.reg, modrm.reg + gen_regs); 3082b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org 3092b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org return; 3102b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org} 311