The ROme OpTimistic Simulator  2.0.0
A General-Purpose Multithreaded Parallel/Distributed Simulation Platform
x86.h
Go to the documentation of this file.
1 
31 #pragma once
32 
33 #include <stdbool.h>
34 
35 #include "instruction.h"
36 
37 #define A32(f) ((f) & ADDR_32) // Indirizzi a 32 bit?
38 #define D32(f) ((f) & DATA_32) // Dati a 32 bit?
39 #define A64(f) ((f) & ADDR_64) // Indirizzi a 64 bit?
40 #define D64(f) ((f) & DATA_64) // Dati a 64 bit?
41 
42 /* Test sui prefissi */
43 #define p_is_group1(p) (((p) == 0xf0) /* lock */ \
44  || ((p) == 0xf2) /* repne/repnz */ \
45  || ((p) == 0xf3)) /* rep/repe/repz */
46 
47 #define p_is_group2(p) (((p) == 0x2e) /* CS override/branch not taken */ \
48  || ((p) == 0x36) /* SS override */ \
49  || ((p) == 0x3e) /* DS override/branch taken */ \
50  || ((p) == 0x26) /* ES override */ \
51  || ((p) == 0x64) /* FS override */ \
52  || ((p) == 0x65)) /* GS override */
53 
54 #define p_is_group3(p) ((p) == 0x66) /* opsize override */
55 
56 #define p_is_group4(p) ((p) == 0x67) /* addr size override */
57 
58 #define is_prefix(o) (p_is_group1 (o) || p_is_group2 (o) \
59  || p_is_group3 (o) || p_is_group4 (o))
60 
61 #define is_sse_prefix(o) (((o) == 0xf2) || ((o) == 0xf3) || ((o) == 0x66))
62 
63 #define is_rex_prefix(r, mode64) (((r) >= 0x40 && (r) <= 0x4f ) && (mode64))
64 
65 /* Recuperano i bit di interesse del byte REX (i primi 4 bit sono fissi e valgono 0100b) */
66 
67 #define REXW(r) (((r) & 0x08) >> 3)
68 #define REXR(r) (((r) & 0x04) >> 2)
69 #define REXX(r) (((r) & 0x02) >> 1)
70 #define REXB(r) (((r) & 0x01))
71 
72 /* Test per le operazioni Jcc */
73 
74 // opcode nell'intervallo 70-7f,e3
75 #define is_jcc_insn(o) (((o) == 0xe3) || (((o) >= 0x70) && ((o) <= 0x7f)))
76 
77 // opcode nell'intervallo 80-8f (quando il primo byte è 0f)
78 #define is_esc_jcc_insn(o) (((o) >= 0x80) && ((o) <= 0x8f))
79 
80 // Gli operandi dell'istruzione specificano se c'è o meno un byte ModR/M
81 #define has_modrm(addr) (((addr) == ADDR_C) \
82  || ((addr) == ADDR_D) \
83  || ((addr) == ADDR_E) \
84  || ((addr) == ADDR_G) \
85  || ((addr) == ADDR_M) \
86  || ((addr) == ADDR_P) \
87  || ((addr) == ADDR_Q) \
88  || ((addr) == ADDR_R) \
89  || ((addr) == ADDR_S) \
90  || ((addr) == ADDR_T) \
91  || ((addr) == ADDR_V) \
92  || ((addr) == ADDR_W))
93 
94 // È presente un byte SIB se il campo Mod non è 11b, il campo R/M è
95 // 100b e la modalità di indirizzamento è a 32 bit o 64 bit
96 #define has_sib(modrm, addr) ((((modrm) & 0x07) == 0x04) \
97  && (((addr) == SIZE_32) || (addr) == SIZE_64) \
98  && (((modrm) & 0xC0) != 0xC0))
99 
100 // Se il campo Mod è 01b, allora c'è uno spiazzamento di 1 byte. Se il campo
101 // Mod è 10b, e siamo in modalità di indirizzamento a 32/64 bit, allora c'è
102 // uno spiazzamento di 4 byte. Inoltre, se la modalità di indirizzamento è
103 // a 16 bit e il campo Mod è 10b, allora c'è uno spiazzamento di 2 byte.
104 // Se la modalità di indirizzamento è a 32 o 64 bit e sia il campo Mod è 00b sia
105 // il campo R/M è 101b, o il campo Mod è 10b, allora c'è uno spiazzamento
106 // di 4 byte. Altrimenti non c'è spiazzamento.
107 #define disp_size(modrm, addr) ((((modrm) & 0xC0) == 0x40) ? 1 \
108  : ((((addr) == SIZE_16) \
109  && ((((modrm) & 0xC7) == 0x06) \
110  || (((modrm) & 0xC0) == 0x80))) ? 2 \
111  : (((((addr) == SIZE_32) || (addr) == SIZE_64) \
112  && ((((modrm) & 0xC7) == 0x05) \
113  || (((modrm) & 0xC0) == 0x80))) ? 4\
114  : 0)))
115 
116 enum addr_method {
117  ADDR_0, /* Nessun metodo di indirizzamento */
118  ADDR_A, /* Indirizzamento diretto, nessun byte ModR/M */
119  ADDR_C, /* Il campo reg del byte ModR/M seleziona un registro di controllo */
120  ADDR_D, /* Il campo reg del byte ModR/M seleziona un registro di debug */
121  ADDR_E, /* Il byte ModR/M specifica l'operando: o un registro general purpose
122  o un offset per un indirizzo di memoria da un segment register
123  con un registro base, un registro d'indice, un fattore di scala
124  o spiazzamento */
125  ADDR_F, /* registro EFLAGS */
126  ADDR_G, /* Il campo reg del byte ModR/M seleziona un registro generale */
127  ADDR_I, /* Dati immediati */
128  ADDR_J, /* L'istruzione contiene un offset relativo, da (E)IP */
129  ADDR_M, /* Il byte ModR/M può riferirsi solo a memoria */
130  ADDR_N, /* [FV] Il campo R/M del byte ModR/M indica un registro MMX */
131  ADDR_O, /* Nessun byte ModR/M. L'op è codificata come word o dword o qword in 64bit */
132  ADDR_P, /* Il campo reg del byte ModR/M seleziona un registro packed qword MMX */
133  ADDR_Q, /* Il byte ModR/M specifica o un registro MMX o un indirizzo in memoria (scala, ecc...) */
134  ADDR_R, /* Il campo reg del byte ModR/M si può riferire solo a un registro generale */
135  ADDR_S, /* Il campo reg del byte ModR/M seleziona un segment register */
136  ADDR_T, /* Il campo reg del byte ModR/M seleziona un registro di test */
137  ADDR_U, // Alice: Il campo R/M del byte ModR/M seleziona un registro XMM
138  ADDR_V, /* Il campo reg del byte ModR/M seleziona un registro MMX */
139  ADDR_W, /* Il byte ModR/M seleziona un registro XMM o un indirizzo in memoria (scala, ecc...) */
140  ADDR_X, /* Indirizzo di memoria da DS:SI */
141  ADDR_Y, /* Indirizzo di memoria da ES:DI */
142 
143  /* Registri */
144  R_START,
145 
146  R_AL,
147  R_AH,
148  R_AX,
149  R_EAX,
150  R_RAX,
151 
152  R_BL,
153  R_BH,
154  R_BX,
155  R_EBX,
156  R_RBX,
157 
158  R_CL,
159  R_CH,
160  R_CX,
161  R_ECX,
162  R_RCX,
163 
164  R_DL,
165  R_DH,
166  R_DX,
167  R_EDX,
168  R_RDX,
169 
170  R_SIL,
171  R_SI,
172  R_ESI,
173  R_RSI,
174  R_DIL,
175  R_DI,
176  R_EDI,
177  R_RDI,
178  R_BP,
179  R_EBP,
180  R_SPL,
181  R_SP,
182  R_ESP,
183  R_RSP,
184 
185  /* segment registers */
186  R_CS,
187  R_DS,
188  R_SS,
189  R_ES,
190  R_FS,
191  R_GS,
192 
193  /* EFLAGS */
194  R_F,
195  R_EF,
196 
197  /* EIP */
198  R_IP,
199  R_EIP,
200  R_RIP,
201 
202  /* floating point registers */
203  R_ST0,
204  R_ST1,
205  R_ST2,
206  R_ST3,
207  R_ST4,
208  R_ST5,
209  R_ST6,
210  R_ST7,
211 
212  /* Extra registers in 64bit mode */
213  R_R8L,
214  R_R8W,
215  R_R8D,
216  R_R8,
217 
218  R_R9L,
219  R_R9W,
220  R_R9D,
221  R_R9,
222 
223  R_R10L,
224  R_R10W,
225  R_R10D,
226  R_R10,
227 
228  R_R11L,
229  R_R11W,
230  R_R11D,
231  R_R11,
232 
233  R_R12L,
234  R_R12W,
235  R_R12D,
236  R_R12,
237 
238  R_R13L,
239  R_R13W,
240  R_R13D,
241  R_R13,
242 
243  R_R14L,
244  R_R14W,
245  R_R14D,
246  R_R14,
247 
248  R_R15L,
249  R_R15W,
250  R_R15D,
251  R_R15,
252 
253  /* MMX registers */
254  R_MM0,
255  R_MM1,
256  R_MM2,
257  R_MM3,
258  R_MM4,
259  R_MM5,
260  R_MM6,
261  R_MM7,
262 
263  /* SSE/SSE2 registers */
264  R_XMM0,
265  R_XMM1,
266  R_XMM2,
267  R_XMM3,
268  R_XMM4,
269  R_XMM5,
270  R_XMM6,
271  R_XMM7,
272  R_XMM8,
273  R_XMM9,
274  R_XMM10,
275  R_XMM11,
276  R_XMM12,
277  R_XMM13,
278  R_XMM14,
279  R_XMM15,
280 
281  R_END,
282 
283  /* Valore immediato interno all'istruzione (D0, D1) */
284  IMMED_1, /* il valore 1 */
285 };
286 
287 enum operand_type {
288  OP_0, /* nessun tipo */
289  OP_A, /* due oper da 1 word o 2 operandi dword in mem (dipende dall'attr opsize) */
290  OP_B, /* byte, indifferentemente dall'attrib opsize */
291  OP_C, /* byte o word, a seconda dell'attrib opsize */
292  OP_D, /* dword, indifferentemente dall'attributo opsize */
293  OP_DQ, /* dqword, indifferentemebre dall'attr opsize */
294  OP_P, /* puntatore di 32 o 48 bit a seconda dell'attributo opsize */
295  OP_PI, /* Registro MMX qword */
296  OP_PS, /* 128 bit packed single float [FV] o 256 bit */
297  OP_Q, /* qword, indifferentemente dall'att opsize */
298  OP_S, /* 6 byte pseudo-descriptor */
299  OP_SS, /* Elemento scalare di un packed single float a 128 bit */
300  OP_SI, /* registro dword (es: eax) */
301  OP_V, /* word o dword, a seconda dell'attributo opsize */
302  OP_W, /* word, indifferentemente dall'attributo opsize */
303  OP_PD, /* registri dqword o xmm [FV] 128 bit o 256 bit packed double-precision float */
304  OP_SD, /* registri qword o xmm */
305  OP_E, /* usato quando i registri sono codificati direttamente */
306  OP_Y, /* [FV] doubleword o quadword (in modalita' 64 bit), a seconda dell'attributo operand-size */
307  OP_FS, /* [FV] 14 o 24 byte in memoria, a seconda di operand-size (usato da istruzioni load/store FPU state) */
308  OP_FSR, /* [FV] 94 o 108 byte in memoria, a seconda di operand-size (usato da istruzioni FRSTOR/FSAVE FPU
309  * state piu' 80 bit registri FPU) */
310  OP_M80, /* 80 bit in memoria */
311  OP_M512byte /* 512 byte in memoria */
312 };
313 
314 enum op_size {
315  SIZE_8, //Alice
316  SIZE_16,
317  SIZE_32,
318  SIZE_64
319 };
320 
321 /* dimensione operando / indirizzo */
322 enum reg_size {
323  REG_SIZE_8, REG_SIZE_16, REG_SIZE_32, REG_SIZE_64, REG_SIZE_128
324 };
325 
326 // Per tenere traccia dello stato dell'interpretazione
327 struct disassembly_state {
328  enum op_size opd_size; // Dimensione dell'operando corrente
329  enum op_size addr_size; // Dimensione dell'indirizzo corrente
330  unsigned char *text; // Sezione testo corrente (su cui si opera)
331  unsigned long pos; // Posizione corrente nel testo
332  unsigned char rex; // Il byte REX, o 0x00
333  bool mode64; // Stiamo eseguendo a 32 o a 64 bit?
334  unsigned char opcode[2]; // Opcode corrente
335  unsigned char modrm; // Byte ModR/M o 0x00
336  bool read_modrm; // Indica se il byte ModR/M è stato letto
337  unsigned char sib; // Byte SIB o 0x00
338  unsigned long disp_offset; // L'inizio del displacement o 0
339  int disp_size; // Dimensione in byte del displacement
340  unsigned long immed_offset; // L'inizio dei dati immediati o 0
341  int immed_size; // La dimensione dei dati immediati
342  enum addr_method addr[3]; // Codice per il metodo di indirizzamento
343  enum operand_type op[3]; // Codice per il tipo di operando
344  unsigned char prefix[4]; // Prefissi all'istruzione o 0x00
345  unsigned char sse_prefix; // Terzo byte dell'istruzione SSE/SSE2
346  unsigned long orig_pos; // Posizione iniziale nel testo
347  bool read_dest; // Indica se è stata analizzata la destinazione
348 
349  // [FV] Flag indicante se l'istruzione usa un indirizzamento RIP_Relative o meno
350  bool uses_rip;
351 
352  insn_info_x86 *instrument; // Struttura dati per gestire l'instrumentazione
353 };
354 
355 struct _insn {
356  char *instruction; // Nome dell'istruzione (es: "mov")
357  enum addr_method addr_method[3]; // Metodo di indirizzamento (Appendice A di IA-32 SDM)
358  enum operand_type operand_type[3]; // Tipo corrispondete (sempre dall'appendice A)
359  void (*esc_function)(struct disassembly_state *); // Gestore dei byte addizionali dell'opcode
360  unsigned long flags; // Flag contenente info utili sull'istruzione (così come definiti in "instruction.h")
361 };
362 
363 typedef struct _insn insn, *insn_table;
364 
365 extern void x86_disassemble_instruction(unsigned char *text, unsigned long *pos, insn_info_x86 * instrument, char flags);