|
1 #include "ia32_modrm.h" |
|
2 #include "ia32_reg.h" |
|
3 #include "x86_imm.h" |
|
4 |
|
5 /* NOTE: when decoding ModR/M and SIB, we have to add 1 to all register |
|
6 * values obtained from decoding the ModR/M or SIB byte, since they |
|
7 * are encoded with eAX = 0 and the tables in ia32_reg.c use eAX = 1. |
|
8 * ADDENDUM: this is only the case when the register value is used |
|
9 * directly as an index into the register table, not when it is added to |
|
10 * a genregs offset. */ |
|
11 |
|
12 /* -------------------------------- ModR/M, SIB */ |
|
13 /* ModR/M flags */ |
|
14 #define MODRM_RM_SIB 0x04 /* R/M == 100 */ |
|
15 #define MODRM_RM_NOREG 0x05 /* R/B == 101 */ |
|
16 |
|
17 /* if (MODRM.MOD_NODISP && MODRM.RM_NOREG) then just disp32 */ |
|
18 #define MODRM_MOD_NODISP 0x00 /* mod == 00 */ |
|
19 #define MODRM_MOD_DISP8 0x01 /* mod == 01 */ |
|
20 #define MODRM_MOD_DISP32 0x02 /* mod == 10 */ |
|
21 #define MODRM_MOD_NOEA 0x03 /* mod == 11 */ |
|
22 |
|
23 /* 16-bit modrm flags */ |
|
24 #define MOD16_MOD_NODISP 0 |
|
25 #define MOD16_MOD_DISP8 1 |
|
26 #define MOD16_MOD_DISP16 2 |
|
27 #define MOD16_MOD_REG 3 |
|
28 |
|
29 #define MOD16_RM_BXSI 0 |
|
30 #define MOD16_RM_BXDI 1 |
|
31 #define MOD16_RM_BPSI 2 |
|
32 #define MOD16_RM_BPDI 3 |
|
33 #define MOD16_RM_SI 4 |
|
34 #define MOD16_RM_DI 5 |
|
35 #define MOD16_RM_BP 6 |
|
36 #define MOD16_RM_BX 7 |
|
37 |
|
38 /* SIB flags */ |
|
39 #define SIB_INDEX_NONE 0x04 |
|
40 #define SIB_BASE_EBP 0x05 |
|
41 #define SIB_SCALE_NOBASE 0x00 |
|
42 |
|
43 /* Convenience struct for modR/M bitfield */ |
|
44 struct modRM_byte { |
|
45 unsigned int mod : 2; |
|
46 unsigned int reg : 3; |
|
47 unsigned int rm : 3; |
|
48 }; |
|
49 |
|
50 /* Convenience struct for SIB bitfield */ |
|
51 struct SIB_byte { |
|
52 unsigned int scale : 2; |
|
53 unsigned int index : 3; |
|
54 unsigned int base : 3; |
|
55 }; |
|
56 |
|
57 |
|
58 #if 0 |
|
59 int modrm_rm[] = {0,1,2,3,MODRM_RM_SIB,MODRM_MOD_DISP32,6,7}; |
|
60 int modrm_reg[] = {0, 1, 2, 3, 4, 5, 6, 7}; |
|
61 int modrm_mod[] = {0, MODRM_MOD_DISP8, MODRM_MOD_DISP32, MODRM_MOD_NOEA}; |
|
62 int sib_scl[] = {0, 2, 4, 8}; |
|
63 int sib_idx[] = {0, 1, 2, 3, SIB_INDEX_NONE, 5, 6, 7 }; |
|
64 int sib_bas[] = {0, 1, 2, 3, 4, SIB_SCALE_NOBASE, 6, 7 }; |
|
65 #endif |
|
66 |
|
67 /* this is needed to replace x86_imm_signsized() which does not sign-extend |
|
68 * to dest */ |
|
69 static unsigned int imm32_signsized( unsigned char *buf, size_t buf_len, |
|
70 int32_t *dest, unsigned int size ) { |
|
71 if ( size > buf_len ) { |
|
72 return 0; |
|
73 } |
|
74 |
|
75 switch (size) { |
|
76 case 1: |
|
77 *dest = *((signed char *) buf); |
|
78 break; |
|
79 case 2: |
|
80 *dest = *((signed short *) buf); |
|
81 break; |
|
82 case 4: |
|
83 default: |
|
84 *dest = *((signed int *) buf); |
|
85 break; |
|
86 } |
|
87 |
|
88 return size; |
|
89 } |
|
90 |
|
91 |
|
92 |
|
93 static void byte_decode(unsigned char b, struct modRM_byte *modrm) { |
|
94 /* generic bitfield-packing routine */ |
|
95 |
|
96 modrm->mod = b >> 6; /* top 2 bits */ |
|
97 modrm->reg = (b & 56) >> 3; /* middle 3 bits */ |
|
98 modrm->rm = b & 7; /* bottom 3 bits */ |
|
99 } |
|
100 |
|
101 |
|
102 static size_t sib_decode( unsigned char *buf, size_t buf_len, x86_ea_t *ea, |
|
103 unsigned int mod ) { |
|
104 /* set Address Expression fields (scale, index, base, disp) |
|
105 * according to the contents of the SIB byte. |
|
106 * b points to the SIB byte in the instruction-stream buffer; the |
|
107 * byte after b[0] is therefore the byte after the SIB |
|
108 * returns number of bytes 'used', including the SIB byte */ |
|
109 size_t size = 1; /* start at 1 for SIB byte */ |
|
110 struct SIB_byte sib; |
|
111 |
|
112 if ( buf_len < 1 ) { |
|
113 return 0; |
|
114 } |
|
115 |
|
116 byte_decode( *buf, (struct modRM_byte *)(void*)&sib ); /* get bit-fields */ |
|
117 |
|
118 if ( sib.base == SIB_BASE_EBP && ! mod ) { /* if base == 101 (ebp) */ |
|
119 /* IF BASE == EBP, deal with exception */ |
|
120 /* IF (ModR/M did not create a Disp */ |
|
121 /* ... create a 32-bit Displacement */ |
|
122 imm32_signsized( &buf[1], buf_len, &ea->disp, sizeof(int32_t)); |
|
123 ea->disp_size = sizeof(int32_t); |
|
124 ea->disp_sign = (ea->disp < 0) ? 1 : 0; |
|
125 size += 4; /* add sizeof disp to count */ |
|
126 |
|
127 } else { |
|
128 /* ELSE BASE refers to a General Register */ |
|
129 ia32_handle_register( &ea->base, sib.base + 1 ); |
|
130 } |
|
131 |
|
132 /* set scale to 1, 2, 4, 8 */ |
|
133 ea->scale = 1 << sib.scale; |
|
134 |
|
135 if (sib.index != SIB_INDEX_NONE) { |
|
136 /* IF INDEX is not 'ESP' (100) */ |
|
137 ia32_handle_register( &ea->index, sib.index + 1 ); |
|
138 } |
|
139 |
|
140 return (size); /* return number of bytes processed */ |
|
141 } |
|
142 |
|
143 static size_t modrm_decode16( unsigned char *buf, unsigned int buf_len, |
|
144 x86_op_t *op, struct modRM_byte *modrm ) { |
|
145 /* 16-bit mode: hackish, but not as hackish as 32-bit mode ;) */ |
|
146 size_t size = 1; /* # of bytes decoded [1 for modR/M byte] */ |
|
147 x86_ea_t * ea = &op->data.expression; |
|
148 |
|
149 switch( modrm->rm ) { |
|
150 case MOD16_RM_BXSI: |
|
151 ia32_handle_register(&ea->base, REG_WORD_OFFSET + 3); |
|
152 ia32_handle_register(&ea->index, REG_WORD_OFFSET + 6); |
|
153 break; |
|
154 case MOD16_RM_BXDI: |
|
155 ia32_handle_register(&ea->base, REG_WORD_OFFSET + 3); |
|
156 ia32_handle_register(&ea->index, REG_WORD_OFFSET + 7); |
|
157 case MOD16_RM_BPSI: |
|
158 op->flags |= op_ss_seg; |
|
159 ia32_handle_register(&ea->base, REG_WORD_OFFSET + 5); |
|
160 ia32_handle_register(&ea->index, REG_WORD_OFFSET + 6); |
|
161 break; |
|
162 case MOD16_RM_BPDI: |
|
163 op->flags |= op_ss_seg; |
|
164 ia32_handle_register(&ea->base, REG_WORD_OFFSET + 5); |
|
165 ia32_handle_register(&ea->index, REG_WORD_OFFSET + 7); |
|
166 break; |
|
167 case MOD16_RM_SI: |
|
168 ia32_handle_register(&ea->base, REG_WORD_OFFSET + 6); |
|
169 break; |
|
170 case MOD16_RM_DI: |
|
171 ia32_handle_register(&ea->base, REG_WORD_OFFSET + 7); |
|
172 break; |
|
173 case MOD16_RM_BP: |
|
174 if ( modrm->mod != MOD16_MOD_NODISP ) { |
|
175 op->flags |= op_ss_seg; |
|
176 ia32_handle_register(&ea->base, |
|
177 REG_WORD_OFFSET + 5); |
|
178 } |
|
179 break; |
|
180 case MOD16_RM_BX: |
|
181 ia32_handle_register(&ea->base, REG_WORD_OFFSET + 3); |
|
182 break; |
|
183 } |
|
184 |
|
185 /* move to byte after ModR/M */ |
|
186 ++buf; |
|
187 --buf_len; |
|
188 |
|
189 if ( modrm->mod == MOD16_MOD_DISP8 ) { |
|
190 imm32_signsized( buf, buf_len, &ea->disp, sizeof(char) ); |
|
191 ea->disp_sign = (ea->disp < 0) ? 1 : 0; |
|
192 ea->disp_size = sizeof(char); |
|
193 size += sizeof(char); |
|
194 } else if ( modrm->mod == MOD16_MOD_DISP16 ) { |
|
195 imm32_signsized( buf, buf_len, &ea->disp, sizeof(short) ); |
|
196 ea->disp_sign = (ea->disp < 0) ? 1 : 0; |
|
197 ea->disp_size = sizeof(short); |
|
198 size += sizeof(short); |
|
199 } |
|
200 |
|
201 return size; |
|
202 } |
|
203 |
|
204 /* TODO : Mark index modes |
|
205 Use addressing mode flags to imply arrays (index), structure (disp), |
|
206 two-dimensional arrays [disp + index], classes [ea reg], and so on. |
|
207 */ |
|
208 size_t ia32_modrm_decode( unsigned char *buf, unsigned int buf_len, |
|
209 x86_op_t *op, x86_insn_t *insn, size_t gen_regs ) { |
|
210 /* create address expression and/or fill operand based on value of |
|
211 * ModR/M byte. Calls sib_decode as appropriate. |
|
212 * flags specifies whether Reg or mod+R/M fields are being decoded |
|
213 * returns the number of bytes in the instruction, including modR/M */ |
|
214 struct modRM_byte modrm; |
|
215 size_t size = 1; /* # of bytes decoded [1 for modR/M byte] */ |
|
216 x86_ea_t * ea; |
|
217 |
|
218 |
|
219 byte_decode(*buf, &modrm); /* get bitfields */ |
|
220 |
|
221 /* first, handle the case where the mod field is a register only */ |
|
222 if ( modrm.mod == MODRM_MOD_NOEA ) { |
|
223 op->type = op_register; |
|
224 ia32_handle_register(&op->data.reg, modrm.rm + gen_regs); |
|
225 /* increase insn size by 1 for modrm byte */ |
|
226 return 1; |
|
227 } |
|
228 |
|
229 /* then deal with cases where there is an effective address */ |
|
230 ea = &op->data.expression; |
|
231 op->type = op_expression; |
|
232 op->flags |= op_pointer; |
|
233 |
|
234 if ( insn->addr_size == 2 ) { |
|
235 /* gah! 16 bit mode! */ |
|
236 return modrm_decode16( buf, buf_len, op, &modrm); |
|
237 } |
|
238 |
|
239 /* move to byte after ModR/M */ |
|
240 ++buf; |
|
241 --buf_len; |
|
242 |
|
243 if (modrm.mod == MODRM_MOD_NODISP) { /* if mod == 00 */ |
|
244 |
|
245 /* IF MOD == No displacement, just Indirect Register */ |
|
246 if (modrm.rm == MODRM_RM_NOREG) { /* if r/m == 101 */ |
|
247 /* IF RM == No Register, just Displacement */ |
|
248 /* This is an Intel Moronic Exception TM */ |
|
249 imm32_signsized( buf, buf_len, &ea->disp, |
|
250 sizeof(int32_t) ); |
|
251 ea->disp_size = sizeof(int32_t); |
|
252 ea->disp_sign = (ea->disp < 0) ? 1 : 0; |
|
253 size += 4; /* add sizeof disp to count */ |
|
254 |
|
255 } else if (modrm.rm == MODRM_RM_SIB) { /* if r/m == 100 */ |
|
256 /* ELSE IF an SIB byte is present */ |
|
257 /* TODO: check for 0 retval */ |
|
258 size += sib_decode( buf, buf_len, ea, modrm.mod); |
|
259 /* move to byte after SIB for displacement */ |
|
260 ++buf; |
|
261 --buf_len; |
|
262 } else { /* modR/M specifies base register */ |
|
263 /* ELSE RM encodes a general register */ |
|
264 ia32_handle_register( &ea->base, modrm.rm + 1 ); |
|
265 } |
|
266 } else { /* mod is 01 or 10 */ |
|
267 if (modrm.rm == MODRM_RM_SIB) { /* rm == 100 */ |
|
268 /* IF base is an AddrExpr specified by an SIB byte */ |
|
269 /* TODO: check for 0 retval */ |
|
270 size += sib_decode( buf, buf_len, ea, modrm.mod); |
|
271 /* move to byte after SIB for displacement */ |
|
272 ++buf; |
|
273 --buf_len; |
|
274 } else { |
|
275 /* ELSE base is a general register */ |
|
276 ia32_handle_register( &ea->base, modrm.rm + 1 ); |
|
277 } |
|
278 |
|
279 /* ELSE mod + r/m specify a disp##[base] or disp##(SIB) */ |
|
280 if (modrm.mod == MODRM_MOD_DISP8) { /* mod == 01 */ |
|
281 /* If this is an 8-bit displacement */ |
|
282 imm32_signsized( buf, buf_len, &ea->disp, |
|
283 sizeof(char)); |
|
284 ea->disp_size = sizeof(char); |
|
285 ea->disp_sign = (ea->disp < 0) ? 1 : 0; |
|
286 size += 1; /* add sizeof disp to count */ |
|
287 |
|
288 } else { |
|
289 /* Displacement is dependent on address size */ |
|
290 imm32_signsized( buf, buf_len, &ea->disp, |
|
291 insn->addr_size); |
|
292 ea->disp_size = insn->addr_size; |
|
293 ea->disp_sign = (ea->disp < 0) ? 1 : 0; |
|
294 size += 4; |
|
295 } |
|
296 } |
|
297 |
|
298 return size; /* number of bytes found in instruction */ |
|
299 } |
|
300 |
|
301 void ia32_reg_decode( unsigned char byte, x86_op_t *op, size_t gen_regs ) { |
|
302 struct modRM_byte modrm; |
|
303 byte_decode( byte, &modrm ); /* get bitfields */ |
|
304 |
|
305 /* set operand to register ID */ |
|
306 op->type = op_register; |
|
307 ia32_handle_register(&op->data.reg, modrm.reg + gen_regs); |
|
308 |
|
309 return; |
|
310 } |