blob: 67dfcac0f27443d9b8c69f16a4318180c10a74e2 [file] [log] [blame]
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001/* assemble.c code generation for the Netwide Assembler
2 *
3 * The Netwide Assembler is copyright (C) 1996 Simon Tatham and
4 * Julian Hall. All rights reserved. The software is
Beroset095e6a22007-12-29 09:44:23 -05005 * redistributable under the license given in the file "LICENSE"
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00006 * distributed in the NASM archive.
7 *
8 * the actual codes (C syntax, i.e. octal):
9 * \0 - terminates the code. (Unless it's a literal of course.)
10 * \1, \2, \3 - that many literal bytes follow in the code stream
11 * \4, \6 - the POP/PUSH (respectively) codes for CS, DS, ES, SS
12 * (POP is never used for CS) depending on operand 0
13 * \5, \7 - the second byte of POP/PUSH codes for FS, GS, depending
14 * on operand 0
H. Peter Anvin7eb4a382007-09-17 15:49:30 -070015 * \10..\13 - a literal byte follows in the code stream, to be added
16 * to the register value of operand 0..3
17 * \14..\17 - a signed byte immediate operand, from operand 0..3
18 * \20..\23 - a byte immediate operand, from operand 0..3
19 * \24..\27 - an unsigned byte immediate operand, from operand 0..3
20 * \30..\33 - a word immediate operand, from operand 0..3
21 * \34..\37 - select between \3[0-3] and \4[0-3] depending on 16/32 bit
H. Peter Anvin3ba46772002-05-27 23:19:35 +000022 * assembly mode or the operand-size override on the operand
H. Peter Anvin7eb4a382007-09-17 15:49:30 -070023 * \40..\43 - a long immediate operand, from operand 0..3
24 * \44..\47 - select between \3[0-3], \4[0-3] and \5[4-7]
H. Peter Anvinde4b89b2007-10-01 15:41:25 -070025 * depending on the address size of the instruction.
H. Peter Anvin7eb4a382007-09-17 15:49:30 -070026 * \50..\53 - a byte relative operand, from operand 0..3
27 * \54..\57 - a qword immediate operand, from operand 0..3
28 * \60..\63 - a word relative operand, from operand 0..3
29 * \64..\67 - select between \6[0-3] and \7[0-3] depending on 16/32 bit
H. Peter Anvin17799b42002-05-21 03:31:21 +000030 * assembly mode or the operand-size override on the operand
H. Peter Anvin7eb4a382007-09-17 15:49:30 -070031 * \70..\73 - a long relative operand, from operand 0..3
32 * \74..\77 - a word constant, from the _segment_ part of operand 0..3
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000033 * \1ab - a ModRM, calculated on EA in operand a, with the spare
34 * field the register value of operand b.
H. Peter Anvin7eb4a382007-09-17 15:49:30 -070035 * \140..\143 - an immediate word or signed byte for operand 0..3
H. Peter Anvina30cc072007-11-18 21:55:26 -080036 * \144..\147 - or 2 (s-field) into opcode byte if operand 0..3
37 * is a signed byte rather than a word. Opcode byte follows.
H. Peter Anvin7eb4a382007-09-17 15:49:30 -070038 * \150..\153 - an immediate dword or signed byte for operand 0..3
H. Peter Anvina30cc072007-11-18 21:55:26 -080039 * \154..\157 - or 2 (s-field) into opcode byte if operand 0..3
H. Peter Anvin32cd4c22008-04-04 13:34:53 -070040 * is a signed byte rather than a dword. Opcode byte follows.
H. Peter Anvin401c07e2007-09-17 16:55:04 -070041 * \160..\163 - this instruction uses DREX rather than REX, with the
42 * OC0 field set to 0, and the dest field taken from
43 * operand 0..3.
44 * \164..\167 - this instruction uses DREX rather than REX, with the
45 * OC0 field set to 1, and the dest field taken from
46 * operand 0..3.
H. Peter Anvin401c07e2007-09-17 16:55:04 -070047 * \171 - placement of DREX suffix in the absence of an EA
H. Peter Anvind85d2502008-05-04 17:53:31 -070048 * \172\ab - the register number from operand a in bits 7..4, with
49 * the 4-bit immediate from operand b in bits 0..3.
H. Peter Anvind58656f2008-05-06 20:11:14 -070050 * \173\xab - the register number from operand a in bits 7..4, with
51 * the value b in bits 0..3.
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000052 * \2ab - a ModRM, calculated on EA in operand a, with the spare
53 * field equal to digit b.
H. Peter Anvin32cd4c22008-04-04 13:34:53 -070054 * \250..\253 - same as \150..\153, except warn if the 64-bit operand
55 * is not equal to the truncated and sign-extended 32-bit
56 * operand; used for 32-bit immediates in 64-bit mode.
H. Peter Anvind85d2502008-05-04 17:53:31 -070057 * \260..\263 - this instruction uses VEX rather than REX, with the
58 * V field taken from operand 0..3.
59 * \270 - this instruction uses VEX rather than REX, with the
60 * V field set to 1111b.
61 *
62 * VEX prefixes are followed by the sequence:
H. Peter Anvinaaa088f2008-05-12 11:13:41 -070063 * \mm\wlp where mm is the M field; and wlp is:
64 * 00 0ww lpp
H. Peter Anvind85d2502008-05-04 17:53:31 -070065 * ww = 0 for W = 0
66 * ww = 1 for W = 1
67 * ww = 2 for W used as REX.W
68 *
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000069 * \310 - indicates fixed 16-bit address size, i.e. optional 0x67.
70 * \311 - indicates fixed 32-bit address size, i.e. optional 0x67.
Keith Kanios48af1772007-08-17 07:37:52 +000071 * \312 - (disassembler only) marker on LOOP, LOOPxx instructions.
H. Peter Anvince2b3972007-05-30 22:21:11 +000072 * \313 - indicates fixed 64-bit address size, 0x67 invalid.
H. Peter Anvin23440102007-11-12 21:02:33 -080073 * \314 - (disassembler only) invalid with REX.B
74 * \315 - (disassembler only) invalid with REX.X
75 * \316 - (disassembler only) invalid with REX.R
76 * \317 - (disassembler only) invalid with REX.W
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000077 * \320 - indicates fixed 16-bit operand size, i.e. optional 0x66.
78 * \321 - indicates fixed 32-bit operand size, i.e. optional 0x66.
79 * \322 - indicates that this instruction is only valid when the
80 * operand size is the default (instruction to disassembler,
81 * generates no code in the assembler)
H. Peter Anvince2b3972007-05-30 22:21:11 +000082 * \323 - indicates fixed 64-bit operand size, REX on extensions only.
Keith Kaniosb7a89542007-04-12 02:40:54 +000083 * \324 - indicates 64-bit operand size requiring REX prefix.
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000084 * \330 - a literal byte follows in the code stream, to be added
85 * to the condition code value of the instruction.
Keith Kanios48af1772007-08-17 07:37:52 +000086 * \331 - instruction not valid with REP prefix. Hint for
H. Peter Anvinef7468f2002-04-30 20:57:59 +000087 * disassembler only; for SSE instructions.
H. Peter Anvincb9b6902007-09-12 21:58:51 -070088 * \332 - REP prefix (0xF2 byte) used as opcode extension.
89 * \333 - REP prefix (0xF3 byte) used as opcode extension.
Keith Kanios48af1772007-08-17 07:37:52 +000090 * \334 - LOCK prefix used instead of REX.R
H. Peter Anvincb9b6902007-09-12 21:58:51 -070091 * \335 - disassemble a rep (0xF3 byte) prefix as repe not rep.
Keith Kaniosb7a89542007-04-12 02:40:54 +000092 * \340 - reserve <operand 0> bytes of uninitialized storage.
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000093 * Operand 0 had better be a segmentless constant.
H. Peter Anvin62cb6062007-09-11 22:44:03 +000094 * \364 - operand-size prefix (0x66) not permitted
95 * \365 - address-size prefix (0x67) not permitted
96 * \366 - operand-size prefix (0x66) used as opcode extension
97 * \367 - address-size prefix (0x67) used as opcode extension
H. Peter Anvin788e6c12002-04-30 21:02:01 +000098 * \370,\371,\372 - match only if operand 0 meets byte jump criteria.
99 * 370 is used for Jcc, 371 is used for JMP.
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000100 * \373 - assemble 0x03 if bits==16, 0x05 if bits==32;
101 * used for conditional jump over longer jump
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000102 */
103
H. Peter Anvinfe501952007-10-02 21:53:51 -0700104#include "compiler.h"
105
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000106#include <stdio.h>
107#include <string.h>
Keith Kaniosb7a89542007-04-12 02:40:54 +0000108#include <inttypes.h>
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000109
110#include "nasm.h"
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000111#include "nasmlib.h"
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000112#include "assemble.h"
113#include "insns.h"
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000114#include "preproc.h"
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000115#include "regflags.c"
Keith Kaniosb7a89542007-04-12 02:40:54 +0000116#include "regvals.c"
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000117
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000118typedef struct {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000119 int sib_present; /* is a SIB byte necessary? */
120 int bytes; /* # of bytes of offset needed */
121 int size; /* lazy - this is sib+bytes+1 */
122 uint8_t modrm, sib, rex, rip; /* the bytes themselves */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000123} ea;
124
Keith Kaniosb7a89542007-04-12 02:40:54 +0000125static uint32_t cpu; /* cpu level received from nasm.c */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000126static efunc errfunc;
127static struct ofmt *outfmt;
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000128static ListGen *list;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000129
H. Peter Anvin3720f7b2008-05-12 11:00:50 -0700130static int64_t calcsize(int32_t, int64_t, int, insn *, const uint8_t *);
131static void gencode(int32_t, int64_t, int, insn *, const uint8_t *, int64_t);
H. Peter Anvin3360d792007-09-11 04:16:57 +0000132static int matches(const struct itemplate *, insn *, int bits);
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000133static int32_t regflag(const operand *);
134static int32_t regval(const operand *);
135static int rexflags(int, int32_t, int);
136static int op_rexflags(const operand *, int);
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700137static ea *process_ea(operand *, ea *, int, int, int, int32_t, int);
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700138static void add_asp(insn *, int);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000139
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700140static int has_prefix(insn * ins, enum prefix_pos pos, enum prefixes prefix)
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000141{
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700142 return ins->prefixes[pos] == prefix;
143}
144
145static void assert_no_prefix(insn * ins, enum prefix_pos pos)
146{
147 if (ins->prefixes[pos])
148 errfunc(ERR_NONFATAL, "invalid %s prefix",
149 prefix_name(ins->prefixes[pos]));
150}
151
152static const char *size_name(int size)
153{
154 switch (size) {
155 case 1:
156 return "byte";
157 case 2:
158 return "word";
159 case 4:
160 return "dword";
161 case 8:
162 return "qword";
163 case 10:
164 return "tword";
165 case 16:
166 return "oword";
167 default:
168 return "???";
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000169 }
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700170}
171
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700172static void warn_overflow(int size, int64_t data)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700173{
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700174 if (size < 8) {
Charles Craynedd462c82007-11-04 15:28:30 -0800175 int64_t lim = ((int64_t)1 << (size*8))-1;
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000176
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700177 if (data < ~lim || data > lim)
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700178 errfunc(ERR_WARNING | ERR_WARN_NOV,
179 "%s data exceeds bounds", size_name(size));
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700180 }
181}
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000182/*
183 * This routine wrappers the real output format's output routine,
184 * in order to pass a copy of the data off to the listing file
185 * generator at the same time.
186 */
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800187static void out(int64_t offset, int32_t segto, const void *data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800188 enum out_type type, uint64_t size,
189 int32_t segment, int32_t wrt)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000190{
Keith Kaniosb7a89542007-04-12 02:40:54 +0000191 static int32_t lineno = 0; /* static!!! */
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000192 static char *lnfname = NULL;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800193 uint8_t p[8];
H. Peter Anvineba20a72002-04-30 20:53:55 +0000194
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800195 if (type == OUT_ADDRESS && segment == NO_SEG && wrt == NO_SEG) {
196 /*
197 * This is a non-relocated address, and we're going to
198 * convert it into RAWDATA format.
199 */
200 uint8_t *q = p;
H. Peter Anvind1fb15c2007-11-13 09:37:59 -0800201
202 if (size > 8) {
203 errfunc(ERR_PANIC, "OUT_ADDRESS with size > 8");
204 return;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800205 }
H. Peter Anvind85d2502008-05-04 17:53:31 -0700206
H. Peter Anvind1fb15c2007-11-13 09:37:59 -0800207 WRITEADDR(q, *(int64_t *)data, size);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800208 data = p;
209 type = OUT_RAWDATA;
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000210 }
211
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800212 list->output(offset, data, type, size);
213
Frank Kotlerabebb082003-09-06 04:45:37 +0000214 /*
215 * this call to src_get determines when we call the
216 * debug-format-specific "linenum" function
217 * it updates lineno and lnfname to the current values
218 * returning 0 if "same as last time", -2 if lnfname
219 * changed, and the amount by which lineno changed,
220 * if it did. thus, these variables must be static
221 */
222
H. Peter Anvine2c80182005-01-15 22:15:51 +0000223 if (src_get(&lineno, &lnfname)) {
224 outfmt->current_dfmt->linenum(lnfname, lineno, segto);
H. Peter Anvince616072002-04-30 21:02:23 +0000225 }
H. Peter Anvineba20a72002-04-30 20:53:55 +0000226
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800227 outfmt->output(segto, data, type, size, segment, wrt);
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000228}
229
Charles Crayne5fbbc8c2007-11-07 19:03:46 -0800230static int jmp_match(int32_t segment, int64_t offset, int bits,
H. Peter Anvin3720f7b2008-05-12 11:00:50 -0700231 insn * ins, const uint8_t *code)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000232{
Charles Crayne5fbbc8c2007-11-07 19:03:46 -0800233 int64_t isize;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000234 uint8_t c = code[0];
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000235
H. Peter Anvine2c80182005-01-15 22:15:51 +0000236 if (c != 0370 && c != 0371)
237 return 0;
H. Peter Anvin788e6c12002-04-30 21:02:01 +0000238 if (ins->oprs[0].opflags & OPFLAG_FORWARD) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000239 if ((optimizing < 0 || (ins->oprs[0].type & STRICT))
240 && c == 0370)
241 return 1;
242 else
243 return (pass0 == 0); /* match a forward reference */
H. Peter Anvin788e6c12002-04-30 21:02:01 +0000244 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000245 isize = calcsize(segment, offset, bits, ins, code);
246 if (ins->oprs[0].segment != segment)
247 return 0;
248 isize = ins->oprs[0].offset - offset - isize; /* isize is now the delta */
249 if (isize >= -128L && isize <= 127L)
250 return 1; /* it is byte size */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000251
252 return 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000253}
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000254
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800255int64_t assemble(int32_t segment, int64_t offset, int bits, uint32_t cp,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000256 insn * instruction, struct ofmt *output, efunc error,
257 ListGen * listgen)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000258{
H. Peter Anvin3360d792007-09-11 04:16:57 +0000259 const struct itemplate *temp;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000260 int j;
261 int size_prob;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800262 int64_t insn_end;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000263 int32_t itimes;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800264 int64_t start = offset;
265 int64_t wsize = 0; /* size for DB etc. */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000266
H. Peter Anvine2c80182005-01-15 22:15:51 +0000267 errfunc = error; /* to pass to other functions */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000268 cpu = cp;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000269 outfmt = output; /* likewise */
270 list = listgen; /* and again */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000271
H. Peter Anvine2c80182005-01-15 22:15:51 +0000272 switch (instruction->opcode) {
273 case -1:
274 return 0;
275 case I_DB:
276 wsize = 1;
277 break;
278 case I_DW:
279 wsize = 2;
280 break;
281 case I_DD:
282 wsize = 4;
283 break;
284 case I_DQ:
285 wsize = 8;
286 break;
287 case I_DT:
288 wsize = 10;
289 break;
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700290 case I_DO:
291 wsize = 16;
292 break;
H. Peter Anvin16b0a332007-09-12 20:27:41 -0700293 default:
294 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000295 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000296
H. Peter Anvineba20a72002-04-30 20:53:55 +0000297 if (wsize) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000298 extop *e;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000299 int32_t t = instruction->times;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000300 if (t < 0)
301 errfunc(ERR_PANIC,
302 "instruction->times < 0 (%ld) in assemble()", t);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000303
H. Peter Anvine2c80182005-01-15 22:15:51 +0000304 while (t--) { /* repeat TIMES times */
305 for (e = instruction->eops; e; e = e->next) {
306 if (e->type == EOT_DB_NUMBER) {
307 if (wsize == 1) {
308 if (e->segment != NO_SEG)
309 errfunc(ERR_NONFATAL,
310 "one-byte relocation attempted");
311 else {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000312 uint8_t out_byte = e->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000313 out(offset, segment, &out_byte,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800314 OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000315 }
Keith Kanios61ff53c2007-04-14 18:54:52 +0000316 } else if (wsize > 8) {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700317 errfunc(ERR_NONFATAL, "integer supplied to a DT or DO"
Keith Kanios61ff53c2007-04-14 18:54:52 +0000318 " instruction");
H. Peter Anvine2c80182005-01-15 22:15:51 +0000319 } else
320 out(offset, segment, &e->offset,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800321 OUT_ADDRESS, wsize, e->segment, e->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000322 offset += wsize;
323 } else if (e->type == EOT_DB_STRING) {
324 int align;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000325
H. Peter Anvine2c80182005-01-15 22:15:51 +0000326 out(offset, segment, e->stringval,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800327 OUT_RAWDATA, e->stringlen, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000328 align = e->stringlen % wsize;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000329
H. Peter Anvine2c80182005-01-15 22:15:51 +0000330 if (align) {
331 align = wsize - align;
H. Peter Anvind387b8c2008-01-27 16:39:26 -0800332 out(offset, segment,
333 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0",
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800334 OUT_RAWDATA, align, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000335 }
336 offset += e->stringlen + align;
337 }
338 }
339 if (t > 0 && t == instruction->times - 1) {
340 /*
341 * Dummy call to list->output to give the offset to the
342 * listing module.
343 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800344 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000345 list->uplevel(LIST_TIMES);
346 }
347 }
348 if (instruction->times > 1)
349 list->downlevel(LIST_TIMES);
350 return offset - start;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000351 }
352
H. Peter Anvine2c80182005-01-15 22:15:51 +0000353 if (instruction->opcode == I_INCBIN) {
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000354 static char fname[FILENAME_MAX];
H. Peter Anvine2c80182005-01-15 22:15:51 +0000355 FILE *fp;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000356 int32_t len;
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000357 char *prefix = "", *combine;
358 char **pPrevPath = NULL;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000359
H. Peter Anvine2c80182005-01-15 22:15:51 +0000360 len = FILENAME_MAX - 1;
361 if (len > instruction->eops->stringlen)
362 len = instruction->eops->stringlen;
363 strncpy(fname, instruction->eops->stringval, len);
364 fname[len] = '\0';
H. Peter Anvineba20a72002-04-30 20:53:55 +0000365
Keith Kaniosb7a89542007-04-12 02:40:54 +0000366 while (1) { /* added by alexfru: 'incbin' uses include paths */
H. Peter Anvine2c80182005-01-15 22:15:51 +0000367 combine = nasm_malloc(strlen(prefix) + len + 1);
368 strcpy(combine, prefix);
369 strcat(combine, fname);
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000370
H. Peter Anvine2c80182005-01-15 22:15:51 +0000371 if ((fp = fopen(combine, "rb")) != NULL) {
372 nasm_free(combine);
373 break;
374 }
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000375
H. Peter Anvine2c80182005-01-15 22:15:51 +0000376 nasm_free(combine);
377 pPrevPath = pp_get_include_path_ptr(pPrevPath);
378 if (pPrevPath == NULL)
379 break;
380 prefix = *pPrevPath;
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000381 }
382
383 if (fp == NULL)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000384 error(ERR_NONFATAL, "`incbin': unable to open file `%s'",
385 fname);
386 else if (fseek(fp, 0L, SEEK_END) < 0)
387 error(ERR_NONFATAL, "`incbin': unable to seek on file `%s'",
388 fname);
389 else {
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000390 static char buf[2048];
Keith Kaniosb7a89542007-04-12 02:40:54 +0000391 int32_t t = instruction->times;
392 int32_t base = 0;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000393
H. Peter Anvine2c80182005-01-15 22:15:51 +0000394 len = ftell(fp);
395 if (instruction->eops->next) {
396 base = instruction->eops->next->offset;
397 len -= base;
398 if (instruction->eops->next->next &&
399 len > instruction->eops->next->next->offset)
400 len = instruction->eops->next->next->offset;
401 }
402 /*
403 * Dummy call to list->output to give the offset to the
404 * listing module.
405 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800406 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000407 list->uplevel(LIST_INCBIN);
408 while (t--) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000409 int32_t l;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000410
H. Peter Anvine2c80182005-01-15 22:15:51 +0000411 fseek(fp, base, SEEK_SET);
412 l = len;
413 while (l > 0) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000414 int32_t m =
Charles Crayne192d5b52007-10-18 19:02:42 -0700415 fread(buf, 1, (l > (int32_t) sizeof(buf) ? (int32_t) sizeof(buf) : l),
H. Peter Anvine2c80182005-01-15 22:15:51 +0000416 fp);
417 if (!m) {
418 /*
419 * This shouldn't happen unless the file
420 * actually changes while we are reading
421 * it.
422 */
423 error(ERR_NONFATAL,
424 "`incbin': unexpected EOF while"
425 " reading file `%s'", fname);
426 t = 0; /* Try to exit cleanly */
427 break;
428 }
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800429 out(offset, segment, buf, OUT_RAWDATA, m,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000430 NO_SEG, NO_SEG);
431 l -= m;
432 }
433 }
434 list->downlevel(LIST_INCBIN);
435 if (instruction->times > 1) {
436 /*
437 * Dummy call to list->output to give the offset to the
438 * listing module.
439 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800440 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000441 list->uplevel(LIST_TIMES);
442 list->downlevel(LIST_TIMES);
443 }
444 fclose(fp);
445 return instruction->times * len;
446 }
447 return 0; /* if we're here, there's an error */
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000448 }
449
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700450 /* Check to see if we need an address-size prefix */
451 add_asp(instruction, bits);
452
H. Peter Anvin6867acc2007-10-10 14:58:45 -0700453 size_prob = false;
H. Peter Anvin70653092007-10-19 14:42:29 -0700454
455 for (temp = nasm_instructions[instruction->opcode]; temp->opcode != -1; temp++){
Keith Kaniosb7a89542007-04-12 02:40:54 +0000456 int m = matches(temp, instruction, bits);
H. Peter Anvin70653092007-10-19 14:42:29 -0700457
H. Peter Anvine2c80182005-01-15 22:15:51 +0000458 if (m == 99)
459 m += jmp_match(segment, offset, bits, instruction, temp->code);
H. Peter Anvineba20a72002-04-30 20:53:55 +0000460
H. Peter Anvine2c80182005-01-15 22:15:51 +0000461 if (m == 100) { /* matches! */
H. Peter Anvin3720f7b2008-05-12 11:00:50 -0700462 const uint8_t *codes = temp->code;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800463 int64_t insn_size = calcsize(segment, offset, bits,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000464 instruction, codes);
465 itimes = instruction->times;
466 if (insn_size < 0) /* shouldn't be, on pass two */
467 error(ERR_PANIC, "errors made it through from pass one");
468 else
469 while (itimes--) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700470 for (j = 0; j < MAXPREFIX; j++) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000471 uint8_t c = 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000472 switch (instruction->prefixes[j]) {
473 case P_LOCK:
474 c = 0xF0;
475 break;
476 case P_REPNE:
477 case P_REPNZ:
478 c = 0xF2;
479 break;
480 case P_REPE:
481 case P_REPZ:
482 case P_REP:
483 c = 0xF3;
484 break;
485 case R_CS:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000486 if (bits == 64) {
487 error(ERR_WARNING,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800488 "cs segment base generated, but will be ignored in 64-bit mode");
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000489 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000490 c = 0x2E;
491 break;
492 case R_DS:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000493 if (bits == 64) {
494 error(ERR_WARNING,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800495 "ds segment base generated, but will be ignored in 64-bit mode");
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000496 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000497 c = 0x3E;
498 break;
499 case R_ES:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000500 if (bits == 64) {
501 error(ERR_WARNING,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800502 "es segment base generated, but will be ignored in 64-bit mode");
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000503 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000504 c = 0x26;
505 break;
506 case R_FS:
507 c = 0x64;
508 break;
509 case R_GS:
510 c = 0x65;
511 break;
512 case R_SS:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000513 if (bits == 64) {
514 error(ERR_WARNING,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800515 "ss segment base generated, but will be ignored in 64-bit mode");
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000516 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000517 c = 0x36;
518 break;
519 case R_SEGR6:
520 case R_SEGR7:
521 error(ERR_NONFATAL,
522 "segr6 and segr7 cannot be used as prefixes");
523 break;
524 case P_A16:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000525 if (bits == 64) {
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000526 error(ERR_NONFATAL,
527 "16-bit addressing is not supported "
528 "in 64-bit mode");
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700529 } else if (bits != 16)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000530 c = 0x67;
531 break;
532 case P_A32:
533 if (bits != 32)
534 c = 0x67;
535 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700536 case P_A64:
537 if (bits != 64) {
538 error(ERR_NONFATAL,
539 "64-bit addressing is only supported "
540 "in 64-bit mode");
541 }
542 break;
543 case P_ASP:
544 c = 0x67;
545 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000546 case P_O16:
547 if (bits != 16)
548 c = 0x66;
549 break;
550 case P_O32:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000551 if (bits == 16)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000552 c = 0x66;
553 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700554 case P_O64:
555 /* REX.W */
556 break;
557 case P_OSP:
558 c = 0x66;
559 break;
560 case P_none:
561 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000562 default:
563 error(ERR_PANIC, "invalid instruction prefix");
564 }
565 if (c != 0) {
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800566 out(offset, segment, &c, OUT_RAWDATA, 1,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000567 NO_SEG, NO_SEG);
568 offset++;
569 }
H. Peter Anvin70653092007-10-19 14:42:29 -0700570 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000571 insn_end = offset + insn_size;
572 gencode(segment, offset, bits, instruction, codes,
573 insn_end);
574 offset += insn_size;
575 if (itimes > 0 && itimes == instruction->times - 1) {
576 /*
577 * Dummy call to list->output to give the offset to the
578 * listing module.
579 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800580 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000581 list->uplevel(LIST_TIMES);
582 }
583 }
584 if (instruction->times > 1)
585 list->downlevel(LIST_TIMES);
586 return offset - start;
587 } else if (m > 0 && m > size_prob) {
588 size_prob = m;
589 }
Keith Kaniosb7a89542007-04-12 02:40:54 +0000590// temp++;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000591 }
H. Peter Anvineba20a72002-04-30 20:53:55 +0000592
H. Peter Anvine2c80182005-01-15 22:15:51 +0000593 if (temp->opcode == -1) { /* didn't match any instruction */
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000594 switch (size_prob) {
595 case 1:
596 error(ERR_NONFATAL, "operation size not specified");
597 break;
598 case 2:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000599 error(ERR_NONFATAL, "mismatch in operand sizes");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000600 break;
601 case 3:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000602 error(ERR_NONFATAL, "no instruction for this cpu level");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000603 break;
604 case 4:
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000605 error(ERR_NONFATAL, "instruction not supported in 64-bit mode");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000606 break;
607 default:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000608 error(ERR_NONFATAL,
609 "invalid combination of opcode and operands");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000610 break;
611 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000612 }
613 return 0;
614}
615
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800616int64_t insn_size(int32_t segment, int64_t offset, int bits, uint32_t cp,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000617 insn * instruction, efunc error)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000618{
H. Peter Anvin3360d792007-09-11 04:16:57 +0000619 const struct itemplate *temp;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000620
H. Peter Anvine2c80182005-01-15 22:15:51 +0000621 errfunc = error; /* to pass to other functions */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000622 cpu = cp;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000623
624 if (instruction->opcode == -1)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000625 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000626
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700627 if (instruction->opcode == I_DB || instruction->opcode == I_DW ||
628 instruction->opcode == I_DD || instruction->opcode == I_DQ ||
629 instruction->opcode == I_DT || instruction->opcode == I_DO) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000630 extop *e;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000631 int32_t isize, osize, wsize = 0; /* placate gcc */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000632
H. Peter Anvine2c80182005-01-15 22:15:51 +0000633 isize = 0;
634 switch (instruction->opcode) {
635 case I_DB:
636 wsize = 1;
637 break;
638 case I_DW:
639 wsize = 2;
640 break;
641 case I_DD:
642 wsize = 4;
643 break;
644 case I_DQ:
645 wsize = 8;
646 break;
647 case I_DT:
648 wsize = 10;
649 break;
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700650 case I_DO:
651 wsize = 16;
652 break;
H. Peter Anvin16b0a332007-09-12 20:27:41 -0700653 default:
654 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000655 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000656
H. Peter Anvine2c80182005-01-15 22:15:51 +0000657 for (e = instruction->eops; e; e = e->next) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000658 int32_t align;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000659
H. Peter Anvine2c80182005-01-15 22:15:51 +0000660 osize = 0;
661 if (e->type == EOT_DB_NUMBER)
662 osize = 1;
663 else if (e->type == EOT_DB_STRING)
664 osize = e->stringlen;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000665
H. Peter Anvine2c80182005-01-15 22:15:51 +0000666 align = (-osize) % wsize;
667 if (align < 0)
668 align += wsize;
669 isize += osize + align;
670 }
671 return isize * instruction->times;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000672 }
673
H. Peter Anvine2c80182005-01-15 22:15:51 +0000674 if (instruction->opcode == I_INCBIN) {
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000675 char fname[FILENAME_MAX];
H. Peter Anvine2c80182005-01-15 22:15:51 +0000676 FILE *fp;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000677 int32_t len;
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000678 char *prefix = "", *combine;
679 char **pPrevPath = NULL;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000680
H. Peter Anvine2c80182005-01-15 22:15:51 +0000681 len = FILENAME_MAX - 1;
682 if (len > instruction->eops->stringlen)
683 len = instruction->eops->stringlen;
684 strncpy(fname, instruction->eops->stringval, len);
685 fname[len] = '\0';
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000686
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700687 /* added by alexfru: 'incbin' uses include paths */
688 while (1) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000689 combine = nasm_malloc(strlen(prefix) + len + 1);
690 strcpy(combine, prefix);
691 strcat(combine, fname);
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000692
H. Peter Anvine2c80182005-01-15 22:15:51 +0000693 if ((fp = fopen(combine, "rb")) != NULL) {
694 nasm_free(combine);
695 break;
696 }
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000697
H. Peter Anvine2c80182005-01-15 22:15:51 +0000698 nasm_free(combine);
699 pPrevPath = pp_get_include_path_ptr(pPrevPath);
700 if (pPrevPath == NULL)
701 break;
702 prefix = *pPrevPath;
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000703 }
704
705 if (fp == NULL)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000706 error(ERR_NONFATAL, "`incbin': unable to open file `%s'",
707 fname);
708 else if (fseek(fp, 0L, SEEK_END) < 0)
709 error(ERR_NONFATAL, "`incbin': unable to seek on file `%s'",
710 fname);
711 else {
712 len = ftell(fp);
713 fclose(fp);
714 if (instruction->eops->next) {
715 len -= instruction->eops->next->offset;
716 if (instruction->eops->next->next &&
717 len > instruction->eops->next->next->offset) {
718 len = instruction->eops->next->next->offset;
719 }
720 }
721 return instruction->times * len;
722 }
723 return 0; /* if we're here, there's an error */
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000724 }
725
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700726 /* Check to see if we need an address-size prefix */
727 add_asp(instruction, bits);
728
Keith Kaniosb7a89542007-04-12 02:40:54 +0000729 for (temp = nasm_instructions[instruction->opcode]; temp->opcode != -1; temp++) {
730 int m = matches(temp, instruction, bits);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000731 if (m == 99)
732 m += jmp_match(segment, offset, bits, instruction, temp->code);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000733
H. Peter Anvine2c80182005-01-15 22:15:51 +0000734 if (m == 100) {
735 /* we've matched an instruction. */
Charles Crayne5fbbc8c2007-11-07 19:03:46 -0800736 int64_t isize;
H. Peter Anvin3720f7b2008-05-12 11:00:50 -0700737 const uint8_t *codes = temp->code;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000738 int j;
739
740 isize = calcsize(segment, offset, bits, instruction, codes);
741 if (isize < 0)
742 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700743 for (j = 0; j < MAXPREFIX; j++) {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700744 switch (instruction->prefixes[j]) {
745 case P_A16:
746 if (bits != 16)
747 isize++;
748 break;
749 case P_A32:
750 if (bits != 32)
751 isize++;
752 break;
753 case P_O16:
754 if (bits != 16)
755 isize++;
756 break;
757 case P_O32:
758 if (bits == 16)
759 isize++;
760 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700761 case P_A64:
762 case P_O64:
763 case P_none:
764 break;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700765 default:
766 isize++;
767 break;
768 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000769 }
770 return isize * instruction->times;
771 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000772 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000773 return -1; /* didn't match any instruction */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000774}
775
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700776static bool possible_sbyte(insn * ins, int op)
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000777{
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700778 return !(ins->forw_ref && ins->oprs[op].opflags) &&
H. Peter Anvine2c80182005-01-15 22:15:51 +0000779 optimizing >= 0 &&
780 !(ins->oprs[op].type & STRICT) &&
781 ins->oprs[op].wrt == NO_SEG && ins->oprs[op].segment == NO_SEG;
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000782}
783
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700784/* check that opn[op] is a signed byte of size 16 or 32 */
785static bool is_sbyte16(insn * ins, int op)
786{
787 int16_t v;
788
789 if (!possible_sbyte(ins, op))
790 return false;
791
792 v = ins->oprs[op].offset;
793 return v >= -128 && v <= 127;
794}
795
796static bool is_sbyte32(insn * ins, int op)
797{
798 int32_t v;
799
800 if (!possible_sbyte(ins, op))
801 return false;
802
803 v = ins->oprs[op].offset;
804 return v >= -128 && v <= 127;
805}
806
807/* check that opn[op] is a signed byte of size 32; warn if this is not
808 the original value when extended to 64 bits */
809static bool is_sbyte64(insn * ins, int op)
810{
811 int64_t v64;
812 int32_t v32;
813
814 /* dead in the water on forward reference or External */
815 if (!possible_sbyte(ins, op))
816 return false;
817
818 v64 = ins->oprs[op].offset;
819 v32 = (int32_t)v64;
820
821 warn_overflow(32, v64);
822
823 return v32 >= -128 && v32 <= 127;
824}
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800825static int64_t calcsize(int32_t segment, int64_t offset, int bits,
H. Peter Anvin3720f7b2008-05-12 11:00:50 -0700826 insn * ins, const uint8_t *codes)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000827{
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800828 int64_t length = 0;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000829 uint8_t c;
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000830 int rex_mask = ~0;
H. Peter Anvin839eca22007-10-29 23:12:47 -0700831 struct operand *opx;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000832
H. Peter Anvine3917fc2007-11-01 14:53:32 -0700833 ins->rex = 0; /* Ensure REX is reset */
834
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700835 if (ins->prefixes[PPS_OSIZE] == P_O64)
836 ins->rex |= REX_W;
837
H. Peter Anvine2c80182005-01-15 22:15:51 +0000838 (void)segment; /* Don't warn that this parameter is unused */
839 (void)offset; /* Don't warn that this parameter is unused */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000840
H. Peter Anvin839eca22007-10-29 23:12:47 -0700841 while (*codes) {
842 c = *codes++;
843 opx = &ins->oprs[c & 3];
844 switch (c) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000845 case 01:
846 case 02:
847 case 03:
848 codes += c, length += c;
849 break;
850 case 04:
851 case 05:
852 case 06:
853 case 07:
854 length++;
855 break;
856 case 010:
857 case 011:
858 case 012:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700859 case 013:
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000860 ins->rex |=
H. Peter Anvin839eca22007-10-29 23:12:47 -0700861 op_rexflags(opx, REX_B|REX_H|REX_P|REX_W);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000862 codes++, length++;
863 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000864 case 014:
865 case 015:
866 case 016:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700867 case 017:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000868 length++;
869 break;
870 case 020:
871 case 021:
872 case 022:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700873 case 023:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000874 length++;
875 break;
876 case 024:
877 case 025:
878 case 026:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700879 case 027:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000880 length++;
881 break;
882 case 030:
883 case 031:
884 case 032:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700885 case 033:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000886 length += 2;
887 break;
888 case 034:
889 case 035:
890 case 036:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700891 case 037:
H. Peter Anvin839eca22007-10-29 23:12:47 -0700892 if (opx->type & (BITS16 | BITS32 | BITS64))
893 length += (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000894 else
895 length += (bits == 16) ? 2 : 4;
896 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000897 case 040:
898 case 041:
899 case 042:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700900 case 043:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000901 length += 4;
902 break;
903 case 044:
904 case 045:
905 case 046:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700906 case 047:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700907 length += ins->addr_size >> 3;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000908 break;
909 case 050:
910 case 051:
911 case 052:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700912 case 053:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000913 length++;
914 break;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000915 case 054:
916 case 055:
917 case 056:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700918 case 057:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000919 length += 8; /* MOV reg64/imm */
920 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000921 case 060:
922 case 061:
923 case 062:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700924 case 063:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000925 length += 2;
926 break;
927 case 064:
928 case 065:
929 case 066:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700930 case 067:
H. Peter Anvin839eca22007-10-29 23:12:47 -0700931 if (opx->type & (BITS16 | BITS32 | BITS64))
932 length += (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000933 else
934 length += (bits == 16) ? 2 : 4;
935 break;
936 case 070:
937 case 071:
938 case 072:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700939 case 073:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000940 length += 4;
941 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700942 case 074:
943 case 075:
944 case 076:
945 case 077:
946 length += 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000947 break;
948 case 0140:
949 case 0141:
950 case 0142:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700951 case 0143:
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700952 length += is_sbyte16(ins, c & 3) ? 1 : 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000953 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000954 case 0144:
955 case 0145:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700956 case 0146:
957 case 0147:
H. Peter Anvina30cc072007-11-18 21:55:26 -0800958 codes++;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000959 length++;
960 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700961 case 0150:
962 case 0151:
963 case 0152:
964 case 0153:
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700965 length += is_sbyte32(ins, c & 3) ? 1 : 4;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700966 break;
967 case 0154:
968 case 0155:
969 case 0156:
970 case 0157:
H. Peter Anvina30cc072007-11-18 21:55:26 -0800971 codes++;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700972 length++;
973 break;
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700974 case 0160:
975 case 0161:
976 case 0162:
977 case 0163:
978 length++;
979 ins->rex |= REX_D;
H. Peter Anvind85d2502008-05-04 17:53:31 -0700980 ins->drexdst = regval(opx);
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700981 break;
982 case 0164:
983 case 0165:
984 case 0166:
985 case 0167:
986 length++;
987 ins->rex |= REX_D|REX_OC;
H. Peter Anvind85d2502008-05-04 17:53:31 -0700988 ins->drexdst = regval(opx);
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700989 break;
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700990 case 0171:
991 break;
H. Peter Anvind85d2502008-05-04 17:53:31 -0700992 case 0172:
H. Peter Anvind58656f2008-05-06 20:11:14 -0700993 case 0173:
H. Peter Anvind85d2502008-05-04 17:53:31 -0700994 codes++;
995 length++;
996 break;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700997 case 0250:
998 case 0251:
999 case 0252:
1000 case 0253:
1001 length += is_sbyte64(ins, c & 3) ? 1 : 4;
1002 break;
H. Peter Anvind85d2502008-05-04 17:53:31 -07001003 case 0260:
1004 case 0261:
1005 case 0262:
1006 case 0263:
1007 length += 2;
1008 ins->rex |= REX_V;
1009 ins->drexdst = regval(opx);
1010 ins->vex_m = *codes++;
1011 ins->vex_wlp = *codes++;
1012 break;
1013 case 0270:
1014 length += 2;
1015 ins->rex |= REX_V;
1016 ins->drexdst = 0;
1017 ins->vex_m = *codes++;
1018 ins->vex_wlp = *codes++;
1019 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001020 case 0300:
1021 case 0301:
H. Peter Anvin70653092007-10-19 14:42:29 -07001022 case 0302:
1023 case 0303:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001024 break;
1025 case 0310:
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07001026 if (bits == 64)
1027 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001028 length += (bits != 16) && !has_prefix(ins, PPS_ASIZE, P_A16);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001029 break;
1030 case 0311:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001031 length += (bits != 32) && !has_prefix(ins, PPS_ASIZE, P_A32);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001032 break;
1033 case 0312:
H. Peter Anvin70653092007-10-19 14:42:29 -07001034 break;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001035 case 0313:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001036 if (bits != 64 || has_prefix(ins, PPS_ASIZE, P_A16) ||
1037 has_prefix(ins, PPS_ASIZE, P_A32))
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07001038 return -1;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001039 break;
H. Peter Anvin23440102007-11-12 21:02:33 -08001040 case 0314:
1041 case 0315:
1042 case 0316:
1043 case 0317:
1044 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001045 case 0320:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001046 length += (bits != 16);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001047 break;
1048 case 0321:
1049 length += (bits == 16);
1050 break;
1051 case 0322:
1052 break;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001053 case 0323:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001054 rex_mask &= ~REX_W;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001055 break;
1056 case 0324:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001057 ins->rex |= REX_W;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001058 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001059 case 0330:
1060 codes++, length++;
1061 break;
1062 case 0331:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001063 break;
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001064 case 0332:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001065 case 0333:
1066 length++;
1067 break;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001068 case 0334:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001069 ins->rex |= REX_L;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001070 break;
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001071 case 0335:
1072 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001073 case 0340:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001074 if (ins->oprs[0].segment != NO_SEG)
1075 errfunc(ERR_NONFATAL, "attempt to reserve non-constant"
1076 " quantity of BSS space");
1077 else
H. Peter Anvin428fd672007-11-15 10:25:52 -08001078 length += ins->oprs[0].offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001079 break;
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001080 case 0364:
1081 case 0365:
1082 break;
Keith Kanios48af1772007-08-17 07:37:52 +00001083 case 0366:
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001084 case 0367:
1085 length++;
1086 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001087 case 0370:
1088 case 0371:
1089 case 0372:
1090 break;
1091 case 0373:
1092 length++;
1093 break;
1094 default: /* can't do it by 'case' statements */
1095 if (c >= 0100 && c <= 0277) { /* it's an EA */
1096 ea ea_data;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001097 int rfield;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001098 int32_t rflags;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001099 ea_data.rex = 0; /* Ensure ea.REX is initially 0 */
H. Peter Anvin70653092007-10-19 14:42:29 -07001100
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001101 if (c <= 0177) {
1102 /* pick rfield from operand b */
1103 rflags = regflag(&ins->oprs[c & 7]);
1104 rfield = regvals[ins->oprs[c & 7].basereg];
1105 } else {
1106 rflags = 0;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001107 rfield = c & 7;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001108 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00001109
H. Peter Anvine2c80182005-01-15 22:15:51 +00001110 if (!process_ea
Keith Kaniosb7a89542007-04-12 02:40:54 +00001111 (&ins->oprs[(c >> 3) & 7], &ea_data, bits,
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001112 ins->addr_size, rfield, rflags, ins->forw_ref)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001113 errfunc(ERR_NONFATAL, "invalid effective address");
1114 return -1;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001115 } else {
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001116 ins->rex |= ea_data.rex;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001117 length += ea_data.size;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001118 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001119 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001120 errfunc(ERR_PANIC, "internal instruction table corrupt"
1121 ": instruction code 0x%02X given", c);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001122 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001123 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001124 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001125
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001126 ins->rex &= rex_mask;
H. Peter Anvin70653092007-10-19 14:42:29 -07001127
H. Peter Anvind85d2502008-05-04 17:53:31 -07001128 if (ins->rex & REX_V) {
1129 int bad32 = REX_R|REX_W|REX_X|REX_B;
1130
1131 if (ins->rex & REX_H) {
1132 errfunc(ERR_NONFATAL, "cannot use high register in vex instruction");
1133 return -1;
1134 }
1135 switch (ins->vex_wlp & 030) {
1136 case 000:
1137 ins->rex &= ~REX_W;
1138 break;
1139 case 010:
1140 ins->rex |= REX_W;
1141 bad32 &= ~REX_W;
1142 break;
1143 default:
1144 /* Follow REX_W */
1145 break;
1146 }
1147
1148 if (bits != 64 && ((ins->rex & bad32) || ins->drexdst > 7)) {
1149 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1150 return -1;
1151 }
1152 if (ins->vex_m != 1 || (ins->rex & (REX_W|REX_R|REX_B)))
1153 length += 3;
1154 else
1155 length += 2;
1156 } else if (ins->rex & REX_D) {
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001157 if (ins->rex & REX_H) {
1158 errfunc(ERR_NONFATAL, "cannot use high register in drex instruction");
1159 return -1;
1160 }
H. Peter Anvind85d2502008-05-04 17:53:31 -07001161 if (bits != 64 && ((ins->rex & (REX_R|REX_W|REX_X|REX_B)) ||
H. Peter Anvincf5180a2007-09-17 17:25:27 -07001162 ins->drexdst > 7)) {
1163 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1164 return -1;
1165 }
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001166 length++;
1167 } else if (ins->rex & REX_REAL) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001168 if (ins->rex & REX_H) {
1169 errfunc(ERR_NONFATAL, "cannot use high register in rex instruction");
1170 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001171 } else if (bits == 64) {
1172 length++;
1173 } else if ((ins->rex & REX_L) &&
1174 !(ins->rex & (REX_P|REX_W|REX_X|REX_B)) &&
1175 cpu >= IF_X86_64) {
1176 /* LOCK-as-REX.R */
1177 assert_no_prefix(ins, PPS_LREP);
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001178 length++;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001179 } else {
H. Peter Anvincf5180a2007-09-17 17:25:27 -07001180 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1181 return -1;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001182 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00001183 }
1184
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001185 return length;
1186}
Keith Kaniosb7a89542007-04-12 02:40:54 +00001187
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001188#define EMIT_REX() \
H. Peter Anvind85d2502008-05-04 17:53:31 -07001189 if (!(ins->rex & (REX_D|REX_V)) && (ins->rex & REX_REAL) && (bits == 64)) { \
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001190 ins->rex = (ins->rex & REX_REAL)|REX_P; \
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001191 out(offset, segment, &ins->rex, OUT_RAWDATA, 1, NO_SEG, NO_SEG); \
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001192 ins->rex = 0; \
1193 offset += 1; \
1194 }
1195
Charles Crayne1f8bc4c2007-11-06 18:27:23 -08001196static void gencode(int32_t segment, int64_t offset, int bits,
H. Peter Anvin3720f7b2008-05-12 11:00:50 -07001197 insn * ins, const uint8_t *codes, int64_t insn_end)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001198{
Keith Kaniosa6dfa782007-04-13 16:47:53 +00001199 static char condval[] = { /* conditional opcodes */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001200 0x7, 0x3, 0x2, 0x6, 0x2, 0x4, 0xF, 0xD, 0xC, 0xE, 0x6, 0x2,
1201 0x3, 0x7, 0x3, 0x5, 0xE, 0xC, 0xD, 0xF, 0x1, 0xB, 0x9, 0x5,
1202 0x0, 0xA, 0xA, 0xB, 0x8, 0x4
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001203 };
Keith Kaniosb7a89542007-04-12 02:40:54 +00001204 uint8_t c;
1205 uint8_t bytes[4];
Charles Crayne1f8bc4c2007-11-06 18:27:23 -08001206 int64_t size;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001207 int64_t data;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001208 struct operand *opx;
H. Peter Anvin70653092007-10-19 14:42:29 -07001209
H. Peter Anvin839eca22007-10-29 23:12:47 -07001210 while (*codes) {
1211 c = *codes++;
1212 opx = &ins->oprs[c & 3];
1213 switch (c) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001214 case 01:
1215 case 02:
1216 case 03:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001217 EMIT_REX();
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001218 out(offset, segment, codes, OUT_RAWDATA, c, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001219 codes += c;
1220 offset += c;
1221 break;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001222
H. Peter Anvine2c80182005-01-15 22:15:51 +00001223 case 04:
1224 case 06:
1225 switch (ins->oprs[0].basereg) {
1226 case R_CS:
1227 bytes[0] = 0x0E + (c == 0x04 ? 1 : 0);
1228 break;
1229 case R_DS:
1230 bytes[0] = 0x1E + (c == 0x04 ? 1 : 0);
1231 break;
1232 case R_ES:
1233 bytes[0] = 0x06 + (c == 0x04 ? 1 : 0);
1234 break;
1235 case R_SS:
1236 bytes[0] = 0x16 + (c == 0x04 ? 1 : 0);
1237 break;
1238 default:
1239 errfunc(ERR_PANIC,
1240 "bizarre 8086 segment register received");
1241 }
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001242 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001243 offset++;
1244 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001245
H. Peter Anvine2c80182005-01-15 22:15:51 +00001246 case 05:
1247 case 07:
1248 switch (ins->oprs[0].basereg) {
1249 case R_FS:
1250 bytes[0] = 0xA0 + (c == 0x05 ? 1 : 0);
1251 break;
1252 case R_GS:
1253 bytes[0] = 0xA8 + (c == 0x05 ? 1 : 0);
1254 break;
1255 default:
1256 errfunc(ERR_PANIC,
1257 "bizarre 386 segment register received");
1258 }
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001259 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001260 offset++;
1261 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001262
H. Peter Anvine2c80182005-01-15 22:15:51 +00001263 case 010:
1264 case 011:
1265 case 012:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001266 case 013:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001267 EMIT_REX();
H. Peter Anvin839eca22007-10-29 23:12:47 -07001268 bytes[0] = *codes++ + ((regval(opx)) & 7);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001269 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001270 offset += 1;
1271 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001272
H. Peter Anvine2c80182005-01-15 22:15:51 +00001273 case 014:
1274 case 015:
1275 case 016:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001276 case 017:
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001277 /* XXX: warns for legitimate optimizer actions */
H. Peter Anvin839eca22007-10-29 23:12:47 -07001278 if (opx->offset < -128 || opx->offset > 127) {
H. Peter Anvin72c64372008-01-08 22:13:48 -08001279 errfunc(ERR_WARNING | ERR_WARN_NOV,
1280 "signed byte value exceeds bounds");
H. Peter Anvine2c80182005-01-15 22:15:51 +00001281 }
H. Peter Anvineba20a72002-04-30 20:53:55 +00001282
H. Peter Anvin839eca22007-10-29 23:12:47 -07001283 if (opx->segment != NO_SEG) {
1284 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001285 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001286 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001287 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001288 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001289 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001290 NO_SEG);
1291 }
1292 offset += 1;
1293 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001294
H. Peter Anvine2c80182005-01-15 22:15:51 +00001295 case 020:
1296 case 021:
1297 case 022:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001298 case 023:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001299 if (opx->offset < -256 || opx->offset > 255) {
H. Peter Anvin72c64372008-01-08 22:13:48 -08001300 errfunc(ERR_WARNING | ERR_WARN_NOV,
1301 "byte value exceeds bounds");
H. Peter Anvine2c80182005-01-15 22:15:51 +00001302 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001303 if (opx->segment != NO_SEG) {
1304 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001305 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001306 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001307 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001308 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001309 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001310 NO_SEG);
1311 }
1312 offset += 1;
1313 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001314
H. Peter Anvine2c80182005-01-15 22:15:51 +00001315 case 024:
1316 case 025:
1317 case 026:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001318 case 027:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001319 if (opx->offset < 0 || opx->offset > 255)
H. Peter Anvin72c64372008-01-08 22:13:48 -08001320 errfunc(ERR_WARNING | ERR_WARN_NOV,
1321 "unsigned byte value exceeds bounds");
H. Peter Anvin839eca22007-10-29 23:12:47 -07001322 if (opx->segment != NO_SEG) {
1323 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001324 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001325 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001326 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001327 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001328 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001329 NO_SEG);
1330 }
1331 offset += 1;
1332 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001333
H. Peter Anvine2c80182005-01-15 22:15:51 +00001334 case 030:
1335 case 031:
1336 case 032:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001337 case 033:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001338 data = opx->offset;
1339 if (opx->segment == NO_SEG && opx->wrt == NO_SEG)
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001340 warn_overflow(2, data);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001341 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001342 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001343 offset += 2;
1344 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001345
H. Peter Anvine2c80182005-01-15 22:15:51 +00001346 case 034:
1347 case 035:
1348 case 036:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001349 case 037:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001350 if (opx->type & (BITS16 | BITS32))
1351 size = (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001352 else
1353 size = (bits == 16) ? 2 : 4;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001354 data = opx->offset;
1355 if (opx->segment == NO_SEG && opx->wrt == NO_SEG)
H. Peter Anvin10e27272007-10-29 22:56:08 -07001356 warn_overflow(size, data);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001357 out(offset, segment, &data, OUT_ADDRESS, size,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001358 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001359 offset += size;
1360 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001361
H. Peter Anvine2c80182005-01-15 22:15:51 +00001362 case 040:
1363 case 041:
1364 case 042:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001365 case 043:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001366 data = opx->offset;
H. Peter Anvin72c64372008-01-08 22:13:48 -08001367 if (opx->segment == NO_SEG && opx->wrt == NO_SEG)
1368 warn_overflow(4, data);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001369 out(offset, segment, &data, OUT_ADDRESS, 4,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001370 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001371 offset += 4;
1372 break;
H. Peter Anvin3ba46772002-05-27 23:19:35 +00001373
H. Peter Anvine2c80182005-01-15 22:15:51 +00001374 case 044:
1375 case 045:
1376 case 046:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001377 case 047:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001378 data = opx->offset;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001379 size = ins->addr_size >> 3;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001380 if (opx->segment == NO_SEG &&
1381 opx->wrt == NO_SEG)
H. Peter Anvin10e27272007-10-29 22:56:08 -07001382 warn_overflow(size, data);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001383 out(offset, segment, &data, OUT_ADDRESS, size,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001384 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001385 offset += size;
1386 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001387
H. Peter Anvine2c80182005-01-15 22:15:51 +00001388 case 050:
1389 case 051:
1390 case 052:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001391 case 053:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001392 if (opx->segment != segment)
H. Peter Anvine2c80182005-01-15 22:15:51 +00001393 errfunc(ERR_NONFATAL,
1394 "short relative jump outside segment");
H. Peter Anvin839eca22007-10-29 23:12:47 -07001395 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001396 if (data > 127 || data < -128)
1397 errfunc(ERR_NONFATAL, "short jump is out of range");
1398 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001399 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001400 offset += 1;
1401 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001402
Keith Kaniosb7a89542007-04-12 02:40:54 +00001403 case 054:
1404 case 055:
1405 case 056:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001406 case 057:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001407 data = (int64_t)opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001408 out(offset, segment, &data, OUT_ADDRESS, 8,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001409 opx->segment, opx->wrt);
Keith Kaniosb7a89542007-04-12 02:40:54 +00001410 offset += 8;
1411 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001412
H. Peter Anvine2c80182005-01-15 22:15:51 +00001413 case 060:
1414 case 061:
1415 case 062:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001416 case 063:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001417 if (opx->segment != segment) {
1418 data = opx->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001419 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001420 OUT_REL2ADR, insn_end - offset,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001421 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001422 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001423 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001424 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001425 OUT_ADDRESS, 2, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001426 }
1427 offset += 2;
1428 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001429
H. Peter Anvine2c80182005-01-15 22:15:51 +00001430 case 064:
1431 case 065:
1432 case 066:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001433 case 067:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001434 if (opx->type & (BITS16 | BITS32 | BITS64))
1435 size = (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001436 else
1437 size = (bits == 16) ? 2 : 4;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001438 if (opx->segment != segment) {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001439 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001440 out(offset, segment, &data,
1441 size == 2 ? OUT_REL2ADR : OUT_REL4ADR,
1442 insn_end - offset, opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001443 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001444 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001445 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001446 OUT_ADDRESS, size, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001447 }
1448 offset += size;
1449 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001450
H. Peter Anvine2c80182005-01-15 22:15:51 +00001451 case 070:
1452 case 071:
1453 case 072:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001454 case 073:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001455 if (opx->segment != segment) {
1456 data = opx->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001457 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001458 OUT_REL4ADR, insn_end - offset,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001459 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001460 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001461 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001462 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001463 OUT_ADDRESS, 4, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001464 }
1465 offset += 4;
1466 break;
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001467
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001468 case 074:
1469 case 075:
1470 case 076:
1471 case 077:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001472 if (opx->segment == NO_SEG)
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001473 errfunc(ERR_NONFATAL, "value referenced by FAR is not"
1474 " relocatable");
1475 data = 0L;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001476 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001477 outfmt->segbase(1 + opx->segment),
1478 opx->wrt);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001479 offset += 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001480 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001481
H. Peter Anvine2c80182005-01-15 22:15:51 +00001482 case 0140:
1483 case 0141:
1484 case 0142:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001485 case 0143:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001486 data = opx->offset;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001487 if (is_sbyte16(ins, c & 3)) {
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001488 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001489 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001490 NO_SEG);
1491 offset++;
1492 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001493 if (opx->segment == NO_SEG &&
1494 opx->wrt == NO_SEG)
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001495 warn_overflow(2, data);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001496 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001497 opx->segment, opx->wrt);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001498 offset += 2;
1499 }
1500 break;
1501
1502 case 0144:
1503 case 0145:
1504 case 0146:
1505 case 0147:
1506 EMIT_REX();
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001507 bytes[0] = *codes++;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001508 if (is_sbyte16(ins, c & 3))
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001509 bytes[0] |= 2; /* s-bit */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001510 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001511 offset++;
1512 break;
1513
1514 case 0150:
1515 case 0151:
1516 case 0152:
1517 case 0153:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001518 data = opx->offset;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001519 if (is_sbyte32(ins, c & 3)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001520 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001521 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001522 NO_SEG);
1523 offset++;
1524 } else {
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001525 out(offset, segment, &data, OUT_ADDRESS, 4,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001526 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001527 offset += 4;
1528 }
1529 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001530
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001531 case 0154:
1532 case 0155:
1533 case 0156:
1534 case 0157:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001535 EMIT_REX();
H. Peter Anvine2c80182005-01-15 22:15:51 +00001536 bytes[0] = *codes++;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001537 if (is_sbyte32(ins, c & 3))
H. Peter Anvine2c80182005-01-15 22:15:51 +00001538 bytes[0] |= 2; /* s-bit */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001539 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001540 offset++;
1541 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001542
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001543 case 0160:
1544 case 0161:
1545 case 0162:
1546 case 0163:
1547 case 0164:
1548 case 0165:
1549 case 0166:
1550 case 0167:
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001551 break;
1552
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001553 case 0171:
1554 bytes[0] =
1555 (ins->drexdst << 4) |
1556 (ins->rex & REX_OC ? 0x08 : 0) |
1557 (ins->rex & (REX_R|REX_X|REX_B));
1558 ins->rex = 0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001559 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001560 offset++;
1561 break;
1562
H. Peter Anvind85d2502008-05-04 17:53:31 -07001563 case 0172:
1564 c = *codes++;
1565 opx = &ins->oprs[c >> 3];
1566 bytes[0] = regvals[opx->basereg] << 4;
1567 opx = &ins->oprs[c & 7];
1568 if (opx->segment != NO_SEG || opx->wrt != NO_SEG) {
1569 errfunc(ERR_NONFATAL,
1570 "non-absolute expression not permitted as argument %d",
1571 c & 7);
1572 } else {
1573 if (opx->offset & ~15) {
1574 errfunc(ERR_WARNING | ERR_WARN_NOV,
1575 "four-bit argument exceeds bounds");
1576 }
1577 bytes[0] |= opx->offset & 15;
1578 }
1579 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1580 offset++;
1581 break;
1582
H. Peter Anvind58656f2008-05-06 20:11:14 -07001583 case 0173:
1584 c = *codes++;
1585 opx = &ins->oprs[c >> 4];
1586 bytes[0] = regvals[opx->basereg] << 4;
1587 bytes[0] |= c & 15;
1588 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1589 offset++;
1590 break;
1591
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001592 case 0250:
1593 case 0251:
1594 case 0252:
1595 case 0253:
1596 data = opx->offset;
1597 /* is_sbyte32() is right here, we have already warned */
1598 if (is_sbyte32(ins, c & 3)) {
1599 bytes[0] = data;
1600 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
1601 NO_SEG);
1602 offset++;
1603 } else {
1604 out(offset, segment, &data, OUT_ADDRESS, 4,
1605 opx->segment, opx->wrt);
1606 offset += 4;
1607 }
1608 break;
1609
H. Peter Anvind85d2502008-05-04 17:53:31 -07001610 case 0260:
1611 case 0261:
1612 case 0262:
1613 case 0263:
1614 case 0270:
1615 codes += 2;
1616 if (ins->vex_m != 1 || (ins->rex & (REX_W|REX_X|REX_B))) {
1617 bytes[0] = 0xc4;
H. Peter Anvin4d2c38c2008-05-04 23:15:13 -07001618 bytes[1] = ins->vex_m | ((~ins->rex & 7) << 5);
H. Peter Anvind85d2502008-05-04 17:53:31 -07001619 bytes[2] = ((ins->rex & REX_W) << (7-3)) |
H. Peter Anvin4d2c38c2008-05-04 23:15:13 -07001620 ((~ins->drexdst & 15)<< 3) | (ins->vex_wlp & 07);
H. Peter Anvind85d2502008-05-04 17:53:31 -07001621 out(offset, segment, &bytes, OUT_RAWDATA, 3, NO_SEG, NO_SEG);
1622 offset += 3;
1623 } else {
1624 bytes[0] = 0xc5;
H. Peter Anvin4d2c38c2008-05-04 23:15:13 -07001625 bytes[1] = ((~ins->rex & REX_R) << (7-2)) |
1626 ((~ins->drexdst & 15) << 3) | (ins->vex_wlp & 07);
H. Peter Anvind85d2502008-05-04 17:53:31 -07001627 out(offset, segment, &bytes, OUT_RAWDATA, 2, NO_SEG, NO_SEG);
1628 offset += 2;
1629 }
1630 break;
1631
H. Peter Anvine2c80182005-01-15 22:15:51 +00001632 case 0300:
1633 case 0301:
1634 case 0302:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001635 case 0303:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001636 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001637
H. Peter Anvine2c80182005-01-15 22:15:51 +00001638 case 0310:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001639 if (bits == 32 && !has_prefix(ins, PPS_ASIZE, P_A16)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001640 *bytes = 0x67;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001641 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001642 offset += 1;
1643 } else
1644 offset += 0;
1645 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001646
H. Peter Anvine2c80182005-01-15 22:15:51 +00001647 case 0311:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001648 if (bits != 32 && !has_prefix(ins, PPS_ASIZE, P_A32)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001649 *bytes = 0x67;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001650 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001651 offset += 1;
1652 } else
1653 offset += 0;
1654 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001655
H. Peter Anvine2c80182005-01-15 22:15:51 +00001656 case 0312:
1657 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001658
Keith Kaniosb7a89542007-04-12 02:40:54 +00001659 case 0313:
1660 ins->rex = 0;
1661 break;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07001662
H. Peter Anvin23440102007-11-12 21:02:33 -08001663 case 0314:
1664 case 0315:
1665 case 0316:
1666 case 0317:
1667 break;
1668
H. Peter Anvine2c80182005-01-15 22:15:51 +00001669 case 0320:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001670 if (bits != 16) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001671 *bytes = 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001672 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001673 offset += 1;
1674 } else
1675 offset += 0;
1676 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001677
H. Peter Anvine2c80182005-01-15 22:15:51 +00001678 case 0321:
1679 if (bits == 16) {
1680 *bytes = 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001681 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001682 offset += 1;
1683 } else
1684 offset += 0;
1685 break;
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001686
H. Peter Anvine2c80182005-01-15 22:15:51 +00001687 case 0322:
H. Peter Anvin70653092007-10-19 14:42:29 -07001688 case 0323:
1689 break;
1690
Keith Kaniosb7a89542007-04-12 02:40:54 +00001691 case 0324:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001692 ins->rex |= REX_W;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001693 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001694
H. Peter Anvine2c80182005-01-15 22:15:51 +00001695 case 0330:
1696 *bytes = *codes++ ^ condval[ins->condition];
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001697 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001698 offset += 1;
1699 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001700
H. Peter Anvine2c80182005-01-15 22:15:51 +00001701 case 0331:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001702 break;
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001703
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001704 case 0332:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001705 case 0333:
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001706 *bytes = c - 0332 + 0xF2;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001707 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001708 offset += 1;
1709 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001710
Keith Kanios48af1772007-08-17 07:37:52 +00001711 case 0334:
1712 if (ins->rex & REX_R) {
1713 *bytes = 0xF0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001714 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
Keith Kanios48af1772007-08-17 07:37:52 +00001715 offset += 1;
1716 }
1717 ins->rex &= ~(REX_L|REX_R);
1718 break;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001719
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001720 case 0335:
1721 break;
1722
H. Peter Anvine2c80182005-01-15 22:15:51 +00001723 case 0340:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001724 if (ins->oprs[0].segment != NO_SEG)
1725 errfunc(ERR_PANIC, "non-constant BSS size in pass two");
1726 else {
H. Peter Anvin428fd672007-11-15 10:25:52 -08001727 int64_t size = ins->oprs[0].offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001728 if (size > 0)
1729 out(offset, segment, NULL,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001730 OUT_RESERVE, size, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001731 offset += size;
1732 }
1733 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001734
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001735 case 0364:
1736 case 0365:
1737 break;
1738
Keith Kanios48af1772007-08-17 07:37:52 +00001739 case 0366:
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001740 case 0367:
1741 *bytes = c - 0366 + 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001742 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
Keith Kanios48af1772007-08-17 07:37:52 +00001743 offset += 1;
1744 break;
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001745
H. Peter Anvine2c80182005-01-15 22:15:51 +00001746 case 0370:
1747 case 0371:
1748 case 0372:
1749 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001750
H. Peter Anvine2c80182005-01-15 22:15:51 +00001751 case 0373:
1752 *bytes = bits == 16 ? 3 : 5;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001753 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001754 offset += 1;
1755 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001756
H. Peter Anvine2c80182005-01-15 22:15:51 +00001757 default: /* can't do it by 'case' statements */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001758 if (c >= 0100 && c <= 0277) { /* it's an EA */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001759 ea ea_data;
1760 int rfield;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001761 int32_t rflags;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001762 uint8_t *p;
1763 int32_t s;
H. Peter Anvin70653092007-10-19 14:42:29 -07001764
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001765 if (c <= 0177) {
1766 /* pick rfield from operand b */
1767 rflags = regflag(&ins->oprs[c & 7]);
1768 rfield = regvals[ins->oprs[c & 7].basereg];
1769 } else {
1770 /* rfield is constant */
1771 rflags = 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001772 rfield = c & 7;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001773 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001774
1775 if (!process_ea
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001776 (&ins->oprs[(c >> 3) & 7], &ea_data, bits,
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001777 ins->addr_size, rfield, rflags, ins->forw_ref)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001778 errfunc(ERR_NONFATAL, "invalid effective address");
1779 }
H. Peter Anvin70653092007-10-19 14:42:29 -07001780
Charles Crayne7e975552007-11-03 22:06:13 -07001781
H. Peter Anvine2c80182005-01-15 22:15:51 +00001782 p = bytes;
1783 *p++ = ea_data.modrm;
1784 if (ea_data.sib_present)
1785 *p++ = ea_data.sib;
1786
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001787 /* DREX suffixes come between the SIB and the displacement */
1788 if (ins->rex & REX_D) {
1789 *p++ =
1790 (ins->drexdst << 4) |
1791 (ins->rex & REX_OC ? 0x08 : 0) |
1792 (ins->rex & (REX_R|REX_X|REX_B));
1793 ins->rex = 0;
1794 }
1795
H. Peter Anvine2c80182005-01-15 22:15:51 +00001796 s = p - bytes;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001797 out(offset, segment, bytes, OUT_RAWDATA, s, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001798
1799 switch (ea_data.bytes) {
1800 case 0:
1801 break;
1802 case 1:
1803 if (ins->oprs[(c >> 3) & 7].segment != NO_SEG) {
1804 data = ins->oprs[(c >> 3) & 7].offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001805 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001806 ins->oprs[(c >> 3) & 7].segment,
1807 ins->oprs[(c >> 3) & 7].wrt);
1808 } else {
1809 *bytes = ins->oprs[(c >> 3) & 7].offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001810 out(offset, segment, bytes, OUT_RAWDATA, 1,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001811 NO_SEG, NO_SEG);
1812 }
1813 s++;
1814 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001815 case 8:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001816 case 2:
1817 case 4:
1818 data = ins->oprs[(c >> 3) & 7].offset;
Charles Crayne7e975552007-11-03 22:06:13 -07001819 warn_overflow(ea_data.bytes, data);
H. Peter Anvind0b0d282007-09-28 17:17:20 -07001820 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001821 ea_data.rip ? OUT_REL4ADR : OUT_ADDRESS,
1822 ea_data.bytes,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001823 ins->oprs[(c >> 3) & 7].segment,
1824 ins->oprs[(c >> 3) & 7].wrt);
1825 s += ea_data.bytes;
1826 break;
1827 }
1828 offset += s;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001829 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001830 errfunc(ERR_PANIC, "internal instruction table corrupt"
1831 ": instruction code 0x%02X given", c);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001832 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001833 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001834 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001835}
1836
H. Peter Anvin0ec60e62007-07-07 01:59:52 +00001837static int32_t regflag(const operand * o)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001838{
1839 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1840 errfunc(ERR_PANIC, "invalid operand passed to regflag()");
1841 }
1842 return reg_flags[o->basereg];
1843}
1844
H. Peter Anvin5b0e3ec2007-07-07 02:01:08 +00001845static int32_t regval(const operand * o)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001846{
H. Peter Anvine2c80182005-01-15 22:15:51 +00001847 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1848 errfunc(ERR_PANIC, "invalid operand passed to regval()");
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001849 }
H. Peter Anvin232badb2002-06-06 02:41:20 +00001850 return regvals[o->basereg];
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001851}
1852
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001853static int op_rexflags(const operand * o, int mask)
1854{
1855 int32_t flags;
1856 int val;
1857
1858 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1859 errfunc(ERR_PANIC, "invalid operand passed to op_rexflags()");
1860 }
1861
1862 flags = reg_flags[o->basereg];
1863 val = regvals[o->basereg];
1864
1865 return rexflags(val, flags, mask);
1866}
1867
1868static int rexflags(int val, int32_t flags, int mask)
1869{
1870 int rex = 0;
1871
1872 if (val >= 8)
1873 rex |= REX_B|REX_X|REX_R;
1874 if (flags & BITS64)
1875 rex |= REX_W;
1876 if (!(REG_HIGH & ~flags)) /* AH, CH, DH, BH */
1877 rex |= REX_H;
1878 else if (!(REG8 & ~flags) && val >= 4) /* SPL, BPL, SIL, DIL */
1879 rex |= REX_P;
1880
1881 return rex & mask;
1882}
1883
H. Peter Anvin3360d792007-09-11 04:16:57 +00001884static int matches(const struct itemplate *itemp, insn * instruction, int bits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001885{
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001886 int i, size[MAX_OPERANDS], asize, oprs, ret;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001887
1888 ret = 100;
1889
1890 /*
1891 * Check the opcode
1892 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001893 if (itemp->opcode != instruction->opcode)
1894 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001895
1896 /*
1897 * Count the operands
1898 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001899 if (itemp->operands != instruction->operands)
1900 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001901
1902 /*
1903 * Check that no spurious colons or TOs are present
1904 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001905 for (i = 0; i < itemp->operands; i++)
1906 if (instruction->oprs[i].type & ~itemp->opd[i] & (COLON | TO))
1907 return 0;
H. Peter Anvin70653092007-10-19 14:42:29 -07001908
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001909 /*
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001910 * Process size flags
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001911 */
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001912 if (itemp->flags & IF_ARMASK) {
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001913 memset(size, 0, sizeof size);
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001914
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001915 i = ((itemp->flags & IF_ARMASK) >> IF_ARSHFT) - 1;
1916
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001917 switch (itemp->flags & IF_SMASK) {
1918 case IF_SB:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001919 size[i] = BITS8;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001920 break;
1921 case IF_SW:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001922 size[i] = BITS16;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001923 break;
1924 case IF_SD:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001925 size[i] = BITS32;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001926 break;
1927 case IF_SQ:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001928 size[i] = BITS64;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001929 break;
H. Peter Anvin41c9f6f2007-09-18 13:01:32 -07001930 case IF_SO:
1931 size[i] = BITS128;
1932 break;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001933 case IF_SZ:
1934 switch (bits) {
1935 case 16:
1936 size[i] = BITS16;
1937 break;
1938 case 32:
1939 size[i] = BITS32;
1940 break;
1941 case 64:
1942 size[i] = BITS64;
1943 break;
1944 }
1945 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001946 default:
1947 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001948 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001949 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001950 asize = 0;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001951 switch (itemp->flags & IF_SMASK) {
1952 case IF_SB:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001953 asize = BITS8;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001954 break;
1955 case IF_SW:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001956 asize = BITS16;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001957 break;
1958 case IF_SD:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001959 asize = BITS32;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001960 break;
1961 case IF_SQ:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001962 asize = BITS64;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001963 break;
H. Peter Anvin41c9f6f2007-09-18 13:01:32 -07001964 case IF_SO:
1965 asize = BITS128;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001966 break;
1967 case IF_SZ:
1968 switch (bits) {
1969 case 16:
1970 asize = BITS16;
1971 break;
1972 case 32:
1973 asize = BITS32;
1974 break;
1975 case 64:
1976 asize = BITS64;
1977 break;
1978 }
H. Peter Anvin41c9f6f2007-09-18 13:01:32 -07001979 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001980 default:
1981 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001982 }
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001983 for (i = 0; i < MAX_OPERANDS; i++)
1984 size[i] = asize;
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001985 }
H. Peter Anvin70653092007-10-19 14:42:29 -07001986
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001987 /*
1988 * Check that the operand flags all match up
1989 */
1990 for (i = 0; i < itemp->operands; i++) {
1991 int32_t type = instruction->oprs[i].type;
1992 if (!(type & SIZE_MASK))
1993 type |= size[i];
H. Peter Anvind85d2502008-05-04 17:53:31 -07001994
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001995 if (itemp->opd[i] & SAME_AS) {
1996 int j = itemp->opd[i] & ~SAME_AS;
1997 if (type != instruction->oprs[j].type ||
1998 instruction->oprs[i].basereg != instruction->oprs[j].basereg)
1999 return 0;
2000 } else if (itemp->opd[i] & ~type ||
2001 ((itemp->opd[i] & SIZE_MASK) &&
2002 ((itemp->opd[i] ^ type) & SIZE_MASK))) {
2003 if ((itemp->opd[i] & ~type & ~SIZE_MASK) ||
2004 (type & SIZE_MASK))
2005 return 0;
2006 else
2007 return 1;
2008 }
2009 }
2010
2011 /*
2012 * Check operand sizes
2013 */
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002014 if (itemp->flags & (IF_SM | IF_SM2)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002015 oprs = (itemp->flags & IF_SM2 ? 2 : itemp->operands);
2016 asize = 0;
2017 for (i = 0; i < oprs; i++) {
2018 if ((asize = itemp->opd[i] & SIZE_MASK) != 0) {
2019 int j;
2020 for (j = 0; j < oprs; j++)
2021 size[j] = asize;
2022 break;
2023 }
2024 }
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002025 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002026 oprs = itemp->operands;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002027 }
2028
Keith Kaniosb7a89542007-04-12 02:40:54 +00002029 for (i = 0; i < itemp->operands; i++) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002030 if (!(itemp->opd[i] & SIZE_MASK) &&
2031 (instruction->oprs[i].type & SIZE_MASK & ~size[i]))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002032 return 2;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002033 }
2034
H. Peter Anvinaf535c12002-04-30 20:59:21 +00002035 /*
2036 * Check template is okay at the set cpu level
2037 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002038 if (((itemp->flags & IF_PLEVEL) > cpu))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002039 return 3;
H. Peter Anvin70653092007-10-19 14:42:29 -07002040
Keith Kaniosb7a89542007-04-12 02:40:54 +00002041 /*
2042 * Check if instruction is available in long mode
2043 */
2044 if ((itemp->flags & IF_NOLONG) && (bits == 64))
2045 return 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002046
H. Peter Anvinaf535c12002-04-30 20:59:21 +00002047 /*
2048 * Check if special handling needed for Jumps
2049 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002050 if ((uint8_t)(itemp->code[0]) >= 0370)
H. Peter Anvine2c80182005-01-15 22:15:51 +00002051 return 99;
2052
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002053 return ret;
2054}
2055
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002056static ea *process_ea(operand * input, ea * output, int bits,
2057 int addrbits, int rfield, int32_t rflags, int forw_ref)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002058{
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002059 output->rip = false;
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00002060
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002061 /* REX flags for the rfield operand */
2062 output->rex |= rexflags(rfield, rflags, REX_R|REX_P|REX_W|REX_H);
2063
Keith Kaniosb7a89542007-04-12 02:40:54 +00002064 if (!(REGISTER & ~input->type)) { /* register direct */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002065 int i;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002066 int32_t f;
2067
2068 if (input->basereg < EXPR_REG_START /* Verify as Register */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002069 || input->basereg >= REG_ENUM_LIMIT)
H. Peter Anvine2c80182005-01-15 22:15:51 +00002070 return NULL;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002071 f = regflag(input);
Keith Kaniosb7a89542007-04-12 02:40:54 +00002072 i = regvals[input->basereg];
Keith Kaniosb7a89542007-04-12 02:40:54 +00002073
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002074 if (REG_EA & ~f)
2075 return NULL; /* Invalid EA register */
H. Peter Anvin70653092007-10-19 14:42:29 -07002076
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002077 output->rex |= op_rexflags(input, REX_B|REX_P|REX_W|REX_H);
2078
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002079 output->sib_present = false; /* no SIB necessary */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002080 output->bytes = 0; /* no offset necessary either */
2081 output->modrm = 0xC0 | ((rfield & 7) << 3) | (i & 7);
H. Peter Anvine2c80182005-01-15 22:15:51 +00002082 } else { /* it's a memory reference */
2083 if (input->basereg == -1
2084 && (input->indexreg == -1 || input->scale == 0)) {
2085 /* it's a pure offset */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002086 if (bits == 64 && (~input->type & IP_REL)) {
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002087 int scale, index, base;
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002088 output->sib_present = true;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002089 scale = 0;
2090 index = 4;
2091 base = 5;
2092 output->sib = (scale << 6) | (index << 3) | base;
2093 output->bytes = 4;
2094 output->modrm = 4 | ((rfield & 7) << 3);
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002095 output->rip = false;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002096 } else {
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002097 output->sib_present = false;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002098 output->bytes = (addrbits != 16 ? 4 : 2);
2099 output->modrm = (addrbits != 16 ? 5 : 6) | ((rfield & 7) << 3);
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002100 output->rip = bits == 64;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002101 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00002102 } else { /* it's an indirection */
2103 int i = input->indexreg, b = input->basereg, s = input->scale;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002104 int32_t o = input->offset, seg = input->segment;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002105 int hb = input->hintbase, ht = input->hinttype;
2106 int t;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002107 int it, bt;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002108 int32_t ix, bx; /* register flags */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002109
H. Peter Anvine2c80182005-01-15 22:15:51 +00002110 if (s == 0)
2111 i = -1; /* make this easy, at least */
H. Peter Anvin70653092007-10-19 14:42:29 -07002112
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002113 if (i >= EXPR_REG_START && i < REG_ENUM_LIMIT) {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002114 it = regvals[i];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002115 ix = reg_flags[i];
2116 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002117 it = -1;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002118 ix = 0;
2119 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002120
H. Peter Anvinb0c54622007-10-28 23:21:46 -07002121 if (b >= EXPR_REG_START && b < REG_ENUM_LIMIT) {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002122 bt = regvals[b];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002123 bx = reg_flags[b];
2124 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002125 bt = -1;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002126 bx = 0;
2127 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002128
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002129 /* check for a 32/64-bit memory reference... */
2130 if ((ix|bx) & (BITS32|BITS64)) {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002131 /* it must be a 32/64-bit memory reference. Firstly we have
2132 * to check that all registers involved are type E/Rxx. */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002133 int32_t sok = BITS32|BITS64;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002134
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002135 if (it != -1) {
2136 if (!(REG64 & ~ix) || !(REG32 & ~ix))
2137 sok &= ix;
2138 else
2139 return NULL;
2140 }
2141
2142 if (bt != -1) {
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00002143 if (REG_GPR & ~bx)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002144 return NULL; /* Invalid register */
H. Peter Anvina57e8d42007-05-30 03:44:02 +00002145 if (~sok & bx & SIZE_MASK)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002146 return NULL; /* Invalid size */
H. Peter Anvinb0c54622007-10-28 23:21:46 -07002147 sok &= bx;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002148 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002149
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002150 /* While we're here, ensure the user didn't specify
2151 WORD or QWORD. */
2152 if (input->disp_size == 16 || input->disp_size == 64)
2153 return NULL;
2154
2155 if (addrbits == 16 ||
2156 (addrbits == 32 && !(sok & BITS32)) ||
2157 (addrbits == 64 && !(sok & BITS64)))
2158 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002159
Keith Kaniosb7a89542007-04-12 02:40:54 +00002160 /* now reorganize base/index */
2161 if (s == 1 && bt != it && bt != -1 && it != -1 &&
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002162 ((hb == b && ht == EAH_NOTBASE)
2163 || (hb == i && ht == EAH_MAKEBASE))) {
2164 /* swap if hints say so */
2165 t = bt, bt = it, it = t;
2166 t = bx, bx = ix, ix = t;
2167 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00002168 if (bt == it) /* convert EAX+2*EAX to 3*EAX */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002169 bt = -1, bx = 0, s++;
2170 if (bt == -1 && s == 1 && !(hb == it && ht == EAH_NOTBASE)) {
2171 /* make single reg base, unless hint */
2172 bt = it, bx = ix, it = -1, ix = 0;
2173 }
H. Peter Anvinf5843c62007-09-10 18:59:26 +00002174 if (((s == 2 && it != REG_NUM_ESP
H. Peter Anvine2c80182005-01-15 22:15:51 +00002175 && !(input->eaflags & EAF_TIMESTWO)) || s == 3
Keith Kaniosb7a89542007-04-12 02:40:54 +00002176 || s == 5 || s == 9) && bt == -1)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002177 bt = it, bx = ix, s--; /* convert 3*EAX to EAX+2*EAX */
Keith Kanios48af1772007-08-17 07:37:52 +00002178 if (it == -1 && (bt & 7) != REG_NUM_ESP
H. Peter Anvine2c80182005-01-15 22:15:51 +00002179 && (input->eaflags & EAF_TIMESTWO))
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002180 it = bt, ix = bx, bt = -1, bx = 0, s = 1;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002181 /* convert [NOSPLIT EAX] to sib format with 0x0 displacement */
Keith Kanios48af1772007-08-17 07:37:52 +00002182 if (s == 1 && it == REG_NUM_ESP) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002183 /* swap ESP into base if scale is 1 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002184 t = it, it = bt, bt = t;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002185 t = ix, ix = bx, bx = t;
2186 }
Keith Kanios48af1772007-08-17 07:37:52 +00002187 if (it == REG_NUM_ESP
Keith Kaniosb7a89542007-04-12 02:40:54 +00002188 || (s != 1 && s != 2 && s != 4 && s != 8 && it != -1))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002189 return NULL; /* wrong, for various reasons */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002190
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002191 output->rex |= rexflags(it, ix, REX_X);
2192 output->rex |= rexflags(bt, bx, REX_B);
Keith Kaniosb7a89542007-04-12 02:40:54 +00002193
Keith Kanios48af1772007-08-17 07:37:52 +00002194 if (it == -1 && (bt & 7) != REG_NUM_ESP) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002195 /* no SIB needed */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002196 int mod, rm;
H. Peter Anvin70653092007-10-19 14:42:29 -07002197
Keith Kaniosb7a89542007-04-12 02:40:54 +00002198 if (bt == -1) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002199 rm = 5;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002200 mod = 0;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002201 } else {
2202 rm = (bt & 7);
Keith Kanios48af1772007-08-17 07:37:52 +00002203 if (rm != REG_NUM_EBP && o == 0 &&
Keith Kaniosb7a89542007-04-12 02:40:54 +00002204 seg == NO_SEG && !forw_ref &&
2205 !(input->eaflags &
2206 (EAF_BYTEOFFS | EAF_WORDOFFS)))
2207 mod = 0;
2208 else if (input->eaflags & EAF_BYTEOFFS ||
2209 (o >= -128 && o <= 127 && seg == NO_SEG
2210 && !forw_ref
2211 && !(input->eaflags & EAF_WORDOFFS)))
2212 mod = 1;
2213 else
2214 mod = 2;
2215 }
H. Peter Anvinea838272002-04-30 20:51:53 +00002216
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002217 output->sib_present = false;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002218 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2219 output->modrm = (mod << 6) | ((rfield & 7) << 3) | rm;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002220 } else {
2221 /* we need a SIB */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002222 int mod, scale, index, base;
H. Peter Anvin70653092007-10-19 14:42:29 -07002223
Keith Kaniosb7a89542007-04-12 02:40:54 +00002224 if (it == -1)
2225 index = 4, s = 1;
2226 else
2227 index = (it & 7);
H. Peter Anvin70653092007-10-19 14:42:29 -07002228
H. Peter Anvine2c80182005-01-15 22:15:51 +00002229 switch (s) {
2230 case 1:
2231 scale = 0;
2232 break;
2233 case 2:
2234 scale = 1;
2235 break;
2236 case 4:
2237 scale = 2;
2238 break;
2239 case 8:
2240 scale = 3;
2241 break;
2242 default: /* then what the smeg is it? */
2243 return NULL; /* panic */
2244 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002245
Keith Kaniosb7a89542007-04-12 02:40:54 +00002246 if (bt == -1) {
2247 base = 5;
2248 mod = 0;
2249 } else {
2250 base = (bt & 7);
Keith Kanios48af1772007-08-17 07:37:52 +00002251 if (base != REG_NUM_EBP && o == 0 &&
H. Peter Anvine2c80182005-01-15 22:15:51 +00002252 seg == NO_SEG && !forw_ref &&
2253 !(input->eaflags &
Keith Kaniosb7a89542007-04-12 02:40:54 +00002254 (EAF_BYTEOFFS | EAF_WORDOFFS)))
2255 mod = 0;
2256 else if (input->eaflags & EAF_BYTEOFFS ||
2257 (o >= -128 && o <= 127 && seg == NO_SEG
2258 && !forw_ref
2259 && !(input->eaflags & EAF_WORDOFFS)))
2260 mod = 1;
2261 else
2262 mod = 2;
2263 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002264
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002265 output->sib_present = true;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002266 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2267 output->modrm = (mod << 6) | ((rfield & 7) << 3) | 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002268 output->sib = (scale << 6) | (index << 3) | base;
2269 }
2270 } else { /* it's 16-bit */
2271 int mod, rm;
H. Peter Anvin70653092007-10-19 14:42:29 -07002272
Keith Kaniosb7a89542007-04-12 02:40:54 +00002273 /* check for 64-bit long mode */
2274 if (addrbits == 64)
2275 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002276
H. Peter Anvine2c80182005-01-15 22:15:51 +00002277 /* check all registers are BX, BP, SI or DI */
2278 if ((b != -1 && b != R_BP && b != R_BX && b != R_SI
2279 && b != R_DI) || (i != -1 && i != R_BP && i != R_BX
2280 && i != R_SI && i != R_DI))
2281 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002282
Keith Kaniosb7a89542007-04-12 02:40:54 +00002283 /* ensure the user didn't specify DWORD/QWORD */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002284 if (input->disp_size == 32 || input->disp_size == 64)
H. Peter Anvine2c80182005-01-15 22:15:51 +00002285 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002286
H. Peter Anvine2c80182005-01-15 22:15:51 +00002287 if (s != 1 && i != -1)
2288 return NULL; /* no can do, in 16-bit EA */
2289 if (b == -1 && i != -1) {
2290 int tmp = b;
2291 b = i;
2292 i = tmp;
2293 } /* swap */
2294 if ((b == R_SI || b == R_DI) && i != -1) {
2295 int tmp = b;
2296 b = i;
2297 i = tmp;
2298 }
2299 /* have BX/BP as base, SI/DI index */
2300 if (b == i)
2301 return NULL; /* shouldn't ever happen, in theory */
2302 if (i != -1 && b != -1 &&
2303 (i == R_BP || i == R_BX || b == R_SI || b == R_DI))
2304 return NULL; /* invalid combinations */
2305 if (b == -1) /* pure offset: handled above */
2306 return NULL; /* so if it gets to here, panic! */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002307
H. Peter Anvine2c80182005-01-15 22:15:51 +00002308 rm = -1;
2309 if (i != -1)
2310 switch (i * 256 + b) {
2311 case R_SI * 256 + R_BX:
2312 rm = 0;
2313 break;
2314 case R_DI * 256 + R_BX:
2315 rm = 1;
2316 break;
2317 case R_SI * 256 + R_BP:
2318 rm = 2;
2319 break;
2320 case R_DI * 256 + R_BP:
2321 rm = 3;
2322 break;
2323 } else
2324 switch (b) {
2325 case R_SI:
2326 rm = 4;
2327 break;
2328 case R_DI:
2329 rm = 5;
2330 break;
2331 case R_BP:
2332 rm = 6;
2333 break;
2334 case R_BX:
2335 rm = 7;
2336 break;
2337 }
2338 if (rm == -1) /* can't happen, in theory */
2339 return NULL; /* so panic if it does */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002340
H. Peter Anvine2c80182005-01-15 22:15:51 +00002341 if (o == 0 && seg == NO_SEG && !forw_ref && rm != 6 &&
2342 !(input->eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS)))
2343 mod = 0;
2344 else if (input->eaflags & EAF_BYTEOFFS ||
2345 (o >= -128 && o <= 127 && seg == NO_SEG
2346 && !forw_ref
2347 && !(input->eaflags & EAF_WORDOFFS)))
2348 mod = 1;
2349 else
2350 mod = 2;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002351
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002352 output->sib_present = false; /* no SIB - it's 16-bit */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002353 output->bytes = mod; /* bytes of offset needed */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002354 output->modrm = (mod << 6) | ((rfield & 7) << 3) | rm;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002355 }
2356 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002357 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002358
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002359 output->size = 1 + output->sib_present + output->bytes;
2360 return output;
2361}
2362
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002363static void add_asp(insn *ins, int addrbits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002364{
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002365 int j, valid;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002366 int defdisp;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002367
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002368 valid = (addrbits == 64) ? 64|32 : 32|16;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002369
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002370 switch (ins->prefixes[PPS_ASIZE]) {
2371 case P_A16:
2372 valid &= 16;
2373 break;
2374 case P_A32:
2375 valid &= 32;
2376 break;
2377 case P_A64:
2378 valid &= 64;
2379 break;
2380 case P_ASP:
2381 valid &= (addrbits == 32) ? 16 : 32;
2382 break;
2383 default:
2384 break;
2385 }
2386
2387 for (j = 0; j < ins->operands; j++) {
2388 if (!(MEMORY & ~ins->oprs[j].type)) {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002389 int32_t i, b;
H. Peter Anvin70653092007-10-19 14:42:29 -07002390
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002391 /* Verify as Register */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002392 if (ins->oprs[j].indexreg < EXPR_REG_START
2393 || ins->oprs[j].indexreg >= REG_ENUM_LIMIT)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002394 i = 0;
2395 else
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002396 i = reg_flags[ins->oprs[j].indexreg];
H. Peter Anvin70653092007-10-19 14:42:29 -07002397
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002398 /* Verify as Register */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002399 if (ins->oprs[j].basereg < EXPR_REG_START
2400 || ins->oprs[j].basereg >= REG_ENUM_LIMIT)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002401 b = 0;
2402 else
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002403 b = reg_flags[ins->oprs[j].basereg];
H. Peter Anvin70653092007-10-19 14:42:29 -07002404
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002405 if (ins->oprs[j].scale == 0)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002406 i = 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002407
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002408 if (!i && !b) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002409 int ds = ins->oprs[j].disp_size;
2410 if ((addrbits != 64 && ds > 8) ||
2411 (addrbits == 64 && ds == 16))
2412 valid &= ds;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002413 } else {
2414 if (!(REG16 & ~b))
2415 valid &= 16;
2416 if (!(REG32 & ~b))
2417 valid &= 32;
2418 if (!(REG64 & ~b))
2419 valid &= 64;
H. Peter Anvin70653092007-10-19 14:42:29 -07002420
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002421 if (!(REG16 & ~i))
2422 valid &= 16;
2423 if (!(REG32 & ~i))
2424 valid &= 32;
2425 if (!(REG64 & ~i))
2426 valid &= 64;
2427 }
2428 }
2429 }
2430
2431 if (valid & addrbits) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002432 ins->addr_size = addrbits;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002433 } else if (valid & ((addrbits == 32) ? 16 : 32)) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002434 /* Add an address size prefix */
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002435 enum prefixes pref = (addrbits == 32) ? P_A16 : P_A32;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002436 ins->prefixes[PPS_ASIZE] = pref;
2437 ins->addr_size = (addrbits == 32) ? 16 : 32;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002438 } else {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002439 /* Impossible... */
2440 errfunc(ERR_NONFATAL, "impossible combination of address sizes");
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002441 ins->addr_size = addrbits; /* Error recovery */
2442 }
2443
2444 defdisp = ins->addr_size == 16 ? 16 : 32;
2445
2446 for (j = 0; j < ins->operands; j++) {
2447 if (!(MEM_OFFS & ~ins->oprs[j].type) &&
2448 (ins->oprs[j].disp_size ? ins->oprs[j].disp_size : defdisp)
2449 != ins->addr_size) {
2450 /* mem_offs sizes must match the address size; if not,
2451 strip the MEM_OFFS bit and match only EA instructions */
2452 ins->oprs[j].type &= ~(MEM_OFFS & ~MEMORY);
2453 }
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002454 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002455}