OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (c) 2012 The Native Client Authors. All rights reserved. | |
3 * Use of this source code is governed by a BSD-style license that can be | |
4 * found in the LICENSE file. | |
5 */ | |
6 | |
7 #include <fcntl.h> | |
8 #include <getopt.h> | |
9 #include <libgen.h> | |
10 #include <libintl.h> | |
11 #include <locale.h> | |
12 #include <stdio.h> | |
13 #include <stdlib.h> | |
14 #include <string.h> | |
15 | |
16 #include <algorithm> | |
17 #include <map> | |
18 #include <set> | |
19 #include <string> | |
20 #include <tuple> | |
21 #include <vector> | |
22 | |
23 template <typename T, size_t N> | |
24 char (&ArraySizeHelper(T (&array)[N]))[N]; | |
25 #define arraysize(array) (sizeof(ArraySizeHelper(array))) | |
26 | |
27 char* _(const char *s) { return gettext(s); } | |
28 const char* N_(const char *s) { return s; } | |
29 | |
30 namespace { | |
31 const char* short_program_name; | |
32 | |
33 const struct option kProgramOptions[] = { | |
34 {"mode", required_argument, NULL, 'm'}, | |
35 {"disable", required_argument, NULL, 'd'}, | |
36 {"output", required_argument, NULL, 'o'}, | |
37 {"help", no_argument, NULL, 'h'}, | |
38 {"version", no_argument, NULL, 'v'}, | |
39 {NULL, 0, NULL, 0} | |
40 }; | |
41 | |
42 const char kVersion[] = "0.0"; | |
43 | |
44 const char*const kProgramHelp = N_("Usage: %1$s [OPTION]… FILES…\n" | |
45 "\n" | |
46 "Creates ragel machine which recognizes instructions listed in given files.\n" | |
47 "\n" | |
48 "Mandatory arguments to long options are mandatory for short options too.\n" | |
49 "\n" | |
50 "Options list:\n" | |
51 " -m, --mode=mode CPU mode: ia32 for IA32, amd64 for x86-64\n" | |
52 " -d, --disable=action_list disable actions from the comma-separated list\n" | |
53 " -o, --output=FILE write result to FILE instead of standard output\n" | |
54 " -h, --help display this help and exit\n" | |
55 " -v, --version output version information and exit\n" | |
56 "\n" | |
57 "Here is the full list of possible action types with short descrion of places\n" | |
58 "where they are insered:\n" | |
59 " rex_prefix triggered when legacy REX prefix is parsed\n" | |
60 " @rex_prefix inserted after possible REX prefix\n" | |
61 " vex_prefix triggered when VEX-encoded action is detected\n" | |
62 " @vex_prefix2 inserted after second byte of three-byte VEX/XOP prefi
x\n" | |
63 " @vex_prefix3 inserted after third byte of three-byte VEX/XOP prefix
\n" | |
64 " @vex_prefix_short inserted after second byte of two-byte VEX prefix\n" | |
65 " Note: there are no “vex_prefix1” because first byte of\n
" | |
66 " VEX/XOP encoding is multiplexed to “lds”, “les” or\n" | |
67 " “pop Eq” instruction\n" | |
68 " instruction_name triggered when we have processed enough bytes to know th
e\n" | |
69 " name of instruction\n" | |
70 " @instruction_NAME inserted when NAME is known.\n" | |
71 " Note: if this action is enabled then a set of actions\n" | |
72 " will be generated, not just a single call of single\n" | |
73 " action\n" | |
74 " opcode this will generate opcode actions\n" | |
75 " >opcode_begin inserted where actual opcode is started (without any\n
" | |
76 " possible prefixes)\n" | |
77 " @opcode_end inserted where actual opcode is parsed\n" | |
78 " Note: some instructions use dedicated prefixes (0x66,\n" | |
79 " 0xf2, 0xf3) or immediate byte (“cmpeqpd”, “pf2id”,\n" | |
80 " etc) to distinguish operands—these are not captured\n" | |
81 " between “>opcode_begin” and “@opcode_end”\n" | |
82 " parse_operands this will grab instruction operands\n" | |
83 " mark_data_fields this will make “data fields” (dispXX, immXX, relXX) with
\n" | |
84 " xxxXX_operand_begin and xxxXX_operand_end\n" | |
85 " check_access this will check memory access (actions is not generated\
n" | |
86 " by %1$s, you need to define it in your program)\n" | |
87 "\n" | |
88 " imm_operand_action generate imm_operand action references, but not actions\
n" | |
89 " themselves - in you need non-standard definition\n" | |
90 "\n" | |
91 " rel_operand_action generate rel_operand action references, but not actions\
n" | |
92 " themselves - in you need non-standard definition\n" | |
93 "\n" | |
94 " nacl-forbidden don't generate instructions forbidden for nacl\n"); | |
95 | |
96 const char*const kVersionHelp = N_("%1$s %2$s\n" | |
97 "Copyright (c) 2012 The Native Client Authors. All rights reserved.\n" | |
98 "Use of this source code is governed by a BSD-style license that can be\n" | |
99 "found in the LICENSE file.\n" | |
100 ""); | |
101 | |
102 enum class Actions { | |
103 kRexPrefix, | |
104 kVexPrefix, | |
105 kInstructionName, | |
106 kOpcode, | |
107 kParseOperands, | |
108 kParseOperandsStates, | |
109 kMarkDataFields, | |
110 kCheckAccess, | |
111 kImmOperandAction, | |
112 kRelOperandAction, | |
113 kNaClForbidden | |
114 }; | |
115 const char* kDisablableActionsList[] = { | |
116 "rex_prefix", | |
117 "vex_prefix", | |
118 "instruction_name", | |
119 "opcode", | |
120 "parse_operands", | |
121 "parse_operands_states", | |
122 "mark_data_fields", | |
123 "check_access", | |
124 "imm_operand_action", | |
125 "rel_operand_action", | |
126 "nacl-forbidden" | |
127 }; | |
128 bool disabled_actions[arraysize(kDisablableActionsList)]; | |
129 | |
130 bool enabled(Actions action) { | |
131 return !disabled_actions[static_cast<int>(action)]; | |
132 } | |
133 | |
134 std::map<std::string, size_t> instruction_names; | |
135 struct Instruction { | |
136 std::string name; | |
137 struct Operand { | |
138 char source; | |
139 std::string size; | |
140 bool read; | |
141 bool write; | |
142 bool implicit; | |
143 }; | |
144 std::vector<Operand> operands; | |
145 std::vector<std::string> opcodes; | |
146 #if 0 | |
147 /* We need GCC 4.7 for the following */ | |
148 #define INSTRUCTION_FLAG(x) bool x :1 = false; | |
149 #else | |
150 /* Use this and “Instruction instruction { }”… */ | |
151 #define INSTRUCTION_FLAG(x) bool x :1; | |
152 #endif | |
153 #include "gen-decoder-flags.C" | |
154 #undef INSTRUCTION_FLAG | |
155 }; | |
156 std::vector<Instruction> instructions; | |
157 | |
158 FILE *out_file = stdout; | |
159 FILE *const_file = stdout; | |
160 char *out_file_name = NULL; | |
161 | |
162 auto ia32_mode = true; | |
163 | |
164 std::string read_file(const char *filename) { | |
165 std::string file_content; | |
166 auto file = open(filename, O_RDONLY); | |
167 char buf[1024]; | |
168 ssize_t count; | |
169 | |
170 if (file == -1) { | |
171 fprintf(stderr, _("%s: can not open “%s” file (%s)\n"), | |
172 short_program_name, filename, strerror(errno)); | |
173 exit(1); | |
174 } | |
175 while ((count = read(file, buf, sizeof(buf))) > 0) { | |
176 for (auto it = buf; it < buf + count ; ++it) { | |
177 if (*it != '\r') { | |
178 file_content.push_back(*it); | |
179 } else { | |
180 file_content.push_back('\n'); | |
181 } | |
182 } | |
183 } | |
184 if (count == -1) { | |
185 fprintf(stderr, _("%s: can not read “%s” file (%s)\n"), | |
186 short_program_name, filename, strerror(errno)); | |
187 exit(1); | |
188 } | |
189 if (close(file)) { | |
190 fprintf(stderr, _("%s: can not close “%s” file (%s)\n"), | |
191 short_program_name, filename, strerror(errno)); | |
192 exit(1); | |
193 } | |
194 return file_content; | |
195 } | |
196 | |
197 bool eol(char c) { | |
198 return c == '\n'; | |
199 } | |
200 | |
201 bool right_parenthesis(char c) { | |
202 return c == ')'; | |
203 } | |
204 | |
205 bool whitespace(char c) { | |
206 return c == ' ' || c == '\t'; | |
207 } | |
208 | |
209 std::vector<std::string> get_strings(std::string::const_iterator &it, | |
210 std::string::const_iterator end) { | |
211 std::vector<std::string> strings; | |
212 std::string string; | |
213 while ((it = std::find_if_not(it, end, whitespace)) < end && *it != ',') { | |
214 for (; it < end && *it != ',' && !whitespace(*it); ++it) { | |
215 if (*it != '\\') { | |
216 string.push_back(*it); | |
217 } else { | |
218 if (*++it == '(') { | |
219 auto parenthesis = std::find_if(it, end, right_parenthesis); | |
220 string.insert(string.end(), it, ++parenthesis); | |
221 it = --parenthesis; | |
222 } else { | |
223 string.push_back(*it); | |
224 } | |
225 } | |
226 } | |
227 strings.push_back(string); | |
228 string.clear(); | |
229 } | |
230 return strings; | |
231 } | |
232 | |
233 struct extract_operand { | |
234 Instruction &instruction; | |
235 std::vector<std::string> &operation; | |
236 | |
237 extract_operand(Instruction &i, std::vector<std::string> &o) | |
238 : instruction(i), operation(o) { | |
239 } | |
240 | |
241 void operator()(std::string &str) { | |
242 Instruction::Operand operand; | |
243 switch (str[0]) { | |
244 case '\'': | |
245 operand = {str[1], str.substr(2), false, false, false}; | |
246 break; | |
247 case '=': | |
248 operand = {str[1], str.substr(2), true, false, false}; | |
249 break; | |
250 case '!': | |
251 operand = {str[1], str.substr(2), false, true, false}; | |
252 break; | |
253 case '&': | |
254 operand = {str[1], str.substr(2), true, true, false}; | |
255 break; | |
256 default: | |
257 if (&str == &*operation.rbegin()) { | |
258 if (operation.size() <= 3) { | |
259 operand = {str[0], str.substr(1), true, true, false}; | |
260 } else { | |
261 operand = {str[0], str.substr(1), false, true, false}; | |
262 } | |
263 } else { | |
264 operand = {str[0], str.substr(1), true, false, false}; | |
265 } | |
266 } | |
267 if (*(operand.size.rbegin()) == '*') { | |
268 operand.size.resize(operand.size.length() - 1); | |
269 } | |
270 instruction.operands.push_back(operand); | |
271 } | |
272 }; | |
273 | |
274 void load_instructions(const char *filename) { | |
275 const auto file_content = read_file(filename); | |
276 auto it = file_content.begin(); | |
277 while (it != file_content.end()) { | |
278 it = std::find_if_not(it, file_content.end(), eol); | |
279 if (it == file_content.end()) { | |
280 return; | |
281 } | |
282 /* If line starts with “#” then it's a comment. */ | |
283 if (*it == '#') { | |
284 it = std::find_if(it, file_content.end(), eol); | |
285 } else { | |
286 auto end = std::find_if(it, file_content.end(), eol); | |
287 /* Note: initialization list makes sure flags are toggled to zero. */ | |
288 Instruction instruction { }; | |
289 auto operation = get_strings(it, end); | |
290 /* Line with just a whitespaces is ignored. */ | |
291 if (operation.size() != 0) { | |
292 instruction_names[instruction.name = operation[0]] = 0; | |
293 for_each(operation.rbegin(), operation.rend() - 1, | |
294 extract_operand(instruction, operation)); | |
295 auto enabled_instruction = true; | |
296 if (*it == ',') { | |
297 ++it; | |
298 instruction.opcodes = get_strings(it, end); | |
299 if (*it == ',') { | |
300 ++it; | |
301 auto flags = get_strings(it, end); | |
302 for (auto flag_it = flags.begin(); flag_it != flags.end(); ++flag_
it) { | |
303 auto &flag = *flag_it; | |
304 #define INSTRUCTION_FLAG(x) \ | |
305 if (flag == #x) {instruction.x = true;} else | |
306 #include "gen-decoder-flags.C" | |
307 #undef INSTRUCTION_FLAG | |
308 if (flag == "ia32") { | |
309 if (!ia32_mode) { | |
310 enabled_instruction = false; | |
311 break; | |
312 } | |
313 } else if (flag == "amd64") { | |
314 if (ia32_mode) { | |
315 enabled_instruction = false; | |
316 break; | |
317 } | |
318 } else if (flag == "nacl-ia32-forbidden") { | |
319 if (ia32_mode && !enabled(Actions::kNaClForbidden)) { | |
320 enabled_instruction = false; | |
321 break; | |
322 } | |
323 } else if (flag == "nacl-amd64-forbidden") { | |
324 if (!ia32_mode && !enabled(Actions::kNaClForbidden)) { | |
325 enabled_instruction = false; | |
326 break; | |
327 } | |
328 } else if (flag == "nacl-forbidden") { | |
329 if (!enabled(Actions::kNaClForbidden)) { | |
330 enabled_instruction = false; | |
331 break; | |
332 } | |
333 } else { | |
334 fprintf(stderr, _("%s: unknown flag: “%s”\n"), | |
335 short_program_name, flag.c_str()); | |
336 exit(1); | |
337 } | |
338 } | |
339 } | |
340 } | |
341 if (enabled_instruction) { | |
342 instructions.push_back(instruction); | |
343 } | |
344 } | |
345 it = std::find_if(it, file_content.end(), eol); | |
346 } | |
347 } | |
348 } | |
349 | |
350 #if (__GNUC__ >= 4) && (__GNUC_MINOR__ >= 6) | |
351 #define USE_LAMBDA_IN_CHARTEST 1 | |
352 #else | |
353 #define USE_LAMBDA_IN_CHARTEST 0 | |
354 #endif | |
355 #if USE_LAMBDA_IN_CHARTEST | |
356 template<typename func> | |
357 std::string chartest(func f) { | |
358 #else | |
359 std::string chartest(std::vector<bool> v) { | |
360 #endif | |
361 std::string result; | |
362 auto delimeter = "( "; | |
363 for (int c = 0x00; c <= 0xff; ++c) { | |
364 #if USE_LAMBDA_IN_CHARTEST | |
365 if (f(c)) { | |
366 #else | |
367 if (v[c]) { | |
368 #endif | |
369 char buf[10]; | |
370 sprintf(buf, "%s0x%02x", delimeter, c); | |
371 result += buf; | |
372 delimeter = " | "; | |
373 } | |
374 } | |
375 return result + " )"; | |
376 } | |
377 #if USE_LAMBDA_IN_CHARTEST | |
378 #define chartest(x) (chartest([=](int c) { return x; }).c_str()) | |
379 #else | |
380 struct comparator { | |
381 const std::vector<bool> &v; | |
382 const int n; | |
383 comparator(const std::vector<bool> &v_, const int n_) : v(v_), n(n_) { } | |
384 #define operator(x) \ | |
385 const std::vector<bool> operator x (int m) { \ | |
386 std::vector<bool> r(256, false); \ | |
387 for (int c = 0x00; c <= 0xff; ++c) { \ | |
388 if (v[c]) { \ | |
389 r[c] = (c & n) x m; \ | |
390 } \ | |
391 } \ | |
392 return r; \ | |
393 } | |
394 operator(==) | |
395 operator(!=) | |
396 operator(<=) | |
397 operator(>=) | |
398 operator(<) | |
399 operator(>) | |
400 #undef operator | |
401 }; | |
402 comparator operator& (const std::vector<bool> &v, int n) { | |
403 return comparator(v, n); | |
404 } | |
405 #define operator(x) \ | |
406 const std::vector<bool> operator x (const std::vector<bool> &v1, \ | |
407 const std::vector<bool> &v2) { \ | |
408 std::vector<bool> r(256); \ | |
409 for (int c = 0x00; c <= 0xff; ++c) { \ | |
410 r[c] = (v1[c] x v2[c]); \ | |
411 } \ | |
412 return r; \ | |
413 } | |
414 operator(&&) | |
415 operator(||) | |
416 #undef operator | |
417 #define chartest(x) (chartest(x).c_str()) | |
418 std::vector<bool> c(256, true); | |
419 #endif | |
420 | |
421 const std::string& select_name(std::map<std::string, size_t>::value_type& p) { | |
422 return p.first; | |
423 } | |
424 | |
425 bool compare_names(const std::string& x, const std::string& y) { | |
426 return (x.size() > y.size()) || ((x.size() == y.size()) && x < y); | |
427 } | |
428 | |
429 void print_consts(void) { | |
430 if (enabled(Actions::kInstructionName)) { | |
431 std::vector<std::string> names; | |
432 std::transform(instruction_names.begin(), instruction_names.end(), | |
433 std::back_inserter(names), | |
434 select_name); | |
435 std::sort(names.begin(), names.end(), compare_names); | |
436 for (auto name_it = names.begin(); name_it != names.end(); ++name_it) { | |
437 auto &name = *name_it; | |
438 if (instruction_names[name] == 0) { | |
439 for (decltype(name.length()) p = 1; p < name.length(); ++p) { | |
440 auto it = instruction_names.find(std::string(name, p)); | |
441 if (it != instruction_names.end()) { | |
442 it->second = 1; | |
443 } | |
444 } | |
445 } | |
446 } | |
447 size_t offset = 0; | |
448 for (auto pair_it = instruction_names.begin(); pair_it != instruction_name
s.end(); ++pair_it) { | |
449 auto &pair = *pair_it; | |
450 if (pair.second != 1) { | |
451 pair.second = offset; | |
452 offset += pair.first.length() + 1; | |
453 } | |
454 } | |
455 for (auto name_it = names.begin(); name_it != names.end(); ++name_it) { | |
456 auto &name = *name_it; | |
457 auto offset = instruction_names[name]; | |
458 if (offset != 1) { | |
459 for (decltype(name.length()) p = 1; p < name.length(); ++p) { | |
460 auto it = instruction_names.find(std::string(name, p)); | |
461 if ((it != instruction_names.end()) && (it->second == 1)) { | |
462 it->second = offset + p; | |
463 } | |
464 } | |
465 } | |
466 } | |
467 offset = 0; | |
468 auto delimeter = "static const char instruction_names[] = {\n "; | |
469 for (auto pair_it = instruction_names.begin(); pair_it != instruction_name
s.end(); ++pair_it) { | |
470 auto &pair = *pair_it; | |
471 if (pair.second == offset) { | |
472 fprintf(const_file, "%s", delimeter); | |
473 for (auto c_it = pair.first.begin(); c_it != pair.first.end(); ++c_it)
{ | |
474 auto &c = *c_it; | |
475 fprintf(const_file, "0x%02x, ", static_cast<int>(c)); | |
476 } | |
477 fprintf(const_file, "\'\\0\', /* "); | |
478 fprintf(const_file, "%s", pair.first.c_str()); | |
479 offset += pair.first.length() + 1; | |
480 delimeter = " */\n "; | |
481 } | |
482 } | |
483 fprintf(const_file, " */\n};\n"); | |
484 } | |
485 if (enabled(Actions::kParseOperands)) { | |
486 fprintf(const_file, "static const uint8_t index_registers[] = {\n" | |
487 " REG_RAX, REG_RCX, REG_RDX, REG_RBX,\n" | |
488 " REG_RIZ, REG_RBP, REG_RSI, REG_RDI,\n" | |
489 " REG_R8, REG_R9, REG_R10, REG_R11,\n" | |
490 " REG_R12, REG_R13, REG_R14, REG_R15\n" | |
491 "};\n" | |
492 ""); | |
493 } | |
494 } | |
495 | |
496 std::string c_identifier(std::string text) { | |
497 std::string name; | |
498 for (auto c_it = text.begin(); c_it != text.end(); ++c_it) { | |
499 auto c = *c_it; | |
500 if (('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z') || | |
501 ('0' <= c && c <= '9')) { | |
502 name.push_back(c); | |
503 } else { | |
504 name.push_back('_'); | |
505 } | |
506 } | |
507 return name; | |
508 } | |
509 | |
510 void print_common_decoding(void) { | |
511 if (enabled(Actions::kRelOperandAction)) { | |
512 fprintf(out_file, " action rel8_operand {\n" | |
513 " operand0 = JMP_TO;\n" | |
514 " base = REG_RIP;\n" | |
515 " index = REG_NONE;\n" | |
516 " scale = 0;\n" | |
517 " disp_type = DISP8;\n" | |
518 " disp = p;\n" | |
519 " }\n" | |
520 " action rel16_operand {\n" | |
521 " operand0 = JMP_TO;\n" | |
522 " base = REG_RIP;\n" | |
523 " index = REG_NONE;\n" | |
524 " scale = 0;\n" | |
525 " disp_type = DISP16;\n" | |
526 " disp = p - 1;\n" | |
527 " }\n" | |
528 " action rel32_operand {\n" | |
529 " operand0 = JMP_TO;\n" | |
530 " base = REG_RIP;\n" | |
531 " index = REG_NONE;\n" | |
532 " scale = 0;\n" | |
533 " disp_type = DISP32;\n" | |
534 " disp = p - 3;\n" | |
535 " }\n" | |
536 ""); | |
537 } | |
538 fprintf(out_file, " action branch_not_taken {\n" | |
539 " branch_taken = TRUE;\n" | |
540 " }\n" | |
541 " action branch_taken {\n" | |
542 " branch_taken = TRUE;\n" | |
543 " }\n" | |
544 " action data16_prefix {\n" | |
545 " data16_prefix = TRUE;\n" | |
546 " }\n" | |
547 " action lock_prefix {\n" | |
548 " lock_prefix = TRUE;\n" | |
549 " }\n" | |
550 " action rep_prefix {\n" | |
551 " repz_prefix = TRUE;\n" | |
552 " }\n" | |
553 " action repz_prefix {\n" | |
554 " repz_prefix = TRUE;\n" | |
555 " }\n" | |
556 " action repnz_prefix {\n" | |
557 " repnz_prefix = TRUE;\n" | |
558 " }\n" | |
559 " action not_data16_prefix {\n" | |
560 " data16_prefix = FALSE;\n" | |
561 " }\n" | |
562 " action not_lock_prefix0 {\n" | |
563 " operand0 |= 0x08;\n" | |
564 " lock_prefix = FALSE;\n" | |
565 " }\n" | |
566 " action not_lock_prefix1 {\n" | |
567 " operand1 |= 0x08;\n" | |
568 " lock_prefix = FALSE;\n" | |
569 " }\n" | |
570 " action not_repnz_prefix {\n" | |
571 " repnz_prefix = FALSE;\n" | |
572 " }\n" | |
573 " action not_repz_prefix {\n" | |
574 " repz_prefix = FALSE;\n" | |
575 " }\n" | |
576 " action disp8_operand {\n" | |
577 " disp_type = DISP8;\n" | |
578 " disp = p;\n" | |
579 " }\n" | |
580 " action disp32_operand {\n" | |
581 " disp_type = DISP32;\n" | |
582 " disp = p - 3;\n" | |
583 " }\n" | |
584 " action disp64_operand {\n" | |
585 " disp_type = DISP64;\n" | |
586 " disp = p - 7;\n" | |
587 " }\n"); | |
588 if (enabled(Actions::kImmOperandAction)) { | |
589 fprintf(out_file, " action imm2_operand {\n" | |
590 " imm_operand = IMM2;\n" | |
591 " imm = p;\n" | |
592 " }\n" | |
593 " action imm8_operand {\n" | |
594 " imm_operand = IMM8;\n" | |
595 " imm = p;\n" | |
596 " }\n" | |
597 " action imm8_second_operand {\n" | |
598 " imm2_operand = IMM8;\n" | |
599 " imm2 = p;\n" | |
600 " }\n" | |
601 " action imm16_operand {\n" | |
602 " imm_operand = IMM16;\n" | |
603 " imm = p - 1;\n" | |
604 " }\n" | |
605 " action imm16_second_operand {\n" | |
606 " imm2_operand = IMM16;\n" | |
607 " imm2 = p - 1;\n" | |
608 " }\n" | |
609 " action imm32_operand {\n" | |
610 " imm_operand = IMM32;\n" | |
611 " imm = p - 3;\n" | |
612 " }\n" | |
613 " action imm32_second_operand {\n" | |
614 " imm2_operand = IMM32;\n" | |
615 " imm2 = p - 3;\n" | |
616 " }\n" | |
617 " action imm64_operand {\n" | |
618 " imm_operand = IMM64;\n" | |
619 " imm = p - 7;\n" | |
620 " }\n" | |
621 " action imm64_second_operand {\n" | |
622 " imm2_operand = IMM64;\n" | |
623 " imm2 = p - 7;\n" | |
624 " }\n" | |
625 ""); | |
626 } | |
627 if (enabled(Actions::kParseOperands)) { | |
628 if (ia32_mode) { | |
629 fprintf(out_file, " action modrm_only_base {\n" | |
630 " disp_type = DISPNONE;\n" | |
631 " index = REG_NONE;\n" | |
632 " base = (*p) & 0x07;\n" | |
633 " scale = 0;\n" | |
634 " }\n" | |
635 " action modrm_base_disp {\n" | |
636 " index = REG_NONE;\n" | |
637 " base = (*p) & 0x07;\n" | |
638 " scale = 0;\n" | |
639 " }\n" | |
640 " action modrm_pure_disp {\n" | |
641 " base = REG_NONE;\n" | |
642 " index = REG_NONE;\n" | |
643 " scale = 0;\n" | |
644 " }\n" | |
645 " action modrm_pure_index {\n" | |
646 " disp_type = DISPNONE;\n" | |
647 " base = REG_NONE;\n" | |
648 " index = index_registers[((*p) & 0x38) >> 3];\n" | |
649 " scale = ((*p) & 0xc0) >> 6;\n" | |
650 " }\n" | |
651 " action modrm_parse_sib {\n" | |
652 " disp_type = DISPNONE;\n" | |
653 " base = (*p) & 0x7;\n" | |
654 " index = index_registers[((*p) & 0x38) >> 3];\n" | |
655 " scale = ((*p) & 0xc0) >> 6;\n" | |
656 " }\n"); | |
657 } else { | |
658 fprintf(out_file, " action modrm_only_base {\n" | |
659 " disp_type = DISPNONE;\n" | |
660 " index = REG_NONE;\n" | |
661 " base = ((*p) & 0x07) |\n" | |
662 " ((rex_prefix & 0x01) << 3) |\n" | |
663 " (((~vex_prefix2) & 0x20) >> 2);\n" | |
664 " scale = 0;\n" | |
665 " }\n" | |
666 " action modrm_base_disp {\n" | |
667 " index = REG_NONE;\n" | |
668 " base = ((*p) & 0x07) |\n" | |
669 " ((rex_prefix & 0x01) << 3) |\n" | |
670 " (((~vex_prefix2) & 0x20) >> 2);\n" | |
671 " scale = 0;\n" | |
672 " }\n" | |
673 " action modrm_rip {\n" | |
674 " index = REG_NONE;\n" | |
675 " base = REG_RIP;\n" | |
676 " scale = 0;\n" | |
677 " }\n" | |
678 " action modrm_pure_index {\n" | |
679 " disp_type = DISPNONE;\n" | |
680 " base = REG_NONE;\n" | |
681 " index = index_registers[(((*p) & 0x38) >> 3) |\n" | |
682 " ((rex_prefix & 0x02) << 2) |\n" | |
683 " (((~vex_prefix2) & 0x40) >> 3)];\n" | |
684 " scale = ((*p) & 0xc0) >> 6;\n" | |
685 " }\n" | |
686 " action modrm_parse_sib {\n" | |
687 " disp_type = DISPNONE;\n" | |
688 " base = ((*p) & 0x7) |\n" | |
689 " ((rex_prefix & 0x01) << 3) |\n" | |
690 " (((~vex_prefix2) & 0x20) >> 2);\n" | |
691 " index = index_registers[(((*p) & 0x38) >> 3) |\n" | |
692 " ((rex_prefix & 0x02) << 2) |\n" | |
693 " (((~vex_prefix2) & 0x40) >> 3)];\n" | |
694 " scale = ((*p) & 0xc0) >> 6;\n" | |
695 " }\n" | |
696 ""); | |
697 } | |
698 } | |
699 fprintf(out_file, "\n" | |
700 " # Relative jumps and calls.\n" | |
701 " rel8 = any %s;\n" | |
702 " rel16 = any{2} %s;\n" | |
703 " rel32 = any{4} %s;\n" | |
704 "", enabled(Actions::kMarkDataFields) ? | |
705 ">rel8_operand_begin @rel8_operand_end" : "@rel8_operand", | |
706 enabled(Actions::kMarkDataFields) ? | |
707 ">rel16_operand_begin @rel16_operand_end" : "@rel16_operand", | |
708 enabled(Actions::kMarkDataFields) ? | |
709 ">rel32_operand_begin @rel32_operand_end" : "@rel32_operand"); | |
710 fprintf(out_file, "\n" | |
711 " # Displacements.\n" | |
712 " disp8 = any %s;\n" | |
713 " disp32 = any{4} %s;\n" | |
714 " disp64 = any{8} %s;\n" | |
715 "", enabled(Actions::kMarkDataFields) ? | |
716 ">disp8_operand_begin @disp8_operand_end" : "@disp8_operand", | |
717 enabled(Actions::kMarkDataFields) ? | |
718 ">disp32_operand_begin @disp32_operand_end" : "@disp32_operand", | |
719 enabled(Actions::kMarkDataFields) ? | |
720 ">disp64_operand_begin @disp64_operand_end" : "@disp64_operand"); | |
721 fprintf(out_file, "\n" | |
722 " # Immediates.\n" | |
723 " imm2 = %s @imm2_operand;\n" | |
724 "", ia32_mode ? chartest((c & 0x8c) == 0x00) : chartest((c & 0x0c) == 0x00)); | |
725 fprintf(out_file, " imm8 = any %s;\n" | |
726 " imm16 = any{2} %s;\n" | |
727 " imm32 = any{4} %s;\n" | |
728 " imm64 = any{8} %s;\n" | |
729 " imm8n2 = any %s;\n" | |
730 " imm16n2 = any{2} %s;\n" | |
731 " imm32n2 = any{4} %s;\n" | |
732 " imm64n2 = any{8} %s;\n" | |
733 "", enabled(Actions::kMarkDataFields) ? | |
734 ">imm8_operand_begin @imm8_operand_end" : "@imm8_operand", | |
735 enabled(Actions::kMarkDataFields) ? | |
736 ">imm8_operand_begin @imm16_operand_end" : "@imm16_operand", | |
737 enabled(Actions::kMarkDataFields) ? | |
738 ">imm8_operand_begin @imm32_operand_end" : "@imm32_operand", | |
739 enabled(Actions::kMarkDataFields) ? | |
740 ">imm8_operand_begin @imm64_operand_end" : "@imm64_operand", | |
741 enabled(Actions::kMarkDataFields) ? | |
742 ">imm8_operand_begin @imm8_operand_end" : "@imm8_second_operand", | |
743 enabled(Actions::kMarkDataFields) ? | |
744 ">imm16_operand_begin @imm16_operand_end" : "@imm16_second_operand", | |
745 enabled(Actions::kMarkDataFields) ? | |
746 ">imm32_operand_begin @imm32_operand_end" : "@imm32_second_operand", | |
747 enabled(Actions::kMarkDataFields) ? | |
748 ">imm64_operand_begin @imm64_operand_end" : "@imm64_second_operand"); | |
749 fprintf(out_file, "\n" | |
750 " # Different types of operands.\n" | |
751 " operand_sib_base_index = (%2$s . %3$s%1$s) |\n" | |
752 " (%4$s . any%1$s . disp8) |\n" | |
753 " (%5$s . any%1$s . disp32);\n" | |
754 "", enabled(Actions::kParseOperands) ? " @modrm_parse_sib" : "", | |
755 chartest((c & 0xC0) == 0 && (c & 0x07) == 0x04), | |
756 chartest((c & 0x07) != 0x05), | |
757 chartest((c & 0xC0) == 0x40 && (c & 0x07) == 0x04), | |
758 chartest((c & 0xC0) == 0x80 && (c & 0x07) == 0x04)); | |
759 fprintf(out_file, " operand_sib_pure_index = %2$s . %3$s%1$s . disp32;\n" | |
760 "", enabled(Actions::kParseOperands) ? " @modrm_pure_index" : "", | |
761 chartest((c & 0xC0) == 0 && (c & 0x07) == 0x04), | |
762 chartest((c & 0x07) == 0x05)); | |
763 fprintf(out_file, " operand_disp = (%2$s%1$s . disp8) |\n" | |
764 " (%3$s%1$s . disp32);\n" | |
765 "", enabled(Actions::kParseOperands) ? " @modrm_base_disp" : "", | |
766 chartest((c & 0xC0) == 0x40 && (c & 0x07) != 0x04), | |
767 chartest((c & 0xC0) == 0x80 && (c & 0x07) != 0x04)); | |
768 fprintf(out_file, " # It's pure disp32 in IA32 case, " | |
769 "but offset(%%rip) in x86-64 case.\n" | |
770 " operand_rip = %2$s%1$s . disp32;\n" | |
771 "", enabled(Actions::kParseOperands) ? | |
772 ia32_mode ? " @modrm_pure_disp" : " @modrm_rip" : "", | |
773 chartest((c & 0xC0) == 0 && (c & 0x07) == 0x05)); | |
774 fprintf(out_file, " single_register_memory = %2$s%1$s;\n" | |
775 "", enabled(Actions::kParseOperands) ? " @modrm_only_base" : "", | |
776 chartest((c & 0xC0) == 0 && (c & 0x07) != 0x04 && | |
777 (c & 0x07) != 0x05)); | |
778 fprintf(out_file, " modrm_memory = (operand_disp | operand_rip |\n" | |
779 " operand_sib_base_index | operand_sib_pure_index |\n" | |
780 " single_register_memory)%1$s;\n" | |
781 " modrm_registers = %2$s;\n" | |
782 "", enabled(Actions::kCheckAccess) ? " @check_access" : "", | |
783 chartest((c & 0xC0) == 0xC0)); | |
784 fprintf(out_file, "\n" | |
785 " # Operations selected using opcode in ModR/M.\n" | |
786 " opcode_0 = %s;\n" | |
787 " opcode_1 = %s;\n" | |
788 " opcode_2 = %s;\n" | |
789 " opcode_3 = %s;\n" | |
790 " opcode_4 = %s;\n" | |
791 " opcode_5 = %s;\n" | |
792 " opcode_6 = %s;\n" | |
793 " opcode_7 = %s;\n" | |
794 " # Used for segment operations: there only 6 segment registers.\n" | |
795 " opcode_s = %s;\n" | |
796 " # This is used to move operand name detection after first byte of ModRM.\n" | |
797 " opcode_m = any;\n" | |
798 " opcode_r = any;\n" | |
799 "", chartest((c & 0x38) == 0x00), | |
800 chartest((c & 0x38) == 0x08), | |
801 chartest((c & 0x38) == 0x10), | |
802 chartest((c & 0x38) == 0x18), | |
803 chartest((c & 0x38) == 0x20), | |
804 chartest((c & 0x38) == 0x28), | |
805 chartest((c & 0x38) == 0x30), | |
806 chartest((c & 0x38) == 0x38), | |
807 chartest((c & 0x38) < 0x30)); | |
808 fprintf(out_file, "\n" | |
809 " # Prefixes.\n" | |
810 " data16 = 0x66 @data16_prefix;\n" | |
811 " branch = 0x2e @branch_not_taken | 0x3e @branch_taken;\n" | |
812 " condrep = 0xf2 @repnz_prefix | 0xf3 @repz_prefix;\n" | |
813 " lock = 0xf0 @lock_prefix;\n" | |
814 " rep = 0xf3 @rep_prefix;\n" | |
815 " repnz = 0xf2 @repnz_prefix;\n" | |
816 " repz = 0xf3 @repz_prefix;\n" | |
817 ""); | |
818 if (enabled(Actions::kRexPrefix)) { | |
819 fprintf(out_file, "\n" | |
820 " # REX prefixes.\n" | |
821 " action rex_prefix {\n" | |
822 " rex_prefix = *p;\n" | |
823 " }\n" | |
824 ""); | |
825 } | |
826 fprintf(out_file, " REX_NONE = 0x40%1$s;\n" | |
827 " REX_W = %2$s%1$s;\n" | |
828 " REX_R = %3$s%1$s;\n" | |
829 " REX_X = %4$s%1$s;\n" | |
830 " REX_B = %5$s%1$s;\n" | |
831 " REX_WR = %6$s%1$s;\n" | |
832 " REX_WX = %7$s%1$s;\n" | |
833 " REX_WB = %8$s%1$s;\n" | |
834 " REX_RX = %9$s%1$s;\n" | |
835 " REX_RB = %10$s%1$s;\n" | |
836 " REX_XB = %11$s%1$s;\n" | |
837 " REX_WRX = %12$s%1$s;\n" | |
838 " REX_WRB = %13$s%1$s;\n" | |
839 " REX_WXB = %14$s%1$s;\n" | |
840 " REX_RXB = %15$s%1$s;\n" | |
841 " REX_WRXB = %16$s%1$s;\n" | |
842 "", enabled(Actions::kRexPrefix) ? " @rex_prefix" : "", | |
843 chartest((c & 0xf7) == 0x40), | |
844 chartest((c & 0xfb) == 0x40), | |
845 chartest((c & 0xfd) == 0x40), | |
846 chartest((c & 0xfe) == 0x40), | |
847 chartest((c & 0xf3) == 0x40), | |
848 chartest((c & 0xf5) == 0x40), | |
849 chartest((c & 0xf6) == 0x40), | |
850 chartest((c & 0xf9) == 0x40), | |
851 chartest((c & 0xfa) == 0x40), | |
852 chartest((c & 0xfc) == 0x40), | |
853 chartest((c & 0xf1) == 0x40), | |
854 chartest((c & 0xf2) == 0x40), | |
855 chartest((c & 0xf4) == 0x40), | |
856 chartest((c & 0xf8) == 0x40), | |
857 chartest((c & 0xf0) == 0x40)); | |
858 fprintf(out_file, "\n" | |
859 " rex_w = REX_W - REX_NONE;\n" | |
860 " rex_r = REX_R - REX_NONE;\n" | |
861 " rex_x = REX_X - REX_NONE;\n" | |
862 " rex_b = REX_B - REX_NONE;\n" | |
863 " rex_wr = REX_WR - REX_NONE;\n" | |
864 " rex_wx = REX_WX - REX_NONE;\n" | |
865 " rex_wb = REX_WB - REX_NONE;\n" | |
866 " rex_rx = REX_RX - REX_NONE;\n" | |
867 " rex_rb = REX_RB - REX_NONE;\n" | |
868 " rex_xb = REX_XB - REX_NONE;\n" | |
869 " rex_wrx = REX_WRX - REX_NONE;\n" | |
870 " rex_wrb = REX_WRB - REX_NONE;\n" | |
871 " rex_wxb = REX_WXB - REX_NONE;\n" | |
872 " rex_rxb = REX_RXB - REX_NONE;\n" | |
873 " rex_wrxb = REX_WRXB - REX_NONE;\n" | |
874 " REXW_NONE= 0x48%1$s;\n" | |
875 " REXW_R = %2$s%1$s;\n" | |
876 " REXW_X = %3$s%1$s;\n" | |
877 " REXW_B = %4$s%1$s;\n" | |
878 " REXW_RX = %5$s%1$s;\n" | |
879 " REXW_RB = %6$s%1$s;\n" | |
880 " REXW_XB = %7$s%1$s;\n" | |
881 " REXW_RXB = %8$s%1$s;\n" | |
882 "", enabled(Actions::kRexPrefix) ? " @rex_prefix" : "", | |
883 chartest((c & 0xfb) == 0x48), | |
884 chartest((c & 0xfd) == 0x48), | |
885 chartest((c & 0xfe) == 0x48), | |
886 chartest((c & 0xf9) == 0x48), | |
887 chartest((c & 0xfa) == 0x48), | |
888 chartest((c & 0xfc) == 0x48), | |
889 chartest((c & 0xf8) == 0x48)); | |
890 if (enabled(Actions::kVexPrefix)) { | |
891 if (ia32_mode) { | |
892 fprintf(out_file, "\n" | |
893 " # VEX/XOP prefix - byte 3.\n" | |
894 " action vex_prefix3 {\n" | |
895 " vex_prefix3 = *p;\n" | |
896 " }\n" | |
897 " # VEX/XOP short prefix\n" | |
898 " action vex_prefix_short {\n" | |
899 " /* VEX.R is not used in ia32 mode. */\n" | |
900 " vex_prefix3 = p[0] & 0x7f;\n" | |
901 " }\n" | |
902 ""); | |
903 } else { | |
904 fprintf(out_file, "\n" | |
905 " # VEX/XOP prefix - byte 2.\n" | |
906 " action vex_prefix2 {\n" | |
907 " vex_prefix2 = *p;\n" | |
908 " }\n" | |
909 " # VEX/XOP prefix - byte 3.\n" | |
910 " action vex_prefix3 {\n" | |
911 " vex_prefix3 = *p;\n" | |
912 " }\n" | |
913 " # VEX/XOP short prefix\n" | |
914 " action vex_prefix_short {\n" | |
915 " /* This emulates two prefixes case. */\n" | |
916 " vex_prefix2 = (p[0] & 0x80) | 0x61;\n" | |
917 " vex_prefix3 = p[0] & 0x7f;\n" | |
918 " }\n" | |
919 ""); | |
920 } | |
921 } | |
922 typedef std::pair<const char *, int> T; | |
923 static const T vex_fields[] = { | |
924 T { "NONE", 0xe0 }, | |
925 T { "R", 0x60 }, | |
926 T { "X", 0xa0 }, | |
927 T { "B", 0xc0 }, | |
928 T { "RX", 0x20 }, | |
929 T { "RB", 0x40 }, | |
930 T { "XB", 0x80 }, | |
931 T { "RXB", 0x00 } | |
932 }; | |
933 for (int vex_it = 0; vex_it < arraysize(vex_fields); ++vex_it) { | |
934 auto vex = vex_fields[vex_it]; | |
935 fprintf(out_file, " VEX_%2$s = %3$s%1$s;\n" | |
936 "", enabled(Actions::kVexPrefix) && !ia32_mode ? " @vex_prefix2" : "", | |
937 vex.first, chartest((c & vex.second) == vex.second)); | |
938 } | |
939 static const T vex_map[] = { | |
940 T { "01", 1 }, | |
941 T { "02", 2 }, | |
942 T { "03", 3 }, | |
943 T { "08", 8 }, | |
944 T { "09", 9 }, | |
945 T { "0A", 10 }, | |
946 T { "00001", 1 }, | |
947 T { "00010", 2 }, | |
948 T { "00011", 3 }, | |
949 T { "01000", 8 }, | |
950 T { "01001", 9 }, | |
951 T { "01010", 10 }, | |
952 }; | |
953 for (int vex_it = 0; vex_it < arraysize(vex_map); ++vex_it) { | |
954 auto vex = vex_map[vex_it]; | |
955 fprintf(out_file, " VEX_map%1$s = %2$s;\n" | |
956 "", vex.first, chartest((c & 0x1f) == vex.second)); | |
957 } | |
958 if (enabled(Actions::kOpcode)) { | |
959 fprintf(out_file, "\n" | |
960 " action begin_opcode {\n" | |
961 " begin_opcode = p;\n" | |
962 " }\n" | |
963 " action end_opcode {\n" | |
964 " end_opcode = p;\n" | |
965 " }\n" | |
966 ""); | |
967 } | |
968 if (enabled(Actions::kParseOperands)) { | |
969 for (auto i = 0 ; i <= 5; ++i) { | |
970 fprintf(out_file, " action operands_count_is_%1$d {\n" | |
971 " operands_count = %1$d;\n" | |
972 " }\n" | |
973 "", i); | |
974 } | |
975 for (auto i = 0 ; i < 5; ++i) { | |
976 typedef std::pair<const char *, const char *> T; | |
977 static const T sizes[] = { | |
978 T { "2bit", "Size2bit" }, | |
979 T { "8bit", "Size8bit" }, | |
980 T { "16bit", "Size16bit" }, | |
981 T { "32bit", "Size32bit" }, | |
982 T { "64bit", "Size64bit" }, | |
983 T { "128bit", "Size128bit" }, | |
984 T { "256bit", "Size256bit" }, | |
985 T { "float16bit", "FloatSize16bit" }, | |
986 T { "float32bit", "FloatSize32bit" }, | |
987 T { "float64bit", "FloatSize64bit" }, | |
988 T { "float80bit", "FloatSize80bit" }, | |
989 T { "regsize", ia32_mode ? "Size32bit" : | |
990 "Size64bit" }, | |
991 T { "x87_16bit", "X87Size16bit" }, | |
992 T { "x87_32bit", "X87Size32bit" }, | |
993 T { "x87_64bit", "X87Size64bit" }, | |
994 T { "x87_bcd", "X87BCD" }, | |
995 T { "x87_env", "X87ENV" }, | |
996 T { "x87_state", "X87STATE" }, | |
997 T { "x87_mmx_xmm_state", "X87MMXXMMSTATE" }, | |
998 T { "x87", "ST" }, | |
999 T { "mmx", "MMX" }, | |
1000 T { "xmm", "XMM" }, | |
1001 T { "ymm", "YMM" }, | |
1002 T { "farptr", "FarPtr" }, | |
1003 T { "segreg", "SegmentRegister" }, | |
1004 T { "creg", "ControlRegister" }, | |
1005 T { "dreg", "DebugRegister" }, | |
1006 T { "selector", "Selector" } | |
1007 }; | |
1008 for (int size_it = 0; size_it < arraysize(sizes); ++size_it) { | |
1009 auto size = sizes[size_it]; | |
1010 fprintf(out_file, " action operand%1$d_%2$s {\n" | |
1011 " operand%1$d_type = Operand%3$s;\n" | |
1012 " }\n" | |
1013 "", i, size.first, size.second); | |
1014 } | |
1015 if (ia32_mode) { | |
1016 fprintf(out_file, " action operand%1$d_absolute_disp {\n" | |
1017 " operand%1$d = REG_RM;\n" | |
1018 " base = REG_NONE;\n" | |
1019 " index = REG_NONE;\n" | |
1020 " scale = 0;\n" | |
1021 " }\n" | |
1022 " action operand%1$d_from_opcode {\n" | |
1023 " operand%1$d = (*p) & 0x7;\n" | |
1024 " }\n" | |
1025 " action operand%1$d_from_is4 {\n" | |
1026 " operand%1$d = p[0] >> 4;\n" | |
1027 " }\n" | |
1028 " action operand%1$d_from_modrm_rm {\n" | |
1029 " operand%1$d = (*p) & 0x07;\n" | |
1030 " }\n" | |
1031 " action operand%1$d_from_modrm_reg {\n" | |
1032 " operand%1$d = ((*p) & 0x38) >> 3;\n" | |
1033 " }\n" | |
1034 " action operand%1$d_from_vex {\n" | |
1035 " operand%1$d = ((~vex_prefix3) & 0x38) >> 3;\n" | |
1036 " }\n" | |
1037 "", i); | |
1038 } else { | |
1039 fprintf(out_file, " action operand%1$d_absolute_disp {\n" | |
1040 " operand%1$d = REG_RM;\n" | |
1041 " base = REG_NONE;\n" | |
1042 " index = REG_RIZ;\n" | |
1043 " scale = 0;\n" | |
1044 " }\n" | |
1045 " action operand%1$d_from_opcode {\n" | |
1046 " operand%1$d = ((*p) & 0x7) |\n" | |
1047 " ((rex_prefix & 0x01) << 3) |\n" | |
1048 " (((~vex_prefix2) & 0x20) >> 2);\n" | |
1049 " }\n" | |
1050 " action operand%1$d_from_is4 {\n" | |
1051 " operand%1$d = p[0] >> 4;\n" | |
1052 " }\n" | |
1053 " action operand%1$d_from_modrm_rm {\n" | |
1054 " operand%1$d = ((*p) & 0x07) |\n" | |
1055 " ((rex_prefix & 0x01) << 3) |\n" | |
1056 " (((~vex_prefix2) & 0x20) >> 2);\n" | |
1057 " }\n" | |
1058 " action operand%1$d_from_modrm_reg {\n" | |
1059 " operand%1$d = (((*p) & 0x38) >> 3) |\n" | |
1060 " ((rex_prefix & 0x04) << 1) |\n" | |
1061 " (((~vex_prefix2) & 0x80) >> 4);\n" | |
1062 " }\n" | |
1063 " action operand%1$d_from_vex {\n" | |
1064 " operand%1$d = ((~vex_prefix3) & 0x78) >> 3;\n" | |
1065 " }\n" | |
1066 "", i); | |
1067 } | |
1068 static const T types[] = { | |
1069 T { "ds_rbx", "REG_DS_RBX" }, | |
1070 T { "ds_rsi", "REG_DS_RSI" }, | |
1071 T { "es_rdi", "REG_ES_RDI" }, | |
1072 T { "immediate", "REG_IMM" }, | |
1073 T { "second_immediate", "REG_IMM2" }, | |
1074 T { "port_dx", "REG_PORT_DX" }, | |
1075 T { "rax", "REG_RAX" }, | |
1076 T { "rcx", "REG_RCX" }, | |
1077 T { "rdx", "REG_RDX" }, | |
1078 T { "rm", "REG_RM" }, | |
1079 T { "st", "REG_ST" } | |
1080 }; | |
1081 for (int type_it = 0; type_it < arraysize(types); ++type_it) { | |
1082 auto type = types[type_it]; | |
1083 fprintf(out_file, " action operand%1$d_%2$s {\n" | |
1084 " operand%1$d = %3$s;\n" | |
1085 " }\n" | |
1086 "", i, type.first, type.second); | |
1087 } | |
1088 } | |
1089 } | |
1090 if (enabled(Actions::kParseOperandsStates)) { | |
1091 for (auto i = 0 ; i < 5; ++i) { | |
1092 fprintf(out_file, " action operand%1$d_unused {\n" | |
1093 " operand%1$d_read = false;\n" | |
1094 " operand%1$d_write = false;\n" | |
1095 " }\n" | |
1096 " action operand%1$d_read {\n" | |
1097 " operand%1$d_read = true;\n" | |
1098 " operand%1$d_write = false;\n" | |
1099 " }\n" | |
1100 " action operand%1$d_write {\n" | |
1101 " operand%1$d_read = false;\n" | |
1102 " operand%1$d_write = true;\n" | |
1103 " }\n" | |
1104 " action operand%1$d_readwrite {\n" | |
1105 " operand%1$d_read = true;\n" | |
1106 " operand%1$d_write = true;\n" | |
1107 " }\n" | |
1108 "", i); | |
1109 } | |
1110 } | |
1111 } | |
1112 | |
1113 void print_name_actions(void) { | |
1114 for (auto pair_it = instruction_names.begin(); pair_it != instruction_names.
end(); ++pair_it) { | |
1115 auto &pair = *pair_it; | |
1116 fprintf(out_file, " action instruction_%s" | |
1117 " { instruction_name = instruction_names + %zd; }\n", | |
1118 c_identifier(pair.first).c_str(), pair.second); | |
1119 } | |
1120 } | |
1121 | |
1122 struct MarkedInstruction : Instruction { | |
1123 /* Additional marks are created in the process of parsing. */ | |
1124 MarkedInstruction(Instruction instruction_) : | |
1125 Instruction(instruction_), | |
1126 instruction_class(get_instruction_class(instruction_)), | |
1127 opcode_in_modrm(false), opcode_in_imm(false), rex { } { | |
1128 if (condrep) { | |
1129 optional_prefixes.insert("condrep"); | |
1130 } | |
1131 if (rep) { | |
1132 optional_prefixes.insert("rep"); | |
1133 } | |
1134 for (auto opcode_it = opcodes.begin(); opcode_it != opcodes.end(); ++opcod
e_it) { | |
1135 auto opcode = *opcode_it; | |
1136 if (opcode == "/") { | |
1137 opcode_in_imm = true; | |
1138 break; | |
1139 } else if (opcode.find('/') != opcode.npos) { | |
1140 opcode_in_modrm = true; | |
1141 break; | |
1142 } | |
1143 } | |
1144 /* If register is stored in opcode we need to expand opcode now. */ | |
1145 for (auto operand_it = operands.begin(); operand_it != operands.end(); ++o
perand_it) { | |
1146 auto &operand = *operand_it; | |
1147 if (operand.source == 'r') { | |
1148 auto opcode = opcodes.rbegin(); | |
1149 for (; opcode != opcodes.rend(); ++opcode) { | |
1150 if (opcode->find('/') == opcode->npos) { | |
1151 auto saved_opcode = *opcode; | |
1152 switch (*(opcode->rbegin())) { | |
1153 case '0': | |
1154 (*opcode) = "("; | |
1155 opcode->append(saved_opcode); | |
1156 for (auto c = '1'; c <= '7'; ++c) { | |
1157 opcode->push_back('|'); | |
1158 (*(saved_opcode.rbegin())) = c; | |
1159 opcode->append(saved_opcode); | |
1160 } | |
1161 opcode->push_back(')'); | |
1162 if (saved_opcode == "0x97") { | |
1163 opcode->erase(1, 5); | |
1164 } | |
1165 break; | |
1166 case '8': | |
1167 (*opcode) = "("; | |
1168 opcode->append(saved_opcode); | |
1169 static const char cc[] = {'9', 'a', 'b', 'c', 'd', 'e', 'f'}; | |
1170 for (int c_it = 0; c_it < arraysize(cc); ++c_it) { | |
1171 auto c = cc[c_it]; | |
1172 opcode->push_back('|'); | |
1173 (*(saved_opcode.rbegin())) = c; | |
1174 opcode->append(saved_opcode); | |
1175 } | |
1176 opcode->push_back(')'); | |
1177 break; | |
1178 default: | |
1179 fprintf(stderr, _("%s: error - can not use “r” operand in " | |
1180 "instruction “%s”"), short_program_name, name.c_str()); | |
1181 exit(1); | |
1182 } | |
1183 if (operand.size != "7") rex.b = true; | |
1184 break; | |
1185 } | |
1186 } | |
1187 if (opcode == opcodes.rend()) { | |
1188 fprintf(stderr, _("%s: error - can not use “r” operand in " | |
1189 "instruction “%s”"), short_program_name, name.c_str()); | |
1190 exit(1); | |
1191 } | |
1192 break; | |
1193 } | |
1194 } | |
1195 /* Some “opcodes” include prefixes, move them there. */ | |
1196 static std::set<std::string> opcode_prefixes = { | |
1197 "0x66", "data16", | |
1198 "0xf0", "lock", | |
1199 "0xf2", "repnz", | |
1200 "0xf3", "repz", | |
1201 "rexw" | |
1202 }; | |
1203 while (opcode_prefixes.find(*opcodes.begin()) != opcode_prefixes.end()) { | |
1204 if ((*opcodes.begin()) == "rexw") { | |
1205 if (!rex.w && instruction_class == InstructionClass::kDefault) { | |
1206 instruction_class = InstructionClass::kRexW; | |
1207 rex.w = true; | |
1208 } else if (!rex.w && instruction_class == InstructionClass::kSize8) { | |
1209 instruction_class = InstructionClass::kSize8RexW; | |
1210 rex.w = true; | |
1211 } else { | |
1212 fprintf(stderr, _("%s: error - can not enforce “%drexw” prefix in " | |
1213 "instruction “%s”"), short_program_name, instruction_cl
ass, name.c_str()); | |
1214 exit(1); | |
1215 } | |
1216 } else { | |
1217 required_prefixes.insert(*opcodes.begin()); | |
1218 } | |
1219 opcodes.erase(opcodes.begin()); | |
1220 } | |
1221 } | |
1222 | |
1223 enum InstructionClass { | |
1224 kDefault, | |
1225 /* The same as kDefault, but to make “dil”/“sil”/“bpl”/“spl” accesible | |
1226 pure REX (hex 0x40) is allowed. */ | |
1227 kSize8, | |
1228 /* One operand is kSize8, another is RexW. */ | |
1229 kSize8RexW, | |
1230 kData16, | |
1231 kRexW, | |
1232 /* Combinations: must generate few different lines. */ | |
1233 kDefaultRexW, | |
1234 kData16DefaultRexW, | |
1235 kSize8Data16DefaultRexW, | |
1236 kLSetUnset, | |
1237 kLSetUnsetDefaultRexW, | |
1238 /* Unknown: if all arguments are unknown the result is kDefault. */ | |
1239 kUnknown | |
1240 } instruction_class; | |
1241 std::multiset<std::string> required_prefixes; | |
1242 std::multiset<std::string> optional_prefixes; | |
1243 struct { | |
1244 bool b : 1; | |
1245 bool x : 1; | |
1246 bool r : 1; | |
1247 bool w : 1; | |
1248 } rex; | |
1249 bool opcode_in_modrm : 1; | |
1250 bool opcode_in_imm : 1; | |
1251 | |
1252 static InstructionClass get_instruction_class( | |
1253 const Instruction &instruction) { | |
1254 InstructionClass instruction_class = InstructionClass::kUnknown; | |
1255 for (auto operand_it = instruction.operands.begin(); operand_it != instruc
tion.operands.end(); ++operand_it) { | |
1256 auto &operand = *operand_it; | |
1257 static const std::map<std::string, InstructionClass> classes_map { | |
1258 /* “size8” is special “prefix” not included in AMD manual: w bit in | |
1259 opcode switches between 8bit and 16/32/64 bit versions. M is just | |
1260 an address in memory: it means register-only encodings are invalid, | |
1261 but other operands decide everything else. */ | |
1262 { "", InstructionClass::kSize8Data16DefaultRexW }, | |
1263 { "2", InstructionClass::kUnknown }, | |
1264 { "7", InstructionClass::kUnknown }, | |
1265 { "d", InstructionClass::kUnknown }, | |
1266 { "do", InstructionClass::kUnknown }, | |
1267 { "dq", InstructionClass::kUnknown }, | |
1268 { "fq", InstructionClass::kUnknown }, | |
1269 { "o", InstructionClass::kUnknown }, | |
1270 { "p", InstructionClass::kUnknown }, | |
1271 { "pb", InstructionClass::kUnknown }, | |
1272 { "pd", InstructionClass::kUnknown }, | |
1273 { "pdw", InstructionClass::kUnknown }, | |
1274 { "pdwx", InstructionClass::kLSetUnset }, | |
1275 { "pdx", InstructionClass::kLSetUnset }, | |
1276 { "ph", InstructionClass::kUnknown }, | |
1277 { "pi", InstructionClass::kUnknown }, | |
1278 { "pj", InstructionClass::kUnknown }, | |
1279 { "pjx", InstructionClass::kLSetUnset }, | |
1280 { "pk", InstructionClass::kUnknown }, | |
1281 { "pq", InstructionClass::kUnknown }, | |
1282 { "pqw", InstructionClass::kUnknown }, | |
1283 { "pqwx", InstructionClass::kLSetUnset }, | |
1284 { "ps", InstructionClass::kUnknown }, | |
1285 { "psx", InstructionClass::kLSetUnset }, | |
1286 { "pw", InstructionClass::kUnknown }, | |
1287 { "q", InstructionClass::kUnknown }, | |
1288 { "r", InstructionClass::kUnknown }, | |
1289 { "s", InstructionClass::kUnknown }, | |
1290 { "sb", InstructionClass::kUnknown }, | |
1291 { "sd", InstructionClass::kUnknown }, | |
1292 { "se", InstructionClass::kUnknown }, | |
1293 { "si", InstructionClass::kUnknown }, | |
1294 { "sq", InstructionClass::kUnknown }, | |
1295 { "sr", InstructionClass::kUnknown }, | |
1296 { "ss", InstructionClass::kUnknown }, | |
1297 { "st", InstructionClass::kUnknown }, | |
1298 { "sw", InstructionClass::kUnknown }, | |
1299 { "sx", InstructionClass::kUnknown }, | |
1300 { "v", InstructionClass::kData16DefaultRexW }, | |
1301 { "w", InstructionClass::kUnknown }, | |
1302 { "x", InstructionClass::kLSetUnset }, | |
1303 { "y", InstructionClass::kDefaultRexW }, | |
1304 { "z", InstructionClass::kData16DefaultRexW } | |
1305 }; | |
1306 InstructionClass operand_class; | |
1307 auto it = classes_map.find(operand.size); | |
1308 if (it != classes_map.end()) { | |
1309 operand_class = it->second; | |
1310 /* If it's 8bit register specified using ModRM then we mark it as size8 | |
1311 to make it possible to use REX_NONE for “dil”/“sil”/“bpl”/“spl”. */ | |
1312 } else if (operand.size == "b") { | |
1313 if ((operand.source == 'E') || | |
1314 (operand.source == 'G') || | |
1315 (operand.source == 'M') || | |
1316 (operand.source == 'R') || | |
1317 (operand.source == 'r')) { | |
1318 operand_class = InstructionClass::kSize8; | |
1319 } else { | |
1320 operand_class = InstructionClass::kUnknown; | |
1321 } | |
1322 } else { | |
1323 fprintf(stderr, _("%s: unknown operand: “%c%s”\n"), | |
1324 short_program_name, operand.source, operand.size.c_str()); | |
1325 exit(1); | |
1326 } | |
1327 if ((operand_class == InstructionClass::kUnknown) || | |
1328 (instruction_class == operand_class)) { | |
1329 ; /* Do nothing: operand_class does not change anything. */ | |
1330 } else if (instruction_class == InstructionClass::kUnknown) { | |
1331 instruction_class = operand_class; | |
1332 } else if (((instruction_class == InstructionClass::kDefaultRexW) && | |
1333 (operand_class == | |
1334 InstructionClass::kSize8Data16DefaultRexW)) || | |
1335 ((instruction_class == | |
1336 InstructionClass::kSize8Data16DefaultRexW) && | |
1337 (operand_class == InstructionClass::kDefaultRexW))) { | |
1338 instruction_class = InstructionClass::kSize8Data16DefaultRexW; | |
1339 } else { | |
1340 fprintf(stderr, _("%s: error - incompatible modes %d & %d\n"), | |
1341 short_program_name, instruction_class, operand_class); | |
1342 exit(1); | |
1343 } | |
1344 } | |
1345 switch (instruction_class) { | |
1346 case InstructionClass::kUnknown: | |
1347 return InstructionClass::kDefault; | |
1348 default: | |
1349 return instruction_class; | |
1350 } | |
1351 } | |
1352 | |
1353 void print_one_size_definition_data16(void) { | |
1354 auto saved_prefixes = required_prefixes; | |
1355 required_prefixes.insert("data16"); | |
1356 print_one_size_definition(); | |
1357 required_prefixes = saved_prefixes; | |
1358 } | |
1359 | |
1360 void print_one_size_definition_rexw(void) { | |
1361 auto saved_rex = rex; | |
1362 rex.w = true; | |
1363 print_one_size_definition(); | |
1364 rex = saved_rex; | |
1365 } | |
1366 | |
1367 void print_definition(void) { | |
1368 switch (auto saved_class = instruction_class) { | |
1369 case InstructionClass::kDefault: | |
1370 case InstructionClass::kSize8: | |
1371 print_one_size_definition(); | |
1372 break; | |
1373 case InstructionClass::kSize8RexW: | |
1374 case InstructionClass::kRexW: | |
1375 print_one_size_definition_rexw(); | |
1376 break; | |
1377 case InstructionClass::kData16: | |
1378 print_one_size_definition_data16(); | |
1379 break; | |
1380 case InstructionClass::kDefaultRexW: | |
1381 instruction_class = InstructionClass::kDefault; | |
1382 print_one_size_definition(); | |
1383 instruction_class = InstructionClass::kRexW; | |
1384 print_one_size_definition_rexw(); | |
1385 instruction_class = saved_class; | |
1386 break; | |
1387 case InstructionClass::kData16DefaultRexW: | |
1388 instruction_class = InstructionClass::kData16; | |
1389 print_one_size_definition_data16(); | |
1390 instruction_class = InstructionClass::kDefault; | |
1391 print_one_size_definition(); | |
1392 instruction_class = InstructionClass::kRexW; | |
1393 print_one_size_definition_rexw(); | |
1394 instruction_class = saved_class; | |
1395 break; | |
1396 case InstructionClass::kSize8Data16DefaultRexW: | |
1397 instruction_class = InstructionClass::kSize8; | |
1398 print_one_size_definition(); | |
1399 for (auto opcode = opcodes.rbegin(); opcode != opcodes.rend(); | |
1400 ++opcode) { | |
1401 if (opcode->find('/') == opcode->npos) { | |
1402 /* “w” bit is last bit both in binary and textual form. */ | |
1403 *(opcode->rbegin()) += 0x1; | |
1404 instruction_class = InstructionClass::kData16; | |
1405 print_one_size_definition_data16(); | |
1406 instruction_class = InstructionClass::kDefault; | |
1407 print_one_size_definition(); | |
1408 instruction_class = InstructionClass::kRexW; | |
1409 print_one_size_definition_rexw(); | |
1410 instruction_class = saved_class; | |
1411 return; | |
1412 } | |
1413 } | |
1414 fprintf(stderr, _("%s: error - can not set “w” bit in " | |
1415 "instruction “%s”"), short_program_name, name.c_str()); | |
1416 exit(1); | |
1417 case InstructionClass::kLSetUnset: | |
1418 case InstructionClass::kLSetUnsetDefaultRexW: | |
1419 for (auto opcode_it = opcodes.begin(); opcode_it != opcodes.end(); ++o
pcode_it) { | |
1420 auto &opcode = *opcode_it; | |
1421 auto Lbit = opcode.find(".L."); | |
1422 if (Lbit != opcode.npos) { | |
1423 opcode[++Lbit] = '1'; | |
1424 instruction_class = InstructionClass::kDefault; | |
1425 print_one_size_definition(); | |
1426 if (saved_class == InstructionClass::kLSetUnsetDefaultRexW) { | |
1427 instruction_class = InstructionClass::kRexW; | |
1428 print_one_size_definition_rexw(); | |
1429 } | |
1430 opcode[Lbit] = '0'; | |
1431 auto saved_operands = operands; | |
1432 for (auto operand_it = operands.begin(); operand_it != operands.en
d(); ++operand_it) { | |
1433 auto &operand = *operand_it; | |
1434 static const char cc[] = {'H', 'L', 'U', 'V', 'W'}; | |
1435 for (int c_it = 0; c_it < arraysize(cc); ++c_it) { | |
1436 auto c = cc[c_it]; | |
1437 if ((operand.source == c) && | |
1438 (*(operand.size.rbegin()) == 'x') && | |
1439 (((operand.size.length() > 1) && | |
1440 (operand.size[0] == 'p')) || | |
1441 (operand.size.length() == 1))) { | |
1442 operand.size.resize(operand.size.length() - 1); | |
1443 } | |
1444 } | |
1445 } | |
1446 instruction_class = InstructionClass::kDefault; | |
1447 print_one_size_definition(); | |
1448 if (saved_class == InstructionClass::kLSetUnsetDefaultRexW) { | |
1449 instruction_class = InstructionClass::kRexW; | |
1450 print_one_size_definition_rexw(); | |
1451 } | |
1452 operands = saved_operands; | |
1453 return; | |
1454 } | |
1455 } | |
1456 fprintf(stderr, _("%s: error - can not set “L” bit in" | |
1457 "instruction “%s”"), short_program_name, name.c_str()); | |
1458 exit(1); | |
1459 break; | |
1460 case InstructionClass::kUnknown: | |
1461 fprintf(stderr, _("%s: error - incorrect operand mode: “%d”"), | |
1462 short_program_name, instruction_class); | |
1463 exit(1); | |
1464 } | |
1465 } | |
1466 | |
1467 void print_one_size_definition(void) { | |
1468 /* 64bit commands are not supported in ia32 mode. */ | |
1469 if (ia32_mode && rex.w) { | |
1470 return; | |
1471 } | |
1472 bool modrm_memory = false; | |
1473 bool modrm_register = false; | |
1474 char operand_source; | |
1475 for (auto operand_it = operands.begin(); operand_it != operands.end(); ++o
perand_it) { | |
1476 auto &operand = *operand_it; | |
1477 static std::map<char, std::pair<bool, bool> > operand_map { | |
1478 { 'E', std::make_pair(true, true ) }, | |
1479 { 'M', std::make_pair(true, false) }, | |
1480 { 'N', std::make_pair(false, true ) }, | |
1481 { 'Q', std::make_pair(true, true ) }, | |
1482 { 'R', std::make_pair(false, true ) }, | |
1483 { 'U', std::make_pair(false, true ) }, | |
1484 { 'W', std::make_pair(true, true ) } | |
1485 }; | |
1486 auto it = operand_map.find(operand.source); | |
1487 if (it != operand_map.end()) { | |
1488 if ((modrm_memory || modrm_register) && | |
1489 ((modrm_memory != it->second.first) || | |
1490 (modrm_register != it->second.second))) { | |
1491 fprintf(stderr, _("%s: error - conflicting operand sources: “%c”" | |
1492 " and “%c”"), short_program_name, operand_source, operand.source); | |
1493 exit(1); | |
1494 } | |
1495 modrm_memory = it->second.first; | |
1496 modrm_register = it->second.second; | |
1497 operand_source = operand.source; | |
1498 } | |
1499 } | |
1500 if (modrm_memory || modrm_register) { | |
1501 if (modrm_memory) { | |
1502 auto saved_prefixes = optional_prefixes; | |
1503 /* optional_prefixes.insert("(segfs | seggs)"); */ | |
1504 print_one_size_definition_modrm_memory(); | |
1505 if (lock) { | |
1506 auto saved_prefixes = required_prefixes; | |
1507 required_prefixes.insert("lock"); | |
1508 print_one_size_definition_modrm_memory(); | |
1509 required_prefixes = saved_prefixes; | |
1510 } | |
1511 optional_prefixes = saved_prefixes; | |
1512 } | |
1513 if (modrm_register) { | |
1514 print_one_size_definition_modrm_register(); | |
1515 } | |
1516 } else { | |
1517 print_one_size_definition_nomodrm(); | |
1518 } | |
1519 } | |
1520 | |
1521 void print_one_size_definition_nomodrm(void) { | |
1522 print_operator_delimeter(); | |
1523 print_legacy_prefixes(); | |
1524 print_rex_prefix(); | |
1525 print_opcode_nomodrm(); | |
1526 if (opcode_in_imm) { | |
1527 print_immediate_opcode(); | |
1528 print_opcode_recognition(); | |
1529 } else { | |
1530 print_opcode_recognition(); | |
1531 print_immediate_arguments(); | |
1532 } | |
1533 } | |
1534 | |
1535 void print_one_size_definition_modrm_register(void) { | |
1536 print_operator_delimeter(); | |
1537 if (mod_reg_is_used()) { | |
1538 rex.r = true; | |
1539 } | |
1540 if (mod_rm_is_used()) { | |
1541 rex.b = true; | |
1542 } | |
1543 print_legacy_prefixes(); | |
1544 print_rex_prefix(); | |
1545 print_opcode_nomodrm(); | |
1546 if (!opcode_in_imm) { | |
1547 print_opcode_recognition(); | |
1548 } | |
1549 fprintf(out_file, " modrm_registers"); | |
1550 if (enabled(Actions::kParseOperands)) { | |
1551 for (auto operand_it = operands.begin(); operand_it != operands.end(); +
+operand_it) { | |
1552 auto &operand = *operand_it; | |
1553 static const std::map<char, const char*> operand_type { | |
1554 { 'C', "reg" }, | |
1555 { 'D', "reg" }, | |
1556 { 'E', "rm" }, | |
1557 { 'G', "reg" }, | |
1558 { 'M', "rm" }, | |
1559 { 'N', "rm" }, | |
1560 { 'P', "reg" }, | |
1561 { 'Q', "rm" }, | |
1562 { 'R', "rm" }, | |
1563 { 'S', "reg" }, | |
1564 { 'U', "rm" }, | |
1565 { 'V', "reg" }, | |
1566 { 'W', "rm" } | |
1567 }; | |
1568 auto it = operand_type.find(operand.source); | |
1569 if (it != operand_type.end()) { | |
1570 fprintf(out_file, " @operand%zd_from_modrm_%s", | |
1571 &operand - &*operands.begin(), it->second); | |
1572 } | |
1573 } | |
1574 } | |
1575 if (opcode_in_modrm) { | |
1576 fprintf(out_file, ")"); | |
1577 } | |
1578 if (opcode_in_imm) { | |
1579 print_immediate_opcode(); | |
1580 print_opcode_recognition(); | |
1581 } else { | |
1582 print_immediate_arguments(); | |
1583 } | |
1584 } | |
1585 | |
1586 void print_one_size_definition_modrm_memory(void) { | |
1587 typedef std::tuple<const char *, bool, bool> T; | |
1588 static const T modes[] = { | |
1589 T { " operand_disp", false, true }, | |
1590 T { " operand_rip", false, false }, | |
1591 T { " single_register_memory", false, true }, | |
1592 T { " operand_sib_pure_index", true, false }, | |
1593 T { " operand_sib_base_index", true, true } | |
1594 }; | |
1595 for (int mode_it = 0; mode_it < arraysize(modes); ++mode_it) { | |
1596 auto mode = modes[mode_it]; | |
1597 print_operator_delimeter(); | |
1598 if (mod_reg_is_used()) { | |
1599 rex.r = true; | |
1600 } | |
1601 if (mod_rm_is_used()) { | |
1602 rex.x = std::get<1>(mode); | |
1603 rex.b = std::get<2>(mode); | |
1604 } | |
1605 print_legacy_prefixes(); | |
1606 print_rex_prefix(); | |
1607 print_opcode_nomodrm(); | |
1608 if (!opcode_in_imm) { | |
1609 print_opcode_recognition(); | |
1610 } | |
1611 if (opcode_in_modrm) { | |
1612 fprintf(out_file, " any"); | |
1613 } else { | |
1614 fprintf(out_file, " (any"); | |
1615 } | |
1616 if (enabled(Actions::kParseOperands)) { | |
1617 for (auto operand_it = operands.begin(); operand_it != operands.end();
++operand_it) { | |
1618 auto &operand = *operand_it; | |
1619 static const std::map<char, const char*> operand_type { | |
1620 { 'C', "from_modrm_reg" }, | |
1621 { 'D', "from_modrm_reg" }, | |
1622 { 'E', "rm" }, | |
1623 { 'G', "from_modrm_reg" }, | |
1624 { 'M', "rm" }, | |
1625 { 'N', "rm" }, | |
1626 { 'P', "from_modrm_reg" }, | |
1627 { 'Q', "rm" }, | |
1628 { 'R', "rm" }, | |
1629 { 'S', "from_modrm_reg" }, | |
1630 { 'U', "rm" }, | |
1631 { 'V', "from_modrm_reg" }, | |
1632 { 'W', "rm" } | |
1633 }; | |
1634 auto it = operand_type.find(operand.source); | |
1635 if (it != operand_type.end()) { | |
1636 fprintf(out_file, " @operand%zd_%s", | |
1637 &operand - &*operands.begin(), it->second); | |
1638 } | |
1639 } | |
1640 } | |
1641 fprintf(out_file, " . any* &%s", std::get<0>(mode)); | |
1642 if (enabled(Actions::kCheckAccess) && !no_memory_access) { | |
1643 fprintf(out_file, " @check_access"); | |
1644 } | |
1645 fprintf(out_file, ")"); | |
1646 if (opcode_in_imm) { | |
1647 print_immediate_opcode(); | |
1648 print_opcode_recognition(); | |
1649 } else { | |
1650 print_immediate_arguments(); | |
1651 } | |
1652 } | |
1653 } | |
1654 | |
1655 #if 0 | |
1656 /* We need GCC 4.7 to use the following. */ | |
1657 static auto first_delimeter = true; | |
1658 #else | |
1659 static bool first_delimeter; | |
1660 #endif | |
1661 void print_operator_delimeter(void) { | |
1662 if (first_delimeter) { | |
1663 fprintf(out_file, "\n ("); | |
1664 } else { | |
1665 fprintf(out_file, ") |\n ("); | |
1666 } | |
1667 first_delimeter = false; | |
1668 } | |
1669 | |
1670 bool mod_reg_is_used() { | |
1671 for (auto operand_it = operands.begin(); operand_it != operands.end(); ++o
perand_it) { | |
1672 auto &operand = *operand_it; | |
1673 if (operand.source == 'C' && | |
1674 required_prefixes.find("0xf0") == required_prefixes.end()) { | |
1675 return true; | |
1676 } | |
1677 static const char cc[] = { 'G', 'P', 'V' }; | |
1678 for (int c_it = 0; c_it < arraysize(cc); ++c_it) { | |
1679 auto c = cc[c_it]; | |
1680 if (operand.source == c) { | |
1681 return true; | |
1682 } | |
1683 } | |
1684 } | |
1685 return false; | |
1686 } | |
1687 | |
1688 bool mod_rm_is_used() { | |
1689 for (auto operand_it = operands.begin(); operand_it != operands.end(); ++o
perand_it) { | |
1690 auto &operand = *operand_it; | |
1691 static const char cc[] = { 'E', 'M', 'N', 'Q', 'R', 'U', 'W' }; | |
1692 for (int c_it = 0; c_it < arraysize(cc); ++c_it) { | |
1693 auto c = cc[c_it]; | |
1694 if (operand.source == c) { | |
1695 return true; | |
1696 } | |
1697 } | |
1698 } | |
1699 return false; | |
1700 } | |
1701 | |
1702 void print_legacy_prefixes(void) { | |
1703 if ((required_prefixes.size() == 1) && | |
1704 (optional_prefixes.size() == 0)) { | |
1705 fprintf(out_file, "%s ", required_prefixes.begin()->c_str()); | |
1706 } else if ((required_prefixes.size() == 0) && | |
1707 (optional_prefixes.size() == 1)) { | |
1708 fprintf(out_file, "%s? ", optional_prefixes.begin()->c_str()); | |
1709 } else if ((optional_prefixes.size() > 0) || | |
1710 (required_prefixes.size() > 0)) { | |
1711 auto delimeter = "("; | |
1712 auto opt_start = required_prefixes.size() ? 0 : 1; | |
1713 auto opt_end = 1 << optional_prefixes.size(); | |
1714 for (auto opt = opt_start; opt < opt_end; ++opt) { | |
1715 auto prefixes = required_prefixes; | |
1716 auto it = optional_prefixes.begin(); | |
1717 for (auto id = 1; id < opt_end; id <<= 1, ++it) { | |
1718 if (opt & id) { | |
1719 prefixes.insert(*it); | |
1720 } | |
1721 } | |
1722 if (prefixes.size() == 1) { | |
1723 fprintf(out_file, "%s%s", delimeter, prefixes.begin()->c_str()); | |
1724 delimeter = " | "; | |
1725 } else { | |
1726 std::vector<std::string> permutations(prefixes.begin(), | |
1727 prefixes.end()); | |
1728 do { | |
1729 fprintf(out_file, "%s", delimeter); | |
1730 delimeter = " | "; | |
1731 auto delimeter = '('; | |
1732 for (auto prefix_it = permutations.begin(); prefix_it != permutati
ons.end(); ++prefix_it) { | |
1733 auto &prefix = *prefix_it; | |
1734 fprintf(out_file, "%c%s", delimeter, prefix.c_str()); | |
1735 delimeter = ' '; | |
1736 } | |
1737 fprintf(out_file, ")"); | |
1738 } while (next_permutation(permutations.begin(), | |
1739 permutations.end())); | |
1740 } | |
1741 } | |
1742 if (opt_start) { | |
1743 fprintf(out_file, ")? "); | |
1744 } else { | |
1745 fprintf(out_file, ") "); | |
1746 } | |
1747 } | |
1748 } | |
1749 | |
1750 void print_rex_prefix(void) { | |
1751 /* Prefix REX is not used in ia32 mode. */ | |
1752 if (ia32_mode) { | |
1753 return; | |
1754 } | |
1755 /* VEX/XOP instructions integrate REX bits and opcode bits. They will | |
1756 be printed in print_opcode_nomodrm. */ | |
1757 if ((opcodes.size() >= 3) && | |
1758 ((opcodes[0] == "0xc4") || | |
1759 ((opcodes[0] == "0x8f") && (opcodes[1] != "/0")))) { | |
1760 return; | |
1761 } | |
1762 if (rex.w || rex.r || rex.x || rex.b) { | |
1763 if (!rex.r && !rex.x && ! rex.b) { | |
1764 fprintf(out_file, "REXW_NONE "); | |
1765 } else { | |
1766 if (rex.w) { | |
1767 fprintf(out_file, "REXW_"); | |
1768 if (rex.r) fprintf(out_file, "R"); | |
1769 if (rex.x) fprintf(out_file, "X"); | |
1770 if (rex.b) fprintf(out_file, "B"); | |
1771 fprintf(out_file, " "); | |
1772 } else if (instruction_class == InstructionClass::kSize8 || | |
1773 instruction_class == InstructionClass::kSize8RexW) { | |
1774 fprintf(out_file, "REX_"); | |
1775 if (rex.r) fprintf(out_file, "R"); | |
1776 if (rex.x) fprintf(out_file, "X"); | |
1777 if (rex.b) fprintf(out_file, "B"); | |
1778 fprintf(out_file, "? "); | |
1779 } else { | |
1780 fprintf(out_file, "rex_"); | |
1781 if (rex.r) fprintf(out_file, "r"); | |
1782 if (rex.x) fprintf(out_file, "x"); | |
1783 if (rex.b) fprintf(out_file, "b"); | |
1784 fprintf(out_file, "? "); | |
1785 } | |
1786 } | |
1787 } | |
1788 } | |
1789 | |
1790 void print_third_byte(const std::string& third_byte) const { | |
1791 auto byte = 0; | |
1792 for (auto i = 7, p = 1; i>=0; --i, p <<= 1) { | |
1793 if (third_byte[i] == '1' || third_byte[i] == 'X' || | |
1794 ((third_byte[i] == 'W') && rex.w)) { | |
1795 byte |= p; | |
1796 } | |
1797 } | |
1798 if (third_byte.find('X') == third_byte.npos) { | |
1799 fprintf(out_file, "0x%02x", byte); | |
1800 } else { | |
1801 std::set<decltype(byte)> bytes { byte }; | |
1802 for (auto i = 7, p = 1; i>=0; --i, p <<= 1) { | |
1803 if (third_byte[i] == 'X') { | |
1804 for (auto byte_it = bytes.begin(); byte_it != bytes.end(); ++byte_it
) { | |
1805 auto &byte = *byte_it; | |
1806 bytes.insert(byte & ~p); | |
1807 } | |
1808 } | |
1809 } | |
1810 auto delimeter = "("; | |
1811 for (auto byte_it = bytes.begin(); byte_it != bytes.end(); ++byte_it) { | |
1812 auto &byte = *byte_it; | |
1813 fprintf(out_file, "%s0x%02x", delimeter, byte); | |
1814 delimeter = " | "; | |
1815 } | |
1816 fprintf(out_file, ")"); | |
1817 } | |
1818 } | |
1819 | |
1820 void print_opcode_nomodrm(void) { | |
1821 if ((opcodes.size() == 1) || | |
1822 ((opcodes.size() == 2) && | |
1823 (opcodes[1].find('/') != opcodes[1].npos))) { | |
1824 if (opcodes[0].find('/') == opcodes[0].npos) { | |
1825 if ((instruction_class == InstructionClass::kData16) && | |
1826 (opcodes[0] == "(0x91|0x92|0x93|0x94|0x95|0x96|0x97)")) { | |
1827 fprintf(out_file, "(0x90|0x91|0x92|0x93|0x94|0x95|0x96|0x97)"); | |
1828 } else { | |
1829 fprintf(out_file, "%s", opcodes[0].c_str()); | |
1830 } | |
1831 } | |
1832 } else if ((opcodes.size() >= 3) && | |
1833 ((opcodes[0] == "0xc4") || | |
1834 ((opcodes[0] == "0x8f") && (opcodes[1] != "/0"))) && | |
1835 (opcodes[1].substr(0, 4) == "RXB.")) { | |
1836 auto c5_ok = (opcodes[0] == "0xc4") && | |
1837 ((opcodes[1] == "RXB.01") || | |
1838 (opcodes[1] == "RXB.00001")) && | |
1839 ((*opcodes[2].begin() == '0') || | |
1840 (*opcodes[2].begin() == 'x') || | |
1841 (*opcodes[2].begin() == 'X')); | |
1842 if (c5_ok) fprintf(out_file, "(("); | |
1843 fprintf(out_file, "(%s (VEX_", opcodes[0].c_str()); | |
1844 if (ia32_mode || (!rex.r && !rex.x & !rex.b)) { | |
1845 fprintf(out_file, "NONE"); | |
1846 } else { | |
1847 if (rex.r) fprintf(out_file, "R"); | |
1848 if (rex.x) fprintf(out_file, "X"); | |
1849 if (rex.b) fprintf(out_file, "B"); | |
1850 } | |
1851 fprintf(out_file, " & VEX_map%s) ", opcodes[1].c_str() + 4); | |
1852 auto third_byte = opcodes[2]; | |
1853 #if 0 | |
1854 /* We need GCC 4.8 for the following. */ | |
1855 static const std::regex third_byte_check( | |
1856 R"([01xX]\.[01xX][01xX][01xX][01xX]\.[01xX]\.[01][01])"); | |
1857 if ((third_byte.length() != 11) || | |
1858 !regex_match(third_byte.begin(), third_byte.end(), | |
1859 third_byte_check)) { | |
1860 #else | |
1861 static const char* symbolic_names[] = { "cntl", "dest", "src1", "src" }; | |
1862 for (int symbolic_it = 0; symbolic_it < arraysize(symbolic_names); ++sym
bolic_it) { | |
1863 auto symbolic = symbolic_names[symbolic_it]; | |
1864 for (auto it = third_byte.begin(); it != third_byte.end(); ++it) { | |
1865 if ((third_byte.end() - it) >= strlen(symbolic) && | |
1866 !strncmp(&*it, symbolic, strlen(symbolic))) { | |
1867 third_byte.replace(it, it + strlen(symbolic), "XXXX"); | |
1868 break; | |
1869 } | |
1870 } | |
1871 } | |
1872 static const std::set<char> third_byte_check[] { | |
1873 { '0', '1', 'x', 'X', 'W' }, | |
1874 { '.' }, | |
1875 { '0', '1', 'x', 'X' }, | |
1876 { '0', '1', 'x', 'X' }, | |
1877 { '0', '1', 'x', 'X' }, | |
1878 { '0', '1', 'x', 'X' }, | |
1879 { '.' }, | |
1880 { '0', '1', 'x', 'X' }, | |
1881 { '.' }, | |
1882 { '0', '1' }, | |
1883 { '0', '1' } | |
1884 }; | |
1885 auto third_byte_ok = (arraysize(third_byte_check) == | |
1886 third_byte.length()); | |
1887 if (third_byte_ok) { | |
1888 for (int set_it = 0; set_it < arraysize(third_byte_check); ++set_it) { | |
1889 auto &set = third_byte_check[set_it]; | |
1890 if (set.find(third_byte[&set - third_byte_check]) == set.end()) { | |
1891 third_byte_ok = false; | |
1892 break; | |
1893 } | |
1894 } | |
1895 } | |
1896 if (third_byte_ok) { | |
1897 #endif | |
1898 if (ia32_mode && third_byte[2] == 'X') { | |
1899 third_byte[2] = '1'; | |
1900 } | |
1901 third_byte.erase(1, 1); | |
1902 third_byte.erase(5, 1); | |
1903 third_byte.erase(6, 1); | |
1904 print_third_byte(third_byte); | |
1905 if (enabled(Actions::kVexPrefix)) { | |
1906 fprintf(out_file, " @vex_prefix3"); | |
1907 } | |
1908 if (c5_ok) { | |
1909 fprintf(out_file, ") | (0xc5 "); | |
1910 if (!ia32_mode && rex.r) { | |
1911 third_byte[0] = 'X'; | |
1912 } else { | |
1913 third_byte[0] = '1'; | |
1914 } | |
1915 print_third_byte(third_byte); | |
1916 if (enabled(Actions::kVexPrefix)) { | |
1917 fprintf(out_file, " @vex_prefix_short"); | |
1918 } | |
1919 fprintf(out_file, "))"); | |
1920 } | |
1921 for (auto opcode = ++++++opcodes.begin(); opcode != opcodes.end(); | |
1922 ++opcode) { | |
1923 | |
1924 if (opcode->find('/') == opcode->npos) { | |
1925 fprintf(out_file, " %s", opcode->c_str()); | |
1926 } else { | |
1927 break; | |
1928 } | |
1929 } | |
1930 fprintf(out_file, ")"); | |
1931 } else { | |
1932 fprintf(stderr, _("%s: error - third byte of VEX/XOP command " | |
1933 "in unparseable (%s) in instruction “%s”"), | |
1934 short_program_name, third_byte.c_str(), name.c_str()); | |
1935 exit(1); | |
1936 } | |
1937 } else { | |
1938 auto delimeter = '('; | |
1939 for (auto opcode_it = opcodes.begin(); opcode_it != opcodes.end(); ++opc
ode_it) { | |
1940 auto &opcode = *opcode_it; | |
1941 if (opcode.find('/') == opcode.npos) { | |
1942 fprintf(out_file, "%c%s", delimeter, opcode.c_str()); | |
1943 delimeter = ' '; | |
1944 } else { | |
1945 break; | |
1946 } | |
1947 } | |
1948 fprintf(out_file, ")"); | |
1949 } | |
1950 if (enabled(Actions::kOpcode)) { | |
1951 fprintf(out_file, " >begin_opcode"); | |
1952 } | |
1953 if (enabled(Actions::kParseOperands)) { | |
1954 for (auto operand_it = operands.begin(); operand_it != operands.end(); +
+operand_it) { | |
1955 auto &operand = *operand_it; | |
1956 if (operand.source == 'r') { | |
1957 fprintf(out_file, " @operand%zd_from_opcode", | |
1958 &operand - &*operands.begin()); | |
1959 } | |
1960 } | |
1961 } | |
1962 } | |
1963 | |
1964 void print_opcode_recognition(void) { | |
1965 if (opcode_in_modrm) { | |
1966 fprintf(out_file, " ("); | |
1967 for (auto opcode = opcodes.rbegin(); opcode != opcodes.rend(); | |
1968 ++opcode) { | |
1969 if ((*opcode) != "/" && opcode->find('/') != opcode->npos) { | |
1970 fprintf(out_file, "opcode_%s", opcode->c_str() + 1); | |
1971 } | |
1972 } | |
1973 } | |
1974 if (enabled(Actions::kOpcode)) { | |
1975 fprintf(out_file, " @end_opcode"); | |
1976 } | |
1977 for (auto prefix_it = required_prefixes.begin(); prefix_it != required_pre
fixes.end(); ++prefix_it) { | |
1978 auto &prefix = *prefix_it; | |
1979 if (prefix == "0x66") { | |
1980 fprintf(out_file, " @not_data16_prefix"); | |
1981 break; | |
1982 } | |
1983 } | |
1984 for (auto prefix_it = required_prefixes.begin(); prefix_it != required_pre
fixes.end(); ++prefix_it) { | |
1985 auto &prefix = *prefix_it; | |
1986 if (prefix == "0xf2") { | |
1987 fprintf(out_file, " @not_repnz_prefix"); | |
1988 break; | |
1989 } | |
1990 } | |
1991 for (auto prefix_it = required_prefixes.begin(); prefix_it != required_pre
fixes.end(); ++prefix_it) { | |
1992 auto &prefix = *prefix_it; | |
1993 if (prefix == "0xf3") { | |
1994 fprintf(out_file, " @not_repz_prefix"); | |
1995 break; | |
1996 } | |
1997 } | |
1998 if (enabled(Actions::kInstructionName)) { | |
1999 fprintf(out_file, " @instruction_%s", c_identifier(name).c_str()); | |
2000 } | |
2001 if (enabled(Actions::kParseOperands)) { | |
2002 fprintf(out_file, " @operands_count_is_%zd", operands.size()); | |
2003 for (auto operand_it = operands.begin(); operand_it != operands.end(); +
+operand_it) { | |
2004 auto &operand = *operand_it; | |
2005 typedef std::tuple<InstructionClass, char, std::string> T; | |
2006 static const std::map<T, const char*> operand_sizes { | |
2007 { T { InstructionClass::kDefault, ' ', "" }, "32bit" }, | |
2008 { T { InstructionClass::kSize8, ' ', "" }, "8bit" }, | |
2009 { T { InstructionClass::kData16, ' ', "" }, "16bit" }, | |
2010 { T { InstructionClass::kRexW, ' ', "" }, "64bit" }, | |
2011 { T { InstructionClass::kUnknown, 'H', "" }, "128bit" }, | |
2012 { T { InstructionClass::kRexW, 'I', "" }, "32bit" }, | |
2013 { T { InstructionClass::kUnknown, 'L', "" }, "128bit" }, | |
2014 { T { InstructionClass::kUnknown, 'V', "" }, "128bit" }, | |
2015 { T { InstructionClass::kUnknown, 'W', "" }, "128bit" }, | |
2016 { T { InstructionClass::kUnknown, ' ', "2" }, "2bit" }, | |
2017 { T { InstructionClass::kUnknown, ' ', "7" }, "x87" }, | |
2018 { T { InstructionClass::kUnknown, ' ', "b" }, "8bit" }, | |
2019 { T { InstructionClass::kUnknown, ' ', "d" }, "32bit" }, | |
2020 { T { InstructionClass::kUnknown, ' ', "do" }, "256bit" }, | |
2021 { T { InstructionClass::kUnknown, ' ', "dq" }, "128bit" }, | |
2022 { T { InstructionClass::kUnknown, ' ', "fq" }, "256bit" }, | |
2023 { T { InstructionClass::kUnknown, ' ', "o" }, "128bit" }, | |
2024 { T { InstructionClass::kUnknown, ' ', "p" }, "farptr" }, | |
2025 { T { InstructionClass::kUnknown, ' ', "pb" }, "xmm" }, | |
2026 { T { InstructionClass::kUnknown, ' ', "pd" }, "xmm" }, | |
2027 { T { InstructionClass::kUnknown, ' ', "pdw" }, "xmm" }, | |
2028 { T { InstructionClass::kUnknown, ' ', "pdwx" }, "ymm" }, | |
2029 { T { InstructionClass::kUnknown, ' ', "pdx" }, "ymm" }, | |
2030 { T { InstructionClass::kUnknown, ' ', "ph" }, "xmm" }, | |
2031 { T { InstructionClass::kUnknown, ' ', "pi" }, "xmm" }, | |
2032 { T { InstructionClass::kUnknown, ' ', "pj" }, "xmm" }, | |
2033 { T { InstructionClass::kUnknown, ' ', "pjx" }, "ymm" }, | |
2034 { T { InstructionClass::kUnknown, ' ', "pk" }, "xmm" }, | |
2035 { T { InstructionClass::kUnknown, ' ', "pq" }, "xmm" }, | |
2036 { T { InstructionClass::kUnknown, ' ', "pqw" }, "xmm" }, | |
2037 { T { InstructionClass::kUnknown, ' ', "pqwx" }, "ymm" }, | |
2038 { T { InstructionClass::kUnknown, ' ', "ps" }, "xmm" }, | |
2039 { T { InstructionClass::kUnknown, ' ', "psx" }, "ymm" }, | |
2040 { T { InstructionClass::kUnknown, ' ', "pw" }, "xmm" }, | |
2041 { T { InstructionClass::kUnknown, ' ', "q" }, "64bit" }, | |
2042 { T { InstructionClass::kUnknown, 'N', "q" }, "mmx" }, | |
2043 { T { InstructionClass::kUnknown, 'P', "q" }, "mmx" }, | |
2044 { T { InstructionClass::kUnknown, 'Q', "q" }, "mmx" }, | |
2045 { T { InstructionClass::kUnknown, 'U', "q" }, "xmm" }, | |
2046 { T { InstructionClass::kUnknown, 'V', "q" }, "xmm" }, | |
2047 { T { InstructionClass::kUnknown, 'W', "q" }, "xmm" }, | |
2048 { T { InstructionClass::kUnknown, ' ', "r" }, "regsize" }, | |
2049 { T { InstructionClass::kUnknown, 'C', "r" }, "creg" }, | |
2050 { T { InstructionClass::kUnknown, 'D', "r" }, "dreg" }, | |
2051 { T { InstructionClass::kUnknown, ' ', "s" }, "selector" }, | |
2052 { T { InstructionClass::kUnknown, ' ', "sb" }, "x87_bcd" }, | |
2053 { T { InstructionClass::kUnknown, ' ', "sd" }, "float64bit" }, | |
2054 { T { InstructionClass::kUnknown, ' ', "se" }, "x87_env" }, | |
2055 { T { InstructionClass::kUnknown, ' ', "si" }, "x87_32bit" }, | |
2056 { T { InstructionClass::kUnknown, ' ', "sq" }, "x87_64bit" }, | |
2057 { T { InstructionClass::kUnknown, ' ', "sr" }, "x87_state" }, | |
2058 { T { InstructionClass::kUnknown, ' ', "ss" }, "float32bit" }, | |
2059 { T { InstructionClass::kUnknown, ' ', "st" }, "float80bit" }, | |
2060 { T { InstructionClass::kUnknown, ' ', "sw" }, "x87_16bit" }, | |
2061 { T { InstructionClass::kUnknown, ' ', "sx" }, | |
2062 "x87_mmx_xmm_state" }, | |
2063 { T { InstructionClass::kData16, ' ', "v" }, "16bit" }, | |
2064 { T { InstructionClass::kDefault, ' ', "v" }, "32bit" }, | |
2065 { T { InstructionClass::kRexW, ' ', "v" }, "64bit" }, | |
2066 { T { InstructionClass::kUnknown, ' ', "w" }, "16bit" }, | |
2067 { T { InstructionClass::kUnknown, 'S', "w" }, "segreg" }, | |
2068 { T { InstructionClass::kUnknown, 'H', "x" }, "256bit" }, | |
2069 { T { InstructionClass::kUnknown, 'L', "x" }, "256bit" }, | |
2070 { T { InstructionClass::kUnknown, 'V', "x" }, "256bit" }, | |
2071 { T { InstructionClass::kUnknown, 'W', "x" }, "256bit" }, | |
2072 { T { InstructionClass::kDefault, ' ', "y" }, "32bit" }, | |
2073 { T { InstructionClass::kSize8, ' ', "y" }, "32bit" }, | |
2074 { T { InstructionClass::kData16, ' ', "y" }, "32bit" }, | |
2075 { T { InstructionClass::kDefault, ' ', "y" }, "32bit" }, | |
2076 { T { InstructionClass::kRexW, ' ', "y" }, "64bit" }, | |
2077 { T { InstructionClass::kData16, ' ', "z" }, "16bit" }, | |
2078 { T { InstructionClass::kDefault, ' ', "z" }, "32bit" }, | |
2079 { T { InstructionClass::kRexW, ' ', "z" }, "32bit" } | |
2080 }; | |
2081 auto it = operand_sizes.find(T {instruction_class, | |
2082 operand.source, operand.size}); | |
2083 if (it == operand_sizes.end()) { | |
2084 it = operand_sizes.find(T {InstructionClass::kUnknown, | |
2085 operand.source, operand.size}); | |
2086 } | |
2087 if (it == operand_sizes.end()) { | |
2088 it = operand_sizes.find(T {instruction_class, | |
2089 ' ', operand.size}); | |
2090 } | |
2091 if (it == operand_sizes.end()) { | |
2092 it = operand_sizes.find(T {instruction_class, | |
2093 operand.source, ""}); | |
2094 } | |
2095 if (it == operand_sizes.end()) { | |
2096 it = operand_sizes.find(T {InstructionClass::kUnknown, | |
2097 ' ', operand.size}); | |
2098 } | |
2099 if (it == operand_sizes.end()) { | |
2100 fprintf(stderr, _("%s: error - can not determine operand size: %c%s" | |
2101 ), short_program_name, operand.source, operand.size.c_str()); | |
2102 exit(1); | |
2103 } else { | |
2104 fprintf(out_file, " @operand%zd_%s", &operand - &*operands.begin(), | |
2105 it->second); | |
2106 } | |
2107 static std::map<char, const char*> operand_type { | |
2108 { '1', "one" }, | |
2109 { 'a', "rax" }, | |
2110 { 'b', "ds_rbx" }, | |
2111 { 'c', "rcx" }, | |
2112 { 'd', "rdx" }, | |
2113 { 'i', "second_immediate" }, | |
2114 { 'o', "port_dx" }, | |
2115 { 't', "st" }, | |
2116 { 'B', "from_vex" }, | |
2117 { 'H', "from_vex" }, | |
2118 { 'I', "immediate" }, | |
2119 { 'O', "absolute_disp" }, | |
2120 { 'X', "ds_rsi" }, | |
2121 { 'Y', "es_rdi" } | |
2122 }; | |
2123 auto it2 = operand_type.find(operand.source); | |
2124 if (it2 != operand_type.end()) { | |
2125 fprintf(out_file, " @operand%zd_%s", &operand - &*operands.begin(), | |
2126 it2->second); | |
2127 } | |
2128 } | |
2129 } | |
2130 if (enabled(Actions::kParseOperandsStates)) { | |
2131 for (auto operand_it = operands.begin(); operand_it != operands.end(); +
+operand_it) { | |
2132 auto &operand = *operand_it; | |
2133 if (operand.read) { | |
2134 if (operand.write) { | |
2135 fprintf(out_file, " @operand%zd_readwrite", | |
2136 &operand - &*operands.begin()); | |
2137 } else { | |
2138 fprintf(out_file, " @operand%zd_read", | |
2139 &operand - &*operands.begin()); | |
2140 } | |
2141 } else { | |
2142 if (operand.write) { | |
2143 fprintf(out_file, " @operand%zd_write", | |
2144 &operand - &*operands.begin()); | |
2145 } else { | |
2146 fprintf(out_file, " @operand%zd_unused", | |
2147 &operand - &*operands.begin()); | |
2148 } | |
2149 } | |
2150 } | |
2151 } | |
2152 if (opcode_in_modrm) { | |
2153 fprintf(out_file, " any* &"); | |
2154 } | |
2155 } | |
2156 | |
2157 void print_immediate_arguments(void) { | |
2158 for (auto operand = operands.rbegin(); operand != operands.rend(); | |
2159 ++operand) { | |
2160 static const std::map<std::pair<InstructionClass, std::string>, | |
2161 const char*> immediate_sizes { | |
2162 { { InstructionClass::kDefault, "" }, "imm32" }, | |
2163 { { InstructionClass::kSize8, "" }, "imm8" }, | |
2164 { { InstructionClass::kData16, "" }, "imm16" }, | |
2165 { { InstructionClass::kRexW, "" }, "imm32" }, | |
2166 { { InstructionClass::kDefault, "2" }, "imm2" }, | |
2167 { { InstructionClass::kDefault, "b" }, "imm8" }, | |
2168 { { InstructionClass::kSize8, "b" }, "imm8" }, | |
2169 { { InstructionClass::kData16, "b" }, "imm8" }, | |
2170 { { InstructionClass::kRexW, "b" }, "imm8" }, | |
2171 { { InstructionClass::kDefault, "d" }, "imm32" }, | |
2172 { { InstructionClass::kRexW, "d" }, "imm32" }, | |
2173 { { InstructionClass::kDefault, "v" }, "imm32" }, | |
2174 { { InstructionClass::kData16, "v" }, "imm16" }, | |
2175 { { InstructionClass::kRexW, "v" }, "imm64" }, | |
2176 { { InstructionClass::kDefault, "w" }, "imm16" }, | |
2177 { { InstructionClass::kDefault, "z" }, "imm32" }, | |
2178 { { InstructionClass::kData16, "z" }, "imm16" }, | |
2179 { { InstructionClass::kRexW, "z" }, "imm32" } | |
2180 }; | |
2181 if (operand->source == 'i') { | |
2182 auto it = immediate_sizes.find({instruction_class, | |
2183 operand->size}); | |
2184 if (it == immediate_sizes.end()) { | |
2185 fprintf(stderr, _("%s: error - can not determine immediate size: %c" | |
2186 "%s"), short_program_name, operand->source, operand->size.c_str()); | |
2187 exit(1); | |
2188 } | |
2189 fprintf(out_file, " %sn2", it->second); | |
2190 } | |
2191 if (operand->source == 'I') { | |
2192 auto it = immediate_sizes.find({instruction_class, | |
2193 operand->size}); | |
2194 if (it == immediate_sizes.end()) { | |
2195 fprintf(stderr, _("%s: error - can not determine immediate size: %c" | |
2196 "%s"), short_program_name, operand->source, operand->size.c_str()); | |
2197 exit(1); | |
2198 } | |
2199 fprintf(out_file, " %s", it->second); | |
2200 } | |
2201 static const std::map<std::pair<InstructionClass, std::string>, | |
2202 const char *> jump_sizes { | |
2203 { { InstructionClass::kDefault, "b" }, "rel8" }, | |
2204 { { InstructionClass::kDefault, "d" }, "rel32" }, | |
2205 { { InstructionClass::kDefault, "w" }, "rel16" }, | |
2206 { { InstructionClass::kDefault, "z" }, "rel32" }, | |
2207 { { InstructionClass::kData16, "z" }, "rel16" }, | |
2208 { { InstructionClass::kRexW, "z" }, "rel32" }, | |
2209 }; | |
2210 if (operand->source == 'J') { | |
2211 auto it = jump_sizes.find({instruction_class, operand->size}); | |
2212 if (it == jump_sizes.end()) { | |
2213 fprintf(stderr, _("%s: error - can not determine jump size: %c%s"), | |
2214 short_program_name, operand->source, operand->size.c_str()); | |
2215 exit(1); | |
2216 } | |
2217 fprintf(out_file, " %s", it->second); | |
2218 } | |
2219 if (operand->source == 'L') { | |
2220 if (operands.size() == 4) { | |
2221 if (ia32_mode) { | |
2222 fprintf(out_file, " %s", chartest((c & 0x8f) == 0x00)); | |
2223 } else { | |
2224 fprintf(out_file, " %s", chartest((c & 0x0f) == 0x00)); | |
2225 } | |
2226 } | |
2227 if (enabled(Actions::kParseOperands)) { | |
2228 fprintf(out_file, " @operand%zd_from_is4", | |
2229 operands.rend() - operand - 1); | |
2230 } | |
2231 } | |
2232 if (operand->source == 'O') { | |
2233 if (ia32_mode) { | |
2234 fprintf(out_file, " disp32"); | |
2235 } else { | |
2236 fprintf(out_file, " disp64"); | |
2237 } | |
2238 } | |
2239 } | |
2240 for (auto prefix_it = required_prefixes.begin(); prefix_it != required_pre
fixes.end(); ++prefix_it) { | |
2241 auto &prefix = *prefix_it; | |
2242 if (prefix == "0xf0") { | |
2243 for (auto operand_it = operands.begin(); operand_it != operands.end();
++operand_it) { | |
2244 auto &operand = *operand_it; | |
2245 if (operand.source == 'C') { | |
2246 fprintf(out_file, " @not_lock_prefix%zd", | |
2247 &operand - &*operands.begin()); | |
2248 break; | |
2249 } | |
2250 } | |
2251 break; | |
2252 } | |
2253 } | |
2254 } | |
2255 | |
2256 void print_immediate_opcode(void) { | |
2257 auto print_opcode = false; | |
2258 for (auto opcode_it = opcodes.begin(); opcode_it != opcodes.end(); ++opcod
e_it) { | |
2259 auto &opcode = *opcode_it; | |
2260 if (opcode == "/") { | |
2261 print_opcode = true; | |
2262 } else if (print_opcode) { | |
2263 fprintf(out_file, " %s", opcode.c_str()); | |
2264 } | |
2265 } | |
2266 } | |
2267 }; | |
2268 | |
2269 void print_one_instruction_definition(void) { | |
2270 for (auto instruction_it = instructions.begin(); instruction_it != instructi
ons.end(); ++instruction_it) { | |
2271 auto &instruction = *instruction_it; | |
2272 MarkedInstruction(instruction).print_definition(); | |
2273 } | |
2274 } | |
2275 #if 1 | |
2276 /* We need GCC 4.7 to remove the following */ | |
2277 bool MarkedInstruction::first_delimeter = true; | |
2278 #endif | |
2279 } | |
2280 | |
2281 struct compare_action { | |
2282 const char* action; | |
2283 | |
2284 compare_action(const char* y) : action(y) { | |
2285 } | |
2286 | |
2287 bool operator()(const char* x) const { | |
2288 return !strcmp(x, action); | |
2289 } | |
2290 }; | |
2291 | |
2292 int main(int argc, char *argv[]) { | |
2293 setlocale(LC_ALL, ""); | |
2294 bindtextdomain("ncval", "."); | |
2295 textdomain("ncval"); | |
2296 | |
2297 /* basename(3) may change the passed argument thus we are using copy | |
2298 of argv[0]. This creates tiny memory leak but since we only do that | |
2299 once per program invocation it's contained. */ | |
2300 short_program_name = basename(strdup(argv[0])); | |
2301 | |
2302 for (;;) { | |
2303 int option_index; | |
2304 | |
2305 int option = getopt_long(argc, argv, "d:hm:o:v", | |
2306 kProgramOptions, &option_index); | |
2307 | |
2308 if (option == -1) { | |
2309 break; | |
2310 } | |
2311 | |
2312 switch (option) { | |
2313 #if 0 | |
2314 case 0: | |
2315 printf("option %s", kProgramOptions[option_index].name); | |
2316 if (optarg) | |
2317 printf(" with arg %s", optarg); | |
2318 printf("\n"); | |
2319 break; | |
2320 #endif | |
2321 case 'd': { | |
2322 for (auto action_to_disable = strtok(optarg, ","); | |
2323 action_to_disable; | |
2324 action_to_disable = strtok(NULL, ",")) { | |
2325 compare_action compare_with_action_to_disable(action_to_disable); | |
2326 auto action_number = std::find_if( | |
2327 kDisablableActionsList, | |
2328 kDisablableActionsList + arraysize(kDisablableActionsList), | |
2329 compare_with_action_to_disable); | |
2330 if (action_number != | |
2331 kDisablableActionsList + arraysize(kDisablableActionsList)) { | |
2332 disabled_actions[action_number - kDisablableActionsList] = true; | |
2333 } else { | |
2334 fprintf(stderr, _("%s: action “%s” is unknown\n"), | |
2335 short_program_name, action_to_disable); | |
2336 return 1; | |
2337 } | |
2338 } | |
2339 break; | |
2340 } | |
2341 case 'm': { | |
2342 if (!strcmp(optarg, "ia32")) { | |
2343 ia32_mode = true; | |
2344 } else if (!strcmp(optarg, "amd64")) { | |
2345 ia32_mode = false; | |
2346 } else { | |
2347 fprintf(stderr, _("%s: mode “%s” is unknown\n"), | |
2348 short_program_name, optarg); | |
2349 return 1; | |
2350 } | |
2351 break; | |
2352 } | |
2353 case 'o': | |
2354 out_file_name = optarg; | |
2355 break; | |
2356 case 'h': | |
2357 printf(gettext(kProgramHelp), short_program_name); | |
2358 break; | |
2359 case 'v': | |
2360 printf(gettext(kVersionHelp), short_program_name, kVersion); | |
2361 break; | |
2362 case '?': | |
2363 /* getopt_long already printed an error message. */ | |
2364 return 1; | |
2365 default: | |
2366 abort(); | |
2367 } | |
2368 } | |
2369 | |
2370 for (auto i = optind; i < argc; ++i) { | |
2371 load_instructions(argv[i]); | |
2372 } | |
2373 | |
2374 if (!(out_file = fopen(out_file_name, "w"))) { | |
2375 fprintf(stderr, _("%s: can not open “%s” file (%s)\n"), | |
2376 short_program_name, out_file_name, strerror(errno)); | |
2377 return 1; | |
2378 } else if (enabled(Actions::kInstructionName) || | |
2379 enabled(Actions::kParseOperands)) { | |
2380 auto const_name = static_cast<char *>(malloc(strlen(out_file_name) + 10)); | |
2381 strcpy(const_name, out_file_name); | |
2382 auto dot_position = strrchr(const_name, '.'); | |
2383 if (!dot_position) { | |
2384 dot_position = strrchr(const_name, '\0'); | |
2385 } | |
2386 strcpy(dot_position, "-consts.c"); | |
2387 if (!(const_file = fopen(const_name, "w"))) { | |
2388 fprintf(stderr, _("%s: can not open “%s” file (%s)\n"), | |
2389 short_program_name, const_name, strerror(errno)); | |
2390 return 1; | |
2391 } | |
2392 free(const_name); | |
2393 } | |
2394 | |
2395 if (enabled(Actions::kInstructionName) || | |
2396 enabled(Actions::kParseOperands)) { | |
2397 print_consts(); | |
2398 | |
2399 if (out_file == const_file) { | |
2400 for (auto i = 0; i < 80; ++i) { | |
2401 fputc('#', out_file); | |
2402 } | |
2403 fputc('\n', out_file); | |
2404 } | |
2405 } | |
2406 | |
2407 if (ia32_mode) { | |
2408 fprintf(out_file, "%%%%{\n" | |
2409 " machine decode_x86_32;\n" | |
2410 " alphtype unsigned char;\n" | |
2411 ""); | |
2412 } else { | |
2413 fprintf(out_file, "END(%%%%{\n" | |
2414 " machine decode_x86_64;\n" | |
2415 " alphtype unsigned char;\n" | |
2416 ""); | |
2417 } | |
2418 | |
2419 print_common_decoding(); | |
2420 | |
2421 if (enabled(Actions::kInstructionName)) { | |
2422 print_name_actions(); | |
2423 } | |
2424 | |
2425 fprintf(out_file, "\n one_instruction ="); | |
2426 | |
2427 print_one_instruction_definition(); | |
2428 | |
2429 fprintf(out_file, ");\n" | |
2430 "}%%%%\n" | |
2431 ""); | |
2432 return 0; | |
2433 } | |
OLD | NEW |