blob: 56a05e6d8e3cbef196197b4494b1a8e3ee3b3b7a [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 Anvin7eb4a382007-09-17 15:49:30 -070047 * \170 - encodes the literal byte 0. (Some compilers don't take
48 * kindly to a zero byte in the _middle_ of a compile time
49 * string constant, so I had to put this hack in.)
H. Peter Anvin401c07e2007-09-17 16:55:04 -070050 * \171 - placement of DREX suffix in the absence of an EA
H. Peter Anvind85d2502008-05-04 17:53:31 -070051 * \172\ab - the register number from operand a in bits 7..4, with
52 * the 4-bit immediate from operand b in bits 0..3.
H. Peter Anvind58656f2008-05-06 20:11:14 -070053 * \173\xab - the register number from operand a in bits 7..4, with
54 * the value b in bits 0..3.
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000055 * \2ab - a ModRM, calculated on EA in operand a, with the spare
56 * field equal to digit b.
H. Peter Anvin32cd4c22008-04-04 13:34:53 -070057 * \250..\253 - same as \150..\153, except warn if the 64-bit operand
58 * is not equal to the truncated and sign-extended 32-bit
59 * operand; used for 32-bit immediates in 64-bit mode.
H. Peter Anvind85d2502008-05-04 17:53:31 -070060 * \260..\263 - this instruction uses VEX rather than REX, with the
61 * V field taken from operand 0..3.
62 * \270 - this instruction uses VEX rather than REX, with the
63 * V field set to 1111b.
64 *
65 * VEX prefixes are followed by the sequence:
66 * \1mm\1wp where mm is the M field; and wp is:
67 * 01 0ww lpp
68 * ww = 0 for W = 0
69 * ww = 1 for W = 1
70 * ww = 2 for W used as REX.W
71 *
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000072 * \310 - indicates fixed 16-bit address size, i.e. optional 0x67.
73 * \311 - indicates fixed 32-bit address size, i.e. optional 0x67.
Keith Kanios48af1772007-08-17 07:37:52 +000074 * \312 - (disassembler only) marker on LOOP, LOOPxx instructions.
H. Peter Anvince2b3972007-05-30 22:21:11 +000075 * \313 - indicates fixed 64-bit address size, 0x67 invalid.
H. Peter Anvin23440102007-11-12 21:02:33 -080076 * \314 - (disassembler only) invalid with REX.B
77 * \315 - (disassembler only) invalid with REX.X
78 * \316 - (disassembler only) invalid with REX.R
79 * \317 - (disassembler only) invalid with REX.W
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000080 * \320 - indicates fixed 16-bit operand size, i.e. optional 0x66.
81 * \321 - indicates fixed 32-bit operand size, i.e. optional 0x66.
82 * \322 - indicates that this instruction is only valid when the
83 * operand size is the default (instruction to disassembler,
84 * generates no code in the assembler)
H. Peter Anvince2b3972007-05-30 22:21:11 +000085 * \323 - indicates fixed 64-bit operand size, REX on extensions only.
Keith Kaniosb7a89542007-04-12 02:40:54 +000086 * \324 - indicates 64-bit operand size requiring REX prefix.
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000087 * \330 - a literal byte follows in the code stream, to be added
88 * to the condition code value of the instruction.
Keith Kanios48af1772007-08-17 07:37:52 +000089 * \331 - instruction not valid with REP prefix. Hint for
H. Peter Anvinef7468f2002-04-30 20:57:59 +000090 * disassembler only; for SSE instructions.
H. Peter Anvincb9b6902007-09-12 21:58:51 -070091 * \332 - REP prefix (0xF2 byte) used as opcode extension.
92 * \333 - REP prefix (0xF3 byte) used as opcode extension.
Keith Kanios48af1772007-08-17 07:37:52 +000093 * \334 - LOCK prefix used instead of REX.R
H. Peter Anvincb9b6902007-09-12 21:58:51 -070094 * \335 - disassemble a rep (0xF3 byte) prefix as repe not rep.
Keith Kaniosb7a89542007-04-12 02:40:54 +000095 * \340 - reserve <operand 0> bytes of uninitialized storage.
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000096 * Operand 0 had better be a segmentless constant.
H. Peter Anvin62cb6062007-09-11 22:44:03 +000097 * \364 - operand-size prefix (0x66) not permitted
98 * \365 - address-size prefix (0x67) not permitted
99 * \366 - operand-size prefix (0x66) used as opcode extension
100 * \367 - address-size prefix (0x67) used as opcode extension
H. Peter Anvin788e6c12002-04-30 21:02:01 +0000101 * \370,\371,\372 - match only if operand 0 meets byte jump criteria.
102 * 370 is used for Jcc, 371 is used for JMP.
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000103 * \373 - assemble 0x03 if bits==16, 0x05 if bits==32;
104 * used for conditional jump over longer jump
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000105 */
106
H. Peter Anvinfe501952007-10-02 21:53:51 -0700107#include "compiler.h"
108
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000109#include <stdio.h>
110#include <string.h>
Keith Kaniosb7a89542007-04-12 02:40:54 +0000111#include <inttypes.h>
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000112
113#include "nasm.h"
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000114#include "nasmlib.h"
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000115#include "assemble.h"
116#include "insns.h"
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000117#include "preproc.h"
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000118#include "regflags.c"
Keith Kaniosb7a89542007-04-12 02:40:54 +0000119#include "regvals.c"
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000120
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000121typedef struct {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000122 int sib_present; /* is a SIB byte necessary? */
123 int bytes; /* # of bytes of offset needed */
124 int size; /* lazy - this is sib+bytes+1 */
125 uint8_t modrm, sib, rex, rip; /* the bytes themselves */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000126} ea;
127
Keith Kaniosb7a89542007-04-12 02:40:54 +0000128static uint32_t cpu; /* cpu level received from nasm.c */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000129static efunc errfunc;
130static struct ofmt *outfmt;
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000131static ListGen *list;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000132
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800133static int64_t calcsize(int32_t, int64_t, int, insn *, const char *);
134static void gencode(int32_t, int64_t, int, insn *, const char *, int64_t);
H. Peter Anvin3360d792007-09-11 04:16:57 +0000135static int matches(const struct itemplate *, insn *, int bits);
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000136static int32_t regflag(const operand *);
137static int32_t regval(const operand *);
138static int rexflags(int, int32_t, int);
139static int op_rexflags(const operand *, int);
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700140static ea *process_ea(operand *, ea *, int, int, int, int32_t, int);
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700141static void add_asp(insn *, int);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000142
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700143static int has_prefix(insn * ins, enum prefix_pos pos, enum prefixes prefix)
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000144{
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700145 return ins->prefixes[pos] == prefix;
146}
147
148static void assert_no_prefix(insn * ins, enum prefix_pos pos)
149{
150 if (ins->prefixes[pos])
151 errfunc(ERR_NONFATAL, "invalid %s prefix",
152 prefix_name(ins->prefixes[pos]));
153}
154
155static const char *size_name(int size)
156{
157 switch (size) {
158 case 1:
159 return "byte";
160 case 2:
161 return "word";
162 case 4:
163 return "dword";
164 case 8:
165 return "qword";
166 case 10:
167 return "tword";
168 case 16:
169 return "oword";
170 default:
171 return "???";
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000172 }
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700173}
174
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700175static void warn_overflow(int size, int64_t data)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700176{
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700177 if (size < 8) {
Charles Craynedd462c82007-11-04 15:28:30 -0800178 int64_t lim = ((int64_t)1 << (size*8))-1;
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000179
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700180 if (data < ~lim || data > lim)
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700181 errfunc(ERR_WARNING | ERR_WARN_NOV,
182 "%s data exceeds bounds", size_name(size));
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700183 }
184}
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000185/*
186 * This routine wrappers the real output format's output routine,
187 * in order to pass a copy of the data off to the listing file
188 * generator at the same time.
189 */
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800190static void out(int64_t offset, int32_t segto, const void *data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800191 enum out_type type, uint64_t size,
192 int32_t segment, int32_t wrt)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000193{
Keith Kaniosb7a89542007-04-12 02:40:54 +0000194 static int32_t lineno = 0; /* static!!! */
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000195 static char *lnfname = NULL;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800196 uint8_t p[8];
H. Peter Anvineba20a72002-04-30 20:53:55 +0000197
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800198 if (type == OUT_ADDRESS && segment == NO_SEG && wrt == NO_SEG) {
199 /*
200 * This is a non-relocated address, and we're going to
201 * convert it into RAWDATA format.
202 */
203 uint8_t *q = p;
H. Peter Anvind1fb15c2007-11-13 09:37:59 -0800204
205 if (size > 8) {
206 errfunc(ERR_PANIC, "OUT_ADDRESS with size > 8");
207 return;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800208 }
H. Peter Anvind85d2502008-05-04 17:53:31 -0700209
H. Peter Anvind1fb15c2007-11-13 09:37:59 -0800210 WRITEADDR(q, *(int64_t *)data, size);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800211 data = p;
212 type = OUT_RAWDATA;
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000213 }
214
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800215 list->output(offset, data, type, size);
216
Frank Kotlerabebb082003-09-06 04:45:37 +0000217 /*
218 * this call to src_get determines when we call the
219 * debug-format-specific "linenum" function
220 * it updates lineno and lnfname to the current values
221 * returning 0 if "same as last time", -2 if lnfname
222 * changed, and the amount by which lineno changed,
223 * if it did. thus, these variables must be static
224 */
225
H. Peter Anvine2c80182005-01-15 22:15:51 +0000226 if (src_get(&lineno, &lnfname)) {
227 outfmt->current_dfmt->linenum(lnfname, lineno, segto);
H. Peter Anvince616072002-04-30 21:02:23 +0000228 }
H. Peter Anvineba20a72002-04-30 20:53:55 +0000229
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800230 outfmt->output(segto, data, type, size, segment, wrt);
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000231}
232
Charles Crayne5fbbc8c2007-11-07 19:03:46 -0800233static int jmp_match(int32_t segment, int64_t offset, int bits,
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000234 insn * ins, const char *code)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000235{
Charles Crayne5fbbc8c2007-11-07 19:03:46 -0800236 int64_t isize;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000237 uint8_t c = code[0];
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000238
H. Peter Anvine2c80182005-01-15 22:15:51 +0000239 if (c != 0370 && c != 0371)
240 return 0;
H. Peter Anvin788e6c12002-04-30 21:02:01 +0000241 if (ins->oprs[0].opflags & OPFLAG_FORWARD) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000242 if ((optimizing < 0 || (ins->oprs[0].type & STRICT))
243 && c == 0370)
244 return 1;
245 else
246 return (pass0 == 0); /* match a forward reference */
H. Peter Anvin788e6c12002-04-30 21:02:01 +0000247 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000248 isize = calcsize(segment, offset, bits, ins, code);
249 if (ins->oprs[0].segment != segment)
250 return 0;
251 isize = ins->oprs[0].offset - offset - isize; /* isize is now the delta */
252 if (isize >= -128L && isize <= 127L)
253 return 1; /* it is byte size */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000254
255 return 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000256}
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000257
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800258int64_t assemble(int32_t segment, int64_t offset, int bits, uint32_t cp,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000259 insn * instruction, struct ofmt *output, efunc error,
260 ListGen * listgen)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000261{
H. Peter Anvin3360d792007-09-11 04:16:57 +0000262 const struct itemplate *temp;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000263 int j;
264 int size_prob;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800265 int64_t insn_end;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000266 int32_t itimes;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800267 int64_t start = offset;
268 int64_t wsize = 0; /* size for DB etc. */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000269
H. Peter Anvine2c80182005-01-15 22:15:51 +0000270 errfunc = error; /* to pass to other functions */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000271 cpu = cp;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000272 outfmt = output; /* likewise */
273 list = listgen; /* and again */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000274
H. Peter Anvine2c80182005-01-15 22:15:51 +0000275 switch (instruction->opcode) {
276 case -1:
277 return 0;
278 case I_DB:
279 wsize = 1;
280 break;
281 case I_DW:
282 wsize = 2;
283 break;
284 case I_DD:
285 wsize = 4;
286 break;
287 case I_DQ:
288 wsize = 8;
289 break;
290 case I_DT:
291 wsize = 10;
292 break;
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700293 case I_DO:
294 wsize = 16;
295 break;
H. Peter Anvin16b0a332007-09-12 20:27:41 -0700296 default:
297 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000298 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000299
H. Peter Anvineba20a72002-04-30 20:53:55 +0000300 if (wsize) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000301 extop *e;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000302 int32_t t = instruction->times;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000303 if (t < 0)
304 errfunc(ERR_PANIC,
305 "instruction->times < 0 (%ld) in assemble()", t);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000306
H. Peter Anvine2c80182005-01-15 22:15:51 +0000307 while (t--) { /* repeat TIMES times */
308 for (e = instruction->eops; e; e = e->next) {
309 if (e->type == EOT_DB_NUMBER) {
310 if (wsize == 1) {
311 if (e->segment != NO_SEG)
312 errfunc(ERR_NONFATAL,
313 "one-byte relocation attempted");
314 else {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000315 uint8_t out_byte = e->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000316 out(offset, segment, &out_byte,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800317 OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000318 }
Keith Kanios61ff53c2007-04-14 18:54:52 +0000319 } else if (wsize > 8) {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700320 errfunc(ERR_NONFATAL, "integer supplied to a DT or DO"
Keith Kanios61ff53c2007-04-14 18:54:52 +0000321 " instruction");
H. Peter Anvine2c80182005-01-15 22:15:51 +0000322 } else
323 out(offset, segment, &e->offset,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800324 OUT_ADDRESS, wsize, e->segment, e->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000325 offset += wsize;
326 } else if (e->type == EOT_DB_STRING) {
327 int align;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000328
H. Peter Anvine2c80182005-01-15 22:15:51 +0000329 out(offset, segment, e->stringval,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800330 OUT_RAWDATA, e->stringlen, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000331 align = e->stringlen % wsize;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000332
H. Peter Anvine2c80182005-01-15 22:15:51 +0000333 if (align) {
334 align = wsize - align;
H. Peter Anvind387b8c2008-01-27 16:39:26 -0800335 out(offset, segment,
336 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0",
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800337 OUT_RAWDATA, align, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000338 }
339 offset += e->stringlen + align;
340 }
341 }
342 if (t > 0 && t == instruction->times - 1) {
343 /*
344 * Dummy call to list->output to give the offset to the
345 * listing module.
346 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800347 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000348 list->uplevel(LIST_TIMES);
349 }
350 }
351 if (instruction->times > 1)
352 list->downlevel(LIST_TIMES);
353 return offset - start;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000354 }
355
H. Peter Anvine2c80182005-01-15 22:15:51 +0000356 if (instruction->opcode == I_INCBIN) {
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000357 static char fname[FILENAME_MAX];
H. Peter Anvine2c80182005-01-15 22:15:51 +0000358 FILE *fp;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000359 int32_t len;
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000360 char *prefix = "", *combine;
361 char **pPrevPath = NULL;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000362
H. Peter Anvine2c80182005-01-15 22:15:51 +0000363 len = FILENAME_MAX - 1;
364 if (len > instruction->eops->stringlen)
365 len = instruction->eops->stringlen;
366 strncpy(fname, instruction->eops->stringval, len);
367 fname[len] = '\0';
H. Peter Anvineba20a72002-04-30 20:53:55 +0000368
Keith Kaniosb7a89542007-04-12 02:40:54 +0000369 while (1) { /* added by alexfru: 'incbin' uses include paths */
H. Peter Anvine2c80182005-01-15 22:15:51 +0000370 combine = nasm_malloc(strlen(prefix) + len + 1);
371 strcpy(combine, prefix);
372 strcat(combine, fname);
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000373
H. Peter Anvine2c80182005-01-15 22:15:51 +0000374 if ((fp = fopen(combine, "rb")) != NULL) {
375 nasm_free(combine);
376 break;
377 }
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000378
H. Peter Anvine2c80182005-01-15 22:15:51 +0000379 nasm_free(combine);
380 pPrevPath = pp_get_include_path_ptr(pPrevPath);
381 if (pPrevPath == NULL)
382 break;
383 prefix = *pPrevPath;
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000384 }
385
386 if (fp == NULL)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000387 error(ERR_NONFATAL, "`incbin': unable to open file `%s'",
388 fname);
389 else if (fseek(fp, 0L, SEEK_END) < 0)
390 error(ERR_NONFATAL, "`incbin': unable to seek on file `%s'",
391 fname);
392 else {
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000393 static char buf[2048];
Keith Kaniosb7a89542007-04-12 02:40:54 +0000394 int32_t t = instruction->times;
395 int32_t base = 0;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000396
H. Peter Anvine2c80182005-01-15 22:15:51 +0000397 len = ftell(fp);
398 if (instruction->eops->next) {
399 base = instruction->eops->next->offset;
400 len -= base;
401 if (instruction->eops->next->next &&
402 len > instruction->eops->next->next->offset)
403 len = instruction->eops->next->next->offset;
404 }
405 /*
406 * Dummy call to list->output to give the offset to the
407 * listing module.
408 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800409 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000410 list->uplevel(LIST_INCBIN);
411 while (t--) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000412 int32_t l;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000413
H. Peter Anvine2c80182005-01-15 22:15:51 +0000414 fseek(fp, base, SEEK_SET);
415 l = len;
416 while (l > 0) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000417 int32_t m =
Charles Crayne192d5b52007-10-18 19:02:42 -0700418 fread(buf, 1, (l > (int32_t) sizeof(buf) ? (int32_t) sizeof(buf) : l),
H. Peter Anvine2c80182005-01-15 22:15:51 +0000419 fp);
420 if (!m) {
421 /*
422 * This shouldn't happen unless the file
423 * actually changes while we are reading
424 * it.
425 */
426 error(ERR_NONFATAL,
427 "`incbin': unexpected EOF while"
428 " reading file `%s'", fname);
429 t = 0; /* Try to exit cleanly */
430 break;
431 }
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800432 out(offset, segment, buf, OUT_RAWDATA, m,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000433 NO_SEG, NO_SEG);
434 l -= m;
435 }
436 }
437 list->downlevel(LIST_INCBIN);
438 if (instruction->times > 1) {
439 /*
440 * Dummy call to list->output to give the offset to the
441 * listing module.
442 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800443 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000444 list->uplevel(LIST_TIMES);
445 list->downlevel(LIST_TIMES);
446 }
447 fclose(fp);
448 return instruction->times * len;
449 }
450 return 0; /* if we're here, there's an error */
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000451 }
452
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700453 /* Check to see if we need an address-size prefix */
454 add_asp(instruction, bits);
455
H. Peter Anvin6867acc2007-10-10 14:58:45 -0700456 size_prob = false;
H. Peter Anvin70653092007-10-19 14:42:29 -0700457
458 for (temp = nasm_instructions[instruction->opcode]; temp->opcode != -1; temp++){
Keith Kaniosb7a89542007-04-12 02:40:54 +0000459 int m = matches(temp, instruction, bits);
H. Peter Anvin70653092007-10-19 14:42:29 -0700460
H. Peter Anvine2c80182005-01-15 22:15:51 +0000461 if (m == 99)
462 m += jmp_match(segment, offset, bits, instruction, temp->code);
H. Peter Anvineba20a72002-04-30 20:53:55 +0000463
H. Peter Anvine2c80182005-01-15 22:15:51 +0000464 if (m == 100) { /* matches! */
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000465 const char *codes = temp->code;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800466 int64_t insn_size = calcsize(segment, offset, bits,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000467 instruction, codes);
468 itimes = instruction->times;
469 if (insn_size < 0) /* shouldn't be, on pass two */
470 error(ERR_PANIC, "errors made it through from pass one");
471 else
472 while (itimes--) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700473 for (j = 0; j < MAXPREFIX; j++) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000474 uint8_t c = 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000475 switch (instruction->prefixes[j]) {
476 case P_LOCK:
477 c = 0xF0;
478 break;
479 case P_REPNE:
480 case P_REPNZ:
481 c = 0xF2;
482 break;
483 case P_REPE:
484 case P_REPZ:
485 case P_REP:
486 c = 0xF3;
487 break;
488 case R_CS:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000489 if (bits == 64) {
490 error(ERR_WARNING,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800491 "cs segment base generated, but will be ignored in 64-bit mode");
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000492 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000493 c = 0x2E;
494 break;
495 case R_DS:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000496 if (bits == 64) {
497 error(ERR_WARNING,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800498 "ds segment base generated, but will be ignored in 64-bit mode");
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000499 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000500 c = 0x3E;
501 break;
502 case R_ES:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000503 if (bits == 64) {
504 error(ERR_WARNING,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800505 "es segment base generated, but will be ignored in 64-bit mode");
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000506 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000507 c = 0x26;
508 break;
509 case R_FS:
510 c = 0x64;
511 break;
512 case R_GS:
513 c = 0x65;
514 break;
515 case R_SS:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000516 if (bits == 64) {
517 error(ERR_WARNING,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800518 "ss segment base generated, but will be ignored in 64-bit mode");
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000519 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000520 c = 0x36;
521 break;
522 case R_SEGR6:
523 case R_SEGR7:
524 error(ERR_NONFATAL,
525 "segr6 and segr7 cannot be used as prefixes");
526 break;
527 case P_A16:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000528 if (bits == 64) {
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000529 error(ERR_NONFATAL,
530 "16-bit addressing is not supported "
531 "in 64-bit mode");
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700532 } else if (bits != 16)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000533 c = 0x67;
534 break;
535 case P_A32:
536 if (bits != 32)
537 c = 0x67;
538 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700539 case P_A64:
540 if (bits != 64) {
541 error(ERR_NONFATAL,
542 "64-bit addressing is only supported "
543 "in 64-bit mode");
544 }
545 break;
546 case P_ASP:
547 c = 0x67;
548 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000549 case P_O16:
550 if (bits != 16)
551 c = 0x66;
552 break;
553 case P_O32:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000554 if (bits == 16)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000555 c = 0x66;
556 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700557 case P_O64:
558 /* REX.W */
559 break;
560 case P_OSP:
561 c = 0x66;
562 break;
563 case P_none:
564 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000565 default:
566 error(ERR_PANIC, "invalid instruction prefix");
567 }
568 if (c != 0) {
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800569 out(offset, segment, &c, OUT_RAWDATA, 1,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000570 NO_SEG, NO_SEG);
571 offset++;
572 }
H. Peter Anvin70653092007-10-19 14:42:29 -0700573 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000574 insn_end = offset + insn_size;
575 gencode(segment, offset, bits, instruction, codes,
576 insn_end);
577 offset += insn_size;
578 if (itimes > 0 && itimes == instruction->times - 1) {
579 /*
580 * Dummy call to list->output to give the offset to the
581 * listing module.
582 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800583 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000584 list->uplevel(LIST_TIMES);
585 }
586 }
587 if (instruction->times > 1)
588 list->downlevel(LIST_TIMES);
589 return offset - start;
590 } else if (m > 0 && m > size_prob) {
591 size_prob = m;
592 }
Keith Kaniosb7a89542007-04-12 02:40:54 +0000593// temp++;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000594 }
H. Peter Anvineba20a72002-04-30 20:53:55 +0000595
H. Peter Anvine2c80182005-01-15 22:15:51 +0000596 if (temp->opcode == -1) { /* didn't match any instruction */
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000597 switch (size_prob) {
598 case 1:
599 error(ERR_NONFATAL, "operation size not specified");
600 break;
601 case 2:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000602 error(ERR_NONFATAL, "mismatch in operand sizes");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000603 break;
604 case 3:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000605 error(ERR_NONFATAL, "no instruction for this cpu level");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000606 break;
607 case 4:
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000608 error(ERR_NONFATAL, "instruction not supported in 64-bit mode");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000609 break;
610 default:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000611 error(ERR_NONFATAL,
612 "invalid combination of opcode and operands");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000613 break;
614 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000615 }
616 return 0;
617}
618
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800619int64_t insn_size(int32_t segment, int64_t offset, int bits, uint32_t cp,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000620 insn * instruction, efunc error)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000621{
H. Peter Anvin3360d792007-09-11 04:16:57 +0000622 const struct itemplate *temp;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000623
H. Peter Anvine2c80182005-01-15 22:15:51 +0000624 errfunc = error; /* to pass to other functions */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000625 cpu = cp;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000626
627 if (instruction->opcode == -1)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000628 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000629
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700630 if (instruction->opcode == I_DB || instruction->opcode == I_DW ||
631 instruction->opcode == I_DD || instruction->opcode == I_DQ ||
632 instruction->opcode == I_DT || instruction->opcode == I_DO) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000633 extop *e;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000634 int32_t isize, osize, wsize = 0; /* placate gcc */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000635
H. Peter Anvine2c80182005-01-15 22:15:51 +0000636 isize = 0;
637 switch (instruction->opcode) {
638 case I_DB:
639 wsize = 1;
640 break;
641 case I_DW:
642 wsize = 2;
643 break;
644 case I_DD:
645 wsize = 4;
646 break;
647 case I_DQ:
648 wsize = 8;
649 break;
650 case I_DT:
651 wsize = 10;
652 break;
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700653 case I_DO:
654 wsize = 16;
655 break;
H. Peter Anvin16b0a332007-09-12 20:27:41 -0700656 default:
657 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000658 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000659
H. Peter Anvine2c80182005-01-15 22:15:51 +0000660 for (e = instruction->eops; e; e = e->next) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000661 int32_t align;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000662
H. Peter Anvine2c80182005-01-15 22:15:51 +0000663 osize = 0;
664 if (e->type == EOT_DB_NUMBER)
665 osize = 1;
666 else if (e->type == EOT_DB_STRING)
667 osize = e->stringlen;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000668
H. Peter Anvine2c80182005-01-15 22:15:51 +0000669 align = (-osize) % wsize;
670 if (align < 0)
671 align += wsize;
672 isize += osize + align;
673 }
674 return isize * instruction->times;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000675 }
676
H. Peter Anvine2c80182005-01-15 22:15:51 +0000677 if (instruction->opcode == I_INCBIN) {
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000678 char fname[FILENAME_MAX];
H. Peter Anvine2c80182005-01-15 22:15:51 +0000679 FILE *fp;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000680 int32_t len;
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000681 char *prefix = "", *combine;
682 char **pPrevPath = NULL;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000683
H. Peter Anvine2c80182005-01-15 22:15:51 +0000684 len = FILENAME_MAX - 1;
685 if (len > instruction->eops->stringlen)
686 len = instruction->eops->stringlen;
687 strncpy(fname, instruction->eops->stringval, len);
688 fname[len] = '\0';
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000689
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700690 /* added by alexfru: 'incbin' uses include paths */
691 while (1) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000692 combine = nasm_malloc(strlen(prefix) + len + 1);
693 strcpy(combine, prefix);
694 strcat(combine, fname);
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000695
H. Peter Anvine2c80182005-01-15 22:15:51 +0000696 if ((fp = fopen(combine, "rb")) != NULL) {
697 nasm_free(combine);
698 break;
699 }
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000700
H. Peter Anvine2c80182005-01-15 22:15:51 +0000701 nasm_free(combine);
702 pPrevPath = pp_get_include_path_ptr(pPrevPath);
703 if (pPrevPath == NULL)
704 break;
705 prefix = *pPrevPath;
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000706 }
707
708 if (fp == NULL)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000709 error(ERR_NONFATAL, "`incbin': unable to open file `%s'",
710 fname);
711 else if (fseek(fp, 0L, SEEK_END) < 0)
712 error(ERR_NONFATAL, "`incbin': unable to seek on file `%s'",
713 fname);
714 else {
715 len = ftell(fp);
716 fclose(fp);
717 if (instruction->eops->next) {
718 len -= instruction->eops->next->offset;
719 if (instruction->eops->next->next &&
720 len > instruction->eops->next->next->offset) {
721 len = instruction->eops->next->next->offset;
722 }
723 }
724 return instruction->times * len;
725 }
726 return 0; /* if we're here, there's an error */
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000727 }
728
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700729 /* Check to see if we need an address-size prefix */
730 add_asp(instruction, bits);
731
Keith Kaniosb7a89542007-04-12 02:40:54 +0000732 for (temp = nasm_instructions[instruction->opcode]; temp->opcode != -1; temp++) {
733 int m = matches(temp, instruction, bits);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000734 if (m == 99)
735 m += jmp_match(segment, offset, bits, instruction, temp->code);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000736
H. Peter Anvine2c80182005-01-15 22:15:51 +0000737 if (m == 100) {
738 /* we've matched an instruction. */
Charles Crayne5fbbc8c2007-11-07 19:03:46 -0800739 int64_t isize;
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000740 const char *codes = temp->code;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000741 int j;
742
743 isize = calcsize(segment, offset, bits, instruction, codes);
744 if (isize < 0)
745 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700746 for (j = 0; j < MAXPREFIX; j++) {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700747 switch (instruction->prefixes[j]) {
748 case P_A16:
749 if (bits != 16)
750 isize++;
751 break;
752 case P_A32:
753 if (bits != 32)
754 isize++;
755 break;
756 case P_O16:
757 if (bits != 16)
758 isize++;
759 break;
760 case P_O32:
761 if (bits == 16)
762 isize++;
763 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700764 case P_A64:
765 case P_O64:
766 case P_none:
767 break;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700768 default:
769 isize++;
770 break;
771 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000772 }
773 return isize * instruction->times;
774 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000775 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000776 return -1; /* didn't match any instruction */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000777}
778
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700779static bool possible_sbyte(insn * ins, int op)
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000780{
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700781 return !(ins->forw_ref && ins->oprs[op].opflags) &&
H. Peter Anvine2c80182005-01-15 22:15:51 +0000782 optimizing >= 0 &&
783 !(ins->oprs[op].type & STRICT) &&
784 ins->oprs[op].wrt == NO_SEG && ins->oprs[op].segment == NO_SEG;
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000785}
786
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700787/* check that opn[op] is a signed byte of size 16 or 32 */
788static bool is_sbyte16(insn * ins, int op)
789{
790 int16_t v;
791
792 if (!possible_sbyte(ins, op))
793 return false;
794
795 v = ins->oprs[op].offset;
796 return v >= -128 && v <= 127;
797}
798
799static bool is_sbyte32(insn * ins, int op)
800{
801 int32_t v;
802
803 if (!possible_sbyte(ins, op))
804 return false;
805
806 v = ins->oprs[op].offset;
807 return v >= -128 && v <= 127;
808}
809
810/* check that opn[op] is a signed byte of size 32; warn if this is not
811 the original value when extended to 64 bits */
812static bool is_sbyte64(insn * ins, int op)
813{
814 int64_t v64;
815 int32_t v32;
816
817 /* dead in the water on forward reference or External */
818 if (!possible_sbyte(ins, op))
819 return false;
820
821 v64 = ins->oprs[op].offset;
822 v32 = (int32_t)v64;
823
824 warn_overflow(32, v64);
825
826 return v32 >= -128 && v32 <= 127;
827}
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800828static int64_t calcsize(int32_t segment, int64_t offset, int bits,
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000829 insn * ins, const char *codes)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000830{
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800831 int64_t length = 0;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000832 uint8_t c;
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000833 int rex_mask = ~0;
H. Peter Anvin839eca22007-10-29 23:12:47 -0700834 struct operand *opx;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000835
H. Peter Anvine3917fc2007-11-01 14:53:32 -0700836 ins->rex = 0; /* Ensure REX is reset */
837
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700838 if (ins->prefixes[PPS_OSIZE] == P_O64)
839 ins->rex |= REX_W;
840
H. Peter Anvine2c80182005-01-15 22:15:51 +0000841 (void)segment; /* Don't warn that this parameter is unused */
842 (void)offset; /* Don't warn that this parameter is unused */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000843
H. Peter Anvin839eca22007-10-29 23:12:47 -0700844 while (*codes) {
845 c = *codes++;
846 opx = &ins->oprs[c & 3];
847 switch (c) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000848 case 01:
849 case 02:
850 case 03:
851 codes += c, length += c;
852 break;
853 case 04:
854 case 05:
855 case 06:
856 case 07:
857 length++;
858 break;
859 case 010:
860 case 011:
861 case 012:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700862 case 013:
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000863 ins->rex |=
H. Peter Anvin839eca22007-10-29 23:12:47 -0700864 op_rexflags(opx, REX_B|REX_H|REX_P|REX_W);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000865 codes++, length++;
866 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000867 case 014:
868 case 015:
869 case 016:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700870 case 017:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000871 length++;
872 break;
873 case 020:
874 case 021:
875 case 022:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700876 case 023:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000877 length++;
878 break;
879 case 024:
880 case 025:
881 case 026:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700882 case 027:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000883 length++;
884 break;
885 case 030:
886 case 031:
887 case 032:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700888 case 033:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000889 length += 2;
890 break;
891 case 034:
892 case 035:
893 case 036:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700894 case 037:
H. Peter Anvin839eca22007-10-29 23:12:47 -0700895 if (opx->type & (BITS16 | BITS32 | BITS64))
896 length += (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000897 else
898 length += (bits == 16) ? 2 : 4;
899 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000900 case 040:
901 case 041:
902 case 042:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700903 case 043:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000904 length += 4;
905 break;
906 case 044:
907 case 045:
908 case 046:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700909 case 047:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700910 length += ins->addr_size >> 3;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000911 break;
912 case 050:
913 case 051:
914 case 052:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700915 case 053:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000916 length++;
917 break;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000918 case 054:
919 case 055:
920 case 056:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700921 case 057:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000922 length += 8; /* MOV reg64/imm */
923 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000924 case 060:
925 case 061:
926 case 062:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700927 case 063:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000928 length += 2;
929 break;
930 case 064:
931 case 065:
932 case 066:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700933 case 067:
H. Peter Anvin839eca22007-10-29 23:12:47 -0700934 if (opx->type & (BITS16 | BITS32 | BITS64))
935 length += (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000936 else
937 length += (bits == 16) ? 2 : 4;
938 break;
939 case 070:
940 case 071:
941 case 072:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700942 case 073:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000943 length += 4;
944 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700945 case 074:
946 case 075:
947 case 076:
948 case 077:
949 length += 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000950 break;
951 case 0140:
952 case 0141:
953 case 0142:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700954 case 0143:
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700955 length += is_sbyte16(ins, c & 3) ? 1 : 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000956 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000957 case 0144:
958 case 0145:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700959 case 0146:
960 case 0147:
H. Peter Anvina30cc072007-11-18 21:55:26 -0800961 codes++;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000962 length++;
963 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700964 case 0150:
965 case 0151:
966 case 0152:
967 case 0153:
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700968 length += is_sbyte32(ins, c & 3) ? 1 : 4;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700969 break;
970 case 0154:
971 case 0155:
972 case 0156:
973 case 0157:
H. Peter Anvina30cc072007-11-18 21:55:26 -0800974 codes++;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700975 length++;
976 break;
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700977 case 0160:
978 case 0161:
979 case 0162:
980 case 0163:
981 length++;
982 ins->rex |= REX_D;
H. Peter Anvind85d2502008-05-04 17:53:31 -0700983 ins->drexdst = regval(opx);
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700984 break;
985 case 0164:
986 case 0165:
987 case 0166:
988 case 0167:
989 length++;
990 ins->rex |= REX_D|REX_OC;
H. Peter Anvind85d2502008-05-04 17:53:31 -0700991 ins->drexdst = regval(opx);
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700992 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700993 case 0170:
994 length++;
995 break;
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700996 case 0171:
997 break;
H. Peter Anvind85d2502008-05-04 17:53:31 -0700998 case 0172:
H. Peter Anvind58656f2008-05-06 20:11:14 -0700999 case 0173:
H. Peter Anvind85d2502008-05-04 17:53:31 -07001000 codes++;
1001 length++;
1002 break;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001003 case 0250:
1004 case 0251:
1005 case 0252:
1006 case 0253:
1007 length += is_sbyte64(ins, c & 3) ? 1 : 4;
1008 break;
H. Peter Anvind85d2502008-05-04 17:53:31 -07001009 case 0260:
1010 case 0261:
1011 case 0262:
1012 case 0263:
1013 length += 2;
1014 ins->rex |= REX_V;
1015 ins->drexdst = regval(opx);
1016 ins->vex_m = *codes++;
1017 ins->vex_wlp = *codes++;
1018 break;
1019 case 0270:
1020 length += 2;
1021 ins->rex |= REX_V;
1022 ins->drexdst = 0;
1023 ins->vex_m = *codes++;
1024 ins->vex_wlp = *codes++;
1025 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001026 case 0300:
1027 case 0301:
H. Peter Anvin70653092007-10-19 14:42:29 -07001028 case 0302:
1029 case 0303:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001030 break;
1031 case 0310:
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07001032 if (bits == 64)
1033 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001034 length += (bits != 16) && !has_prefix(ins, PPS_ASIZE, P_A16);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001035 break;
1036 case 0311:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001037 length += (bits != 32) && !has_prefix(ins, PPS_ASIZE, P_A32);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001038 break;
1039 case 0312:
H. Peter Anvin70653092007-10-19 14:42:29 -07001040 break;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001041 case 0313:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001042 if (bits != 64 || has_prefix(ins, PPS_ASIZE, P_A16) ||
1043 has_prefix(ins, PPS_ASIZE, P_A32))
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07001044 return -1;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001045 break;
H. Peter Anvin23440102007-11-12 21:02:33 -08001046 case 0314:
1047 case 0315:
1048 case 0316:
1049 case 0317:
1050 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001051 case 0320:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001052 length += (bits != 16);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001053 break;
1054 case 0321:
1055 length += (bits == 16);
1056 break;
1057 case 0322:
1058 break;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001059 case 0323:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001060 rex_mask &= ~REX_W;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001061 break;
1062 case 0324:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001063 ins->rex |= REX_W;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001064 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001065 case 0330:
1066 codes++, length++;
1067 break;
1068 case 0331:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001069 break;
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001070 case 0332:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001071 case 0333:
1072 length++;
1073 break;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001074 case 0334:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001075 ins->rex |= REX_L;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001076 break;
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001077 case 0335:
1078 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001079 case 0340:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001080 if (ins->oprs[0].segment != NO_SEG)
1081 errfunc(ERR_NONFATAL, "attempt to reserve non-constant"
1082 " quantity of BSS space");
1083 else
H. Peter Anvin428fd672007-11-15 10:25:52 -08001084 length += ins->oprs[0].offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001085 break;
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001086 case 0364:
1087 case 0365:
1088 break;
Keith Kanios48af1772007-08-17 07:37:52 +00001089 case 0366:
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001090 case 0367:
1091 length++;
1092 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001093 case 0370:
1094 case 0371:
1095 case 0372:
1096 break;
1097 case 0373:
1098 length++;
1099 break;
1100 default: /* can't do it by 'case' statements */
1101 if (c >= 0100 && c <= 0277) { /* it's an EA */
1102 ea ea_data;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001103 int rfield;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001104 int32_t rflags;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001105 ea_data.rex = 0; /* Ensure ea.REX is initially 0 */
H. Peter Anvin70653092007-10-19 14:42:29 -07001106
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001107 if (c <= 0177) {
1108 /* pick rfield from operand b */
1109 rflags = regflag(&ins->oprs[c & 7]);
1110 rfield = regvals[ins->oprs[c & 7].basereg];
1111 } else {
1112 rflags = 0;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001113 rfield = c & 7;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001114 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00001115
H. Peter Anvine2c80182005-01-15 22:15:51 +00001116 if (!process_ea
Keith Kaniosb7a89542007-04-12 02:40:54 +00001117 (&ins->oprs[(c >> 3) & 7], &ea_data, bits,
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001118 ins->addr_size, rfield, rflags, ins->forw_ref)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001119 errfunc(ERR_NONFATAL, "invalid effective address");
1120 return -1;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001121 } else {
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001122 ins->rex |= ea_data.rex;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001123 length += ea_data.size;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001124 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001125 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001126 errfunc(ERR_PANIC, "internal instruction table corrupt"
1127 ": instruction code 0x%02X given", c);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001128 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001129 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001130 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001131
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001132 ins->rex &= rex_mask;
H. Peter Anvin70653092007-10-19 14:42:29 -07001133
H. Peter Anvind85d2502008-05-04 17:53:31 -07001134 if (ins->rex & REX_V) {
1135 int bad32 = REX_R|REX_W|REX_X|REX_B;
1136
1137 if (ins->rex & REX_H) {
1138 errfunc(ERR_NONFATAL, "cannot use high register in vex instruction");
1139 return -1;
1140 }
1141 switch (ins->vex_wlp & 030) {
1142 case 000:
1143 ins->rex &= ~REX_W;
1144 break;
1145 case 010:
1146 ins->rex |= REX_W;
1147 bad32 &= ~REX_W;
1148 break;
1149 default:
1150 /* Follow REX_W */
1151 break;
1152 }
1153
1154 if (bits != 64 && ((ins->rex & bad32) || ins->drexdst > 7)) {
1155 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1156 return -1;
1157 }
1158 if (ins->vex_m != 1 || (ins->rex & (REX_W|REX_R|REX_B)))
1159 length += 3;
1160 else
1161 length += 2;
1162 } else if (ins->rex & REX_D) {
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001163 if (ins->rex & REX_H) {
1164 errfunc(ERR_NONFATAL, "cannot use high register in drex instruction");
1165 return -1;
1166 }
H. Peter Anvind85d2502008-05-04 17:53:31 -07001167 if (bits != 64 && ((ins->rex & (REX_R|REX_W|REX_X|REX_B)) ||
H. Peter Anvincf5180a2007-09-17 17:25:27 -07001168 ins->drexdst > 7)) {
1169 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1170 return -1;
1171 }
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001172 length++;
1173 } else if (ins->rex & REX_REAL) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001174 if (ins->rex & REX_H) {
1175 errfunc(ERR_NONFATAL, "cannot use high register in rex instruction");
1176 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001177 } else if (bits == 64) {
1178 length++;
1179 } else if ((ins->rex & REX_L) &&
1180 !(ins->rex & (REX_P|REX_W|REX_X|REX_B)) &&
1181 cpu >= IF_X86_64) {
1182 /* LOCK-as-REX.R */
1183 assert_no_prefix(ins, PPS_LREP);
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001184 length++;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001185 } else {
H. Peter Anvincf5180a2007-09-17 17:25:27 -07001186 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1187 return -1;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001188 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00001189 }
1190
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001191 return length;
1192}
Keith Kaniosb7a89542007-04-12 02:40:54 +00001193
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001194#define EMIT_REX() \
H. Peter Anvind85d2502008-05-04 17:53:31 -07001195 if (!(ins->rex & (REX_D|REX_V)) && (ins->rex & REX_REAL) && (bits == 64)) { \
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001196 ins->rex = (ins->rex & REX_REAL)|REX_P; \
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001197 out(offset, segment, &ins->rex, OUT_RAWDATA, 1, NO_SEG, NO_SEG); \
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001198 ins->rex = 0; \
1199 offset += 1; \
1200 }
1201
Charles Crayne1f8bc4c2007-11-06 18:27:23 -08001202static void gencode(int32_t segment, int64_t offset, int bits,
1203 insn * ins, const char *codes, int64_t insn_end)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001204{
Keith Kaniosa6dfa782007-04-13 16:47:53 +00001205 static char condval[] = { /* conditional opcodes */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001206 0x7, 0x3, 0x2, 0x6, 0x2, 0x4, 0xF, 0xD, 0xC, 0xE, 0x6, 0x2,
1207 0x3, 0x7, 0x3, 0x5, 0xE, 0xC, 0xD, 0xF, 0x1, 0xB, 0x9, 0x5,
1208 0x0, 0xA, 0xA, 0xB, 0x8, 0x4
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001209 };
Keith Kaniosb7a89542007-04-12 02:40:54 +00001210 uint8_t c;
1211 uint8_t bytes[4];
Charles Crayne1f8bc4c2007-11-06 18:27:23 -08001212 int64_t size;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001213 int64_t data;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001214 struct operand *opx;
H. Peter Anvin70653092007-10-19 14:42:29 -07001215
H. Peter Anvin839eca22007-10-29 23:12:47 -07001216 while (*codes) {
1217 c = *codes++;
1218 opx = &ins->oprs[c & 3];
1219 switch (c) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001220 case 01:
1221 case 02:
1222 case 03:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001223 EMIT_REX();
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001224 out(offset, segment, codes, OUT_RAWDATA, c, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001225 codes += c;
1226 offset += c;
1227 break;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001228
H. Peter Anvine2c80182005-01-15 22:15:51 +00001229 case 04:
1230 case 06:
1231 switch (ins->oprs[0].basereg) {
1232 case R_CS:
1233 bytes[0] = 0x0E + (c == 0x04 ? 1 : 0);
1234 break;
1235 case R_DS:
1236 bytes[0] = 0x1E + (c == 0x04 ? 1 : 0);
1237 break;
1238 case R_ES:
1239 bytes[0] = 0x06 + (c == 0x04 ? 1 : 0);
1240 break;
1241 case R_SS:
1242 bytes[0] = 0x16 + (c == 0x04 ? 1 : 0);
1243 break;
1244 default:
1245 errfunc(ERR_PANIC,
1246 "bizarre 8086 segment register received");
1247 }
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001248 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001249 offset++;
1250 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001251
H. Peter Anvine2c80182005-01-15 22:15:51 +00001252 case 05:
1253 case 07:
1254 switch (ins->oprs[0].basereg) {
1255 case R_FS:
1256 bytes[0] = 0xA0 + (c == 0x05 ? 1 : 0);
1257 break;
1258 case R_GS:
1259 bytes[0] = 0xA8 + (c == 0x05 ? 1 : 0);
1260 break;
1261 default:
1262 errfunc(ERR_PANIC,
1263 "bizarre 386 segment register received");
1264 }
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001265 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001266 offset++;
1267 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001268
H. Peter Anvine2c80182005-01-15 22:15:51 +00001269 case 010:
1270 case 011:
1271 case 012:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001272 case 013:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001273 EMIT_REX();
H. Peter Anvin839eca22007-10-29 23:12:47 -07001274 bytes[0] = *codes++ + ((regval(opx)) & 7);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001275 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001276 offset += 1;
1277 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001278
H. Peter Anvine2c80182005-01-15 22:15:51 +00001279 case 014:
1280 case 015:
1281 case 016:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001282 case 017:
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001283 /* XXX: warns for legitimate optimizer actions */
H. Peter Anvin839eca22007-10-29 23:12:47 -07001284 if (opx->offset < -128 || opx->offset > 127) {
H. Peter Anvin72c64372008-01-08 22:13:48 -08001285 errfunc(ERR_WARNING | ERR_WARN_NOV,
1286 "signed byte value exceeds bounds");
H. Peter Anvine2c80182005-01-15 22:15:51 +00001287 }
H. Peter Anvineba20a72002-04-30 20:53:55 +00001288
H. Peter Anvin839eca22007-10-29 23:12:47 -07001289 if (opx->segment != NO_SEG) {
1290 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001291 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001292 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001293 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001294 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001295 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001296 NO_SEG);
1297 }
1298 offset += 1;
1299 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001300
H. Peter Anvine2c80182005-01-15 22:15:51 +00001301 case 020:
1302 case 021:
1303 case 022:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001304 case 023:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001305 if (opx->offset < -256 || opx->offset > 255) {
H. Peter Anvin72c64372008-01-08 22:13:48 -08001306 errfunc(ERR_WARNING | ERR_WARN_NOV,
1307 "byte value exceeds bounds");
H. Peter Anvine2c80182005-01-15 22:15:51 +00001308 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001309 if (opx->segment != NO_SEG) {
1310 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001311 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001312 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001313 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001314 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001315 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001316 NO_SEG);
1317 }
1318 offset += 1;
1319 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001320
H. Peter Anvine2c80182005-01-15 22:15:51 +00001321 case 024:
1322 case 025:
1323 case 026:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001324 case 027:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001325 if (opx->offset < 0 || opx->offset > 255)
H. Peter Anvin72c64372008-01-08 22:13:48 -08001326 errfunc(ERR_WARNING | ERR_WARN_NOV,
1327 "unsigned byte value exceeds bounds");
H. Peter Anvin839eca22007-10-29 23:12:47 -07001328 if (opx->segment != NO_SEG) {
1329 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001330 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001331 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001332 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001333 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001334 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001335 NO_SEG);
1336 }
1337 offset += 1;
1338 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001339
H. Peter Anvine2c80182005-01-15 22:15:51 +00001340 case 030:
1341 case 031:
1342 case 032:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001343 case 033:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001344 data = opx->offset;
1345 if (opx->segment == NO_SEG && opx->wrt == NO_SEG)
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001346 warn_overflow(2, data);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001347 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001348 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001349 offset += 2;
1350 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001351
H. Peter Anvine2c80182005-01-15 22:15:51 +00001352 case 034:
1353 case 035:
1354 case 036:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001355 case 037:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001356 if (opx->type & (BITS16 | BITS32))
1357 size = (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001358 else
1359 size = (bits == 16) ? 2 : 4;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001360 data = opx->offset;
1361 if (opx->segment == NO_SEG && opx->wrt == NO_SEG)
H. Peter Anvin10e27272007-10-29 22:56:08 -07001362 warn_overflow(size, data);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001363 out(offset, segment, &data, OUT_ADDRESS, size,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001364 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001365 offset += size;
1366 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001367
H. Peter Anvine2c80182005-01-15 22:15:51 +00001368 case 040:
1369 case 041:
1370 case 042:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001371 case 043:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001372 data = opx->offset;
H. Peter Anvin72c64372008-01-08 22:13:48 -08001373 if (opx->segment == NO_SEG && opx->wrt == NO_SEG)
1374 warn_overflow(4, data);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001375 out(offset, segment, &data, OUT_ADDRESS, 4,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001376 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001377 offset += 4;
1378 break;
H. Peter Anvin3ba46772002-05-27 23:19:35 +00001379
H. Peter Anvine2c80182005-01-15 22:15:51 +00001380 case 044:
1381 case 045:
1382 case 046:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001383 case 047:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001384 data = opx->offset;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001385 size = ins->addr_size >> 3;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001386 if (opx->segment == NO_SEG &&
1387 opx->wrt == NO_SEG)
H. Peter Anvin10e27272007-10-29 22:56:08 -07001388 warn_overflow(size, data);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001389 out(offset, segment, &data, OUT_ADDRESS, size,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001390 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001391 offset += size;
1392 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001393
H. Peter Anvine2c80182005-01-15 22:15:51 +00001394 case 050:
1395 case 051:
1396 case 052:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001397 case 053:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001398 if (opx->segment != segment)
H. Peter Anvine2c80182005-01-15 22:15:51 +00001399 errfunc(ERR_NONFATAL,
1400 "short relative jump outside segment");
H. Peter Anvin839eca22007-10-29 23:12:47 -07001401 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001402 if (data > 127 || data < -128)
1403 errfunc(ERR_NONFATAL, "short jump is out of range");
1404 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001405 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001406 offset += 1;
1407 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001408
Keith Kaniosb7a89542007-04-12 02:40:54 +00001409 case 054:
1410 case 055:
1411 case 056:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001412 case 057:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001413 data = (int64_t)opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001414 out(offset, segment, &data, OUT_ADDRESS, 8,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001415 opx->segment, opx->wrt);
Keith Kaniosb7a89542007-04-12 02:40:54 +00001416 offset += 8;
1417 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001418
H. Peter Anvine2c80182005-01-15 22:15:51 +00001419 case 060:
1420 case 061:
1421 case 062:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001422 case 063:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001423 if (opx->segment != segment) {
1424 data = opx->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001425 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001426 OUT_REL2ADR, insn_end - offset,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001427 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001428 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001429 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001430 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001431 OUT_ADDRESS, 2, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001432 }
1433 offset += 2;
1434 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001435
H. Peter Anvine2c80182005-01-15 22:15:51 +00001436 case 064:
1437 case 065:
1438 case 066:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001439 case 067:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001440 if (opx->type & (BITS16 | BITS32 | BITS64))
1441 size = (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001442 else
1443 size = (bits == 16) ? 2 : 4;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001444 if (opx->segment != segment) {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001445 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001446 out(offset, segment, &data,
1447 size == 2 ? OUT_REL2ADR : OUT_REL4ADR,
1448 insn_end - offset, opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001449 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001450 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001451 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001452 OUT_ADDRESS, size, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001453 }
1454 offset += size;
1455 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001456
H. Peter Anvine2c80182005-01-15 22:15:51 +00001457 case 070:
1458 case 071:
1459 case 072:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001460 case 073:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001461 if (opx->segment != segment) {
1462 data = opx->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001463 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001464 OUT_REL4ADR, insn_end - offset,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001465 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001466 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001467 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001468 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001469 OUT_ADDRESS, 4, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001470 }
1471 offset += 4;
1472 break;
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001473
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001474 case 074:
1475 case 075:
1476 case 076:
1477 case 077:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001478 if (opx->segment == NO_SEG)
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001479 errfunc(ERR_NONFATAL, "value referenced by FAR is not"
1480 " relocatable");
1481 data = 0L;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001482 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001483 outfmt->segbase(1 + opx->segment),
1484 opx->wrt);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001485 offset += 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001486 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001487
H. Peter Anvine2c80182005-01-15 22:15:51 +00001488 case 0140:
1489 case 0141:
1490 case 0142:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001491 case 0143:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001492 data = opx->offset;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001493 if (is_sbyte16(ins, c & 3)) {
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001494 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001495 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001496 NO_SEG);
1497 offset++;
1498 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001499 if (opx->segment == NO_SEG &&
1500 opx->wrt == NO_SEG)
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001501 warn_overflow(2, data);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001502 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001503 opx->segment, opx->wrt);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001504 offset += 2;
1505 }
1506 break;
1507
1508 case 0144:
1509 case 0145:
1510 case 0146:
1511 case 0147:
1512 EMIT_REX();
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001513 bytes[0] = *codes++;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001514 if (is_sbyte16(ins, c & 3))
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001515 bytes[0] |= 2; /* s-bit */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001516 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001517 offset++;
1518 break;
1519
1520 case 0150:
1521 case 0151:
1522 case 0152:
1523 case 0153:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001524 data = opx->offset;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001525 if (is_sbyte32(ins, c & 3)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001526 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001527 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001528 NO_SEG);
1529 offset++;
1530 } else {
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001531 out(offset, segment, &data, OUT_ADDRESS, 4,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001532 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001533 offset += 4;
1534 }
1535 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001536
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001537 case 0154:
1538 case 0155:
1539 case 0156:
1540 case 0157:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001541 EMIT_REX();
H. Peter Anvine2c80182005-01-15 22:15:51 +00001542 bytes[0] = *codes++;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001543 if (is_sbyte32(ins, c & 3))
H. Peter Anvine2c80182005-01-15 22:15:51 +00001544 bytes[0] |= 2; /* s-bit */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001545 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001546 offset++;
1547 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001548
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001549 case 0160:
1550 case 0161:
1551 case 0162:
1552 case 0163:
1553 case 0164:
1554 case 0165:
1555 case 0166:
1556 case 0167:
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001557 break;
1558
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001559 case 0170:
H. Peter Anvinc189b442007-10-05 17:04:32 -07001560 EMIT_REX();
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001561 bytes[0] = 0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001562 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001563 offset += 1;
1564 break;
1565
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001566 case 0171:
1567 bytes[0] =
1568 (ins->drexdst << 4) |
1569 (ins->rex & REX_OC ? 0x08 : 0) |
1570 (ins->rex & (REX_R|REX_X|REX_B));
1571 ins->rex = 0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001572 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001573 offset++;
1574 break;
1575
H. Peter Anvind85d2502008-05-04 17:53:31 -07001576 case 0172:
1577 c = *codes++;
1578 opx = &ins->oprs[c >> 3];
1579 bytes[0] = regvals[opx->basereg] << 4;
1580 opx = &ins->oprs[c & 7];
1581 if (opx->segment != NO_SEG || opx->wrt != NO_SEG) {
1582 errfunc(ERR_NONFATAL,
1583 "non-absolute expression not permitted as argument %d",
1584 c & 7);
1585 } else {
1586 if (opx->offset & ~15) {
1587 errfunc(ERR_WARNING | ERR_WARN_NOV,
1588 "four-bit argument exceeds bounds");
1589 }
1590 bytes[0] |= opx->offset & 15;
1591 }
1592 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1593 offset++;
1594 break;
1595
H. Peter Anvind58656f2008-05-06 20:11:14 -07001596 case 0173:
1597 c = *codes++;
1598 opx = &ins->oprs[c >> 4];
1599 bytes[0] = regvals[opx->basereg] << 4;
1600 bytes[0] |= c & 15;
1601 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1602 offset++;
1603 break;
1604
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001605 case 0250:
1606 case 0251:
1607 case 0252:
1608 case 0253:
1609 data = opx->offset;
1610 /* is_sbyte32() is right here, we have already warned */
1611 if (is_sbyte32(ins, c & 3)) {
1612 bytes[0] = data;
1613 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
1614 NO_SEG);
1615 offset++;
1616 } else {
1617 out(offset, segment, &data, OUT_ADDRESS, 4,
1618 opx->segment, opx->wrt);
1619 offset += 4;
1620 }
1621 break;
1622
H. Peter Anvind85d2502008-05-04 17:53:31 -07001623 case 0260:
1624 case 0261:
1625 case 0262:
1626 case 0263:
1627 case 0270:
1628 codes += 2;
1629 if (ins->vex_m != 1 || (ins->rex & (REX_W|REX_X|REX_B))) {
1630 bytes[0] = 0xc4;
H. Peter Anvin4d2c38c2008-05-04 23:15:13 -07001631 bytes[1] = ins->vex_m | ((~ins->rex & 7) << 5);
H. Peter Anvind85d2502008-05-04 17:53:31 -07001632 bytes[2] = ((ins->rex & REX_W) << (7-3)) |
H. Peter Anvin4d2c38c2008-05-04 23:15:13 -07001633 ((~ins->drexdst & 15)<< 3) | (ins->vex_wlp & 07);
H. Peter Anvind85d2502008-05-04 17:53:31 -07001634 out(offset, segment, &bytes, OUT_RAWDATA, 3, NO_SEG, NO_SEG);
1635 offset += 3;
1636 } else {
1637 bytes[0] = 0xc5;
H. Peter Anvin4d2c38c2008-05-04 23:15:13 -07001638 bytes[1] = ((~ins->rex & REX_R) << (7-2)) |
1639 ((~ins->drexdst & 15) << 3) | (ins->vex_wlp & 07);
H. Peter Anvind85d2502008-05-04 17:53:31 -07001640 out(offset, segment, &bytes, OUT_RAWDATA, 2, NO_SEG, NO_SEG);
1641 offset += 2;
1642 }
1643 break;
1644
H. Peter Anvine2c80182005-01-15 22:15:51 +00001645 case 0300:
1646 case 0301:
1647 case 0302:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001648 case 0303:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001649 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001650
H. Peter Anvine2c80182005-01-15 22:15:51 +00001651 case 0310:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001652 if (bits == 32 && !has_prefix(ins, PPS_ASIZE, P_A16)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001653 *bytes = 0x67;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001654 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001655 offset += 1;
1656 } else
1657 offset += 0;
1658 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001659
H. Peter Anvine2c80182005-01-15 22:15:51 +00001660 case 0311:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001661 if (bits != 32 && !has_prefix(ins, PPS_ASIZE, P_A32)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001662 *bytes = 0x67;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001663 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001664 offset += 1;
1665 } else
1666 offset += 0;
1667 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001668
H. Peter Anvine2c80182005-01-15 22:15:51 +00001669 case 0312:
1670 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001671
Keith Kaniosb7a89542007-04-12 02:40:54 +00001672 case 0313:
1673 ins->rex = 0;
1674 break;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07001675
H. Peter Anvin23440102007-11-12 21:02:33 -08001676 case 0314:
1677 case 0315:
1678 case 0316:
1679 case 0317:
1680 break;
1681
H. Peter Anvine2c80182005-01-15 22:15:51 +00001682 case 0320:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001683 if (bits != 16) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001684 *bytes = 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001685 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001686 offset += 1;
1687 } else
1688 offset += 0;
1689 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001690
H. Peter Anvine2c80182005-01-15 22:15:51 +00001691 case 0321:
1692 if (bits == 16) {
1693 *bytes = 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001694 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001695 offset += 1;
1696 } else
1697 offset += 0;
1698 break;
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001699
H. Peter Anvine2c80182005-01-15 22:15:51 +00001700 case 0322:
H. Peter Anvin70653092007-10-19 14:42:29 -07001701 case 0323:
1702 break;
1703
Keith Kaniosb7a89542007-04-12 02:40:54 +00001704 case 0324:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001705 ins->rex |= REX_W;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001706 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001707
H. Peter Anvine2c80182005-01-15 22:15:51 +00001708 case 0330:
1709 *bytes = *codes++ ^ condval[ins->condition];
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001710 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001711 offset += 1;
1712 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001713
H. Peter Anvine2c80182005-01-15 22:15:51 +00001714 case 0331:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001715 break;
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001716
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001717 case 0332:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001718 case 0333:
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001719 *bytes = c - 0332 + 0xF2;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001720 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001721 offset += 1;
1722 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001723
Keith Kanios48af1772007-08-17 07:37:52 +00001724 case 0334:
1725 if (ins->rex & REX_R) {
1726 *bytes = 0xF0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001727 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
Keith Kanios48af1772007-08-17 07:37:52 +00001728 offset += 1;
1729 }
1730 ins->rex &= ~(REX_L|REX_R);
1731 break;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001732
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001733 case 0335:
1734 break;
1735
H. Peter Anvine2c80182005-01-15 22:15:51 +00001736 case 0340:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001737 if (ins->oprs[0].segment != NO_SEG)
1738 errfunc(ERR_PANIC, "non-constant BSS size in pass two");
1739 else {
H. Peter Anvin428fd672007-11-15 10:25:52 -08001740 int64_t size = ins->oprs[0].offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001741 if (size > 0)
1742 out(offset, segment, NULL,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001743 OUT_RESERVE, size, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001744 offset += size;
1745 }
1746 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001747
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001748 case 0364:
1749 case 0365:
1750 break;
1751
Keith Kanios48af1772007-08-17 07:37:52 +00001752 case 0366:
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001753 case 0367:
1754 *bytes = c - 0366 + 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001755 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
Keith Kanios48af1772007-08-17 07:37:52 +00001756 offset += 1;
1757 break;
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001758
H. Peter Anvine2c80182005-01-15 22:15:51 +00001759 case 0370:
1760 case 0371:
1761 case 0372:
1762 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001763
H. Peter Anvine2c80182005-01-15 22:15:51 +00001764 case 0373:
1765 *bytes = bits == 16 ? 3 : 5;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001766 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001767 offset += 1;
1768 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001769
H. Peter Anvine2c80182005-01-15 22:15:51 +00001770 default: /* can't do it by 'case' statements */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001771 if (c >= 0100 && c <= 0277) { /* it's an EA */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001772 ea ea_data;
1773 int rfield;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001774 int32_t rflags;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001775 uint8_t *p;
1776 int32_t s;
H. Peter Anvin70653092007-10-19 14:42:29 -07001777
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001778 if (c <= 0177) {
1779 /* pick rfield from operand b */
1780 rflags = regflag(&ins->oprs[c & 7]);
1781 rfield = regvals[ins->oprs[c & 7].basereg];
1782 } else {
1783 /* rfield is constant */
1784 rflags = 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001785 rfield = c & 7;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001786 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001787
1788 if (!process_ea
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001789 (&ins->oprs[(c >> 3) & 7], &ea_data, bits,
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001790 ins->addr_size, rfield, rflags, ins->forw_ref)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001791 errfunc(ERR_NONFATAL, "invalid effective address");
1792 }
H. Peter Anvin70653092007-10-19 14:42:29 -07001793
Charles Crayne7e975552007-11-03 22:06:13 -07001794
H. Peter Anvine2c80182005-01-15 22:15:51 +00001795 p = bytes;
1796 *p++ = ea_data.modrm;
1797 if (ea_data.sib_present)
1798 *p++ = ea_data.sib;
1799
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001800 /* DREX suffixes come between the SIB and the displacement */
1801 if (ins->rex & REX_D) {
1802 *p++ =
1803 (ins->drexdst << 4) |
1804 (ins->rex & REX_OC ? 0x08 : 0) |
1805 (ins->rex & (REX_R|REX_X|REX_B));
1806 ins->rex = 0;
1807 }
1808
H. Peter Anvine2c80182005-01-15 22:15:51 +00001809 s = p - bytes;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001810 out(offset, segment, bytes, OUT_RAWDATA, s, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001811
1812 switch (ea_data.bytes) {
1813 case 0:
1814 break;
1815 case 1:
1816 if (ins->oprs[(c >> 3) & 7].segment != NO_SEG) {
1817 data = ins->oprs[(c >> 3) & 7].offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001818 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001819 ins->oprs[(c >> 3) & 7].segment,
1820 ins->oprs[(c >> 3) & 7].wrt);
1821 } else {
1822 *bytes = ins->oprs[(c >> 3) & 7].offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001823 out(offset, segment, bytes, OUT_RAWDATA, 1,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001824 NO_SEG, NO_SEG);
1825 }
1826 s++;
1827 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001828 case 8:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001829 case 2:
1830 case 4:
1831 data = ins->oprs[(c >> 3) & 7].offset;
Charles Crayne7e975552007-11-03 22:06:13 -07001832 warn_overflow(ea_data.bytes, data);
H. Peter Anvind0b0d282007-09-28 17:17:20 -07001833 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001834 ea_data.rip ? OUT_REL4ADR : OUT_ADDRESS,
1835 ea_data.bytes,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001836 ins->oprs[(c >> 3) & 7].segment,
1837 ins->oprs[(c >> 3) & 7].wrt);
1838 s += ea_data.bytes;
1839 break;
1840 }
1841 offset += s;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001842 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001843 errfunc(ERR_PANIC, "internal instruction table corrupt"
1844 ": instruction code 0x%02X given", c);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001845 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001846 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001847 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001848}
1849
H. Peter Anvin0ec60e62007-07-07 01:59:52 +00001850static int32_t regflag(const operand * o)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001851{
1852 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1853 errfunc(ERR_PANIC, "invalid operand passed to regflag()");
1854 }
1855 return reg_flags[o->basereg];
1856}
1857
H. Peter Anvin5b0e3ec2007-07-07 02:01:08 +00001858static int32_t regval(const operand * o)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001859{
H. Peter Anvine2c80182005-01-15 22:15:51 +00001860 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1861 errfunc(ERR_PANIC, "invalid operand passed to regval()");
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001862 }
H. Peter Anvin232badb2002-06-06 02:41:20 +00001863 return regvals[o->basereg];
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001864}
1865
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001866static int op_rexflags(const operand * o, int mask)
1867{
1868 int32_t flags;
1869 int val;
1870
1871 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1872 errfunc(ERR_PANIC, "invalid operand passed to op_rexflags()");
1873 }
1874
1875 flags = reg_flags[o->basereg];
1876 val = regvals[o->basereg];
1877
1878 return rexflags(val, flags, mask);
1879}
1880
1881static int rexflags(int val, int32_t flags, int mask)
1882{
1883 int rex = 0;
1884
1885 if (val >= 8)
1886 rex |= REX_B|REX_X|REX_R;
1887 if (flags & BITS64)
1888 rex |= REX_W;
1889 if (!(REG_HIGH & ~flags)) /* AH, CH, DH, BH */
1890 rex |= REX_H;
1891 else if (!(REG8 & ~flags) && val >= 4) /* SPL, BPL, SIL, DIL */
1892 rex |= REX_P;
1893
1894 return rex & mask;
1895}
1896
H. Peter Anvin3360d792007-09-11 04:16:57 +00001897static int matches(const struct itemplate *itemp, insn * instruction, int bits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001898{
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001899 int i, size[MAX_OPERANDS], asize, oprs, ret;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001900
1901 ret = 100;
1902
1903 /*
1904 * Check the opcode
1905 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001906 if (itemp->opcode != instruction->opcode)
1907 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001908
1909 /*
1910 * Count the operands
1911 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001912 if (itemp->operands != instruction->operands)
1913 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001914
1915 /*
1916 * Check that no spurious colons or TOs are present
1917 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001918 for (i = 0; i < itemp->operands; i++)
1919 if (instruction->oprs[i].type & ~itemp->opd[i] & (COLON | TO))
1920 return 0;
H. Peter Anvin70653092007-10-19 14:42:29 -07001921
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001922 /*
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001923 * Process size flags
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001924 */
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001925 if (itemp->flags & IF_ARMASK) {
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001926 memset(size, 0, sizeof size);
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001927
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001928 i = ((itemp->flags & IF_ARMASK) >> IF_ARSHFT) - 1;
1929
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001930 switch (itemp->flags & IF_SMASK) {
1931 case IF_SB:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001932 size[i] = BITS8;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001933 break;
1934 case IF_SW:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001935 size[i] = BITS16;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001936 break;
1937 case IF_SD:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001938 size[i] = BITS32;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001939 break;
1940 case IF_SQ:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001941 size[i] = BITS64;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001942 break;
H. Peter Anvin41c9f6f2007-09-18 13:01:32 -07001943 case IF_SO:
1944 size[i] = BITS128;
1945 break;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001946 case IF_SZ:
1947 switch (bits) {
1948 case 16:
1949 size[i] = BITS16;
1950 break;
1951 case 32:
1952 size[i] = BITS32;
1953 break;
1954 case 64:
1955 size[i] = BITS64;
1956 break;
1957 }
1958 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001959 default:
1960 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001961 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001962 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001963 asize = 0;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001964 switch (itemp->flags & IF_SMASK) {
1965 case IF_SB:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001966 asize = BITS8;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001967 break;
1968 case IF_SW:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001969 asize = BITS16;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001970 break;
1971 case IF_SD:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001972 asize = BITS32;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001973 break;
1974 case IF_SQ:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001975 asize = BITS64;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001976 break;
H. Peter Anvin41c9f6f2007-09-18 13:01:32 -07001977 case IF_SO:
1978 asize = BITS128;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001979 break;
1980 case IF_SZ:
1981 switch (bits) {
1982 case 16:
1983 asize = BITS16;
1984 break;
1985 case 32:
1986 asize = BITS32;
1987 break;
1988 case 64:
1989 asize = BITS64;
1990 break;
1991 }
H. Peter Anvin41c9f6f2007-09-18 13:01:32 -07001992 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001993 default:
1994 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001995 }
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001996 for (i = 0; i < MAX_OPERANDS; i++)
1997 size[i] = asize;
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001998 }
H. Peter Anvin70653092007-10-19 14:42:29 -07001999
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002000 /*
2001 * Check that the operand flags all match up
2002 */
2003 for (i = 0; i < itemp->operands; i++) {
2004 int32_t type = instruction->oprs[i].type;
2005 if (!(type & SIZE_MASK))
2006 type |= size[i];
H. Peter Anvind85d2502008-05-04 17:53:31 -07002007
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002008 if (itemp->opd[i] & SAME_AS) {
2009 int j = itemp->opd[i] & ~SAME_AS;
2010 if (type != instruction->oprs[j].type ||
2011 instruction->oprs[i].basereg != instruction->oprs[j].basereg)
2012 return 0;
2013 } else if (itemp->opd[i] & ~type ||
2014 ((itemp->opd[i] & SIZE_MASK) &&
2015 ((itemp->opd[i] ^ type) & SIZE_MASK))) {
2016 if ((itemp->opd[i] & ~type & ~SIZE_MASK) ||
2017 (type & SIZE_MASK))
2018 return 0;
2019 else
2020 return 1;
2021 }
2022 }
2023
2024 /*
2025 * Check operand sizes
2026 */
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002027 if (itemp->flags & (IF_SM | IF_SM2)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002028 oprs = (itemp->flags & IF_SM2 ? 2 : itemp->operands);
2029 asize = 0;
2030 for (i = 0; i < oprs; i++) {
2031 if ((asize = itemp->opd[i] & SIZE_MASK) != 0) {
2032 int j;
2033 for (j = 0; j < oprs; j++)
2034 size[j] = asize;
2035 break;
2036 }
2037 }
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002038 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002039 oprs = itemp->operands;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002040 }
2041
Keith Kaniosb7a89542007-04-12 02:40:54 +00002042 for (i = 0; i < itemp->operands; i++) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002043 if (!(itemp->opd[i] & SIZE_MASK) &&
2044 (instruction->oprs[i].type & SIZE_MASK & ~size[i]))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002045 return 2;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002046 }
2047
H. Peter Anvinaf535c12002-04-30 20:59:21 +00002048 /*
2049 * Check template is okay at the set cpu level
2050 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002051 if (((itemp->flags & IF_PLEVEL) > cpu))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002052 return 3;
H. Peter Anvin70653092007-10-19 14:42:29 -07002053
Keith Kaniosb7a89542007-04-12 02:40:54 +00002054 /*
2055 * Check if instruction is available in long mode
2056 */
2057 if ((itemp->flags & IF_NOLONG) && (bits == 64))
2058 return 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002059
H. Peter Anvinaf535c12002-04-30 20:59:21 +00002060 /*
2061 * Check if special handling needed for Jumps
2062 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002063 if ((uint8_t)(itemp->code[0]) >= 0370)
H. Peter Anvine2c80182005-01-15 22:15:51 +00002064 return 99;
2065
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002066 return ret;
2067}
2068
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002069static ea *process_ea(operand * input, ea * output, int bits,
2070 int addrbits, int rfield, int32_t rflags, int forw_ref)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002071{
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002072 output->rip = false;
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00002073
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002074 /* REX flags for the rfield operand */
2075 output->rex |= rexflags(rfield, rflags, REX_R|REX_P|REX_W|REX_H);
2076
Keith Kaniosb7a89542007-04-12 02:40:54 +00002077 if (!(REGISTER & ~input->type)) { /* register direct */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002078 int i;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002079 int32_t f;
2080
2081 if (input->basereg < EXPR_REG_START /* Verify as Register */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002082 || input->basereg >= REG_ENUM_LIMIT)
H. Peter Anvine2c80182005-01-15 22:15:51 +00002083 return NULL;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002084 f = regflag(input);
Keith Kaniosb7a89542007-04-12 02:40:54 +00002085 i = regvals[input->basereg];
Keith Kaniosb7a89542007-04-12 02:40:54 +00002086
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002087 if (REG_EA & ~f)
2088 return NULL; /* Invalid EA register */
H. Peter Anvin70653092007-10-19 14:42:29 -07002089
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002090 output->rex |= op_rexflags(input, REX_B|REX_P|REX_W|REX_H);
2091
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002092 output->sib_present = false; /* no SIB necessary */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002093 output->bytes = 0; /* no offset necessary either */
2094 output->modrm = 0xC0 | ((rfield & 7) << 3) | (i & 7);
H. Peter Anvine2c80182005-01-15 22:15:51 +00002095 } else { /* it's a memory reference */
2096 if (input->basereg == -1
2097 && (input->indexreg == -1 || input->scale == 0)) {
2098 /* it's a pure offset */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002099 if (bits == 64 && (~input->type & IP_REL)) {
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002100 int scale, index, base;
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002101 output->sib_present = true;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002102 scale = 0;
2103 index = 4;
2104 base = 5;
2105 output->sib = (scale << 6) | (index << 3) | base;
2106 output->bytes = 4;
2107 output->modrm = 4 | ((rfield & 7) << 3);
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002108 output->rip = false;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002109 } else {
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002110 output->sib_present = false;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002111 output->bytes = (addrbits != 16 ? 4 : 2);
2112 output->modrm = (addrbits != 16 ? 5 : 6) | ((rfield & 7) << 3);
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002113 output->rip = bits == 64;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002114 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00002115 } else { /* it's an indirection */
2116 int i = input->indexreg, b = input->basereg, s = input->scale;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002117 int32_t o = input->offset, seg = input->segment;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002118 int hb = input->hintbase, ht = input->hinttype;
2119 int t;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002120 int it, bt;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002121 int32_t ix, bx; /* register flags */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002122
H. Peter Anvine2c80182005-01-15 22:15:51 +00002123 if (s == 0)
2124 i = -1; /* make this easy, at least */
H. Peter Anvin70653092007-10-19 14:42:29 -07002125
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002126 if (i >= EXPR_REG_START && i < REG_ENUM_LIMIT) {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002127 it = regvals[i];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002128 ix = reg_flags[i];
2129 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002130 it = -1;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002131 ix = 0;
2132 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002133
H. Peter Anvinb0c54622007-10-28 23:21:46 -07002134 if (b >= EXPR_REG_START && b < REG_ENUM_LIMIT) {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002135 bt = regvals[b];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002136 bx = reg_flags[b];
2137 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002138 bt = -1;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002139 bx = 0;
2140 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002141
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002142 /* check for a 32/64-bit memory reference... */
2143 if ((ix|bx) & (BITS32|BITS64)) {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002144 /* it must be a 32/64-bit memory reference. Firstly we have
2145 * to check that all registers involved are type E/Rxx. */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002146 int32_t sok = BITS32|BITS64;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002147
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002148 if (it != -1) {
2149 if (!(REG64 & ~ix) || !(REG32 & ~ix))
2150 sok &= ix;
2151 else
2152 return NULL;
2153 }
2154
2155 if (bt != -1) {
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00002156 if (REG_GPR & ~bx)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002157 return NULL; /* Invalid register */
H. Peter Anvina57e8d42007-05-30 03:44:02 +00002158 if (~sok & bx & SIZE_MASK)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002159 return NULL; /* Invalid size */
H. Peter Anvinb0c54622007-10-28 23:21:46 -07002160 sok &= bx;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002161 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002162
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002163 /* While we're here, ensure the user didn't specify
2164 WORD or QWORD. */
2165 if (input->disp_size == 16 || input->disp_size == 64)
2166 return NULL;
2167
2168 if (addrbits == 16 ||
2169 (addrbits == 32 && !(sok & BITS32)) ||
2170 (addrbits == 64 && !(sok & BITS64)))
2171 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002172
Keith Kaniosb7a89542007-04-12 02:40:54 +00002173 /* now reorganize base/index */
2174 if (s == 1 && bt != it && bt != -1 && it != -1 &&
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002175 ((hb == b && ht == EAH_NOTBASE)
2176 || (hb == i && ht == EAH_MAKEBASE))) {
2177 /* swap if hints say so */
2178 t = bt, bt = it, it = t;
2179 t = bx, bx = ix, ix = t;
2180 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00002181 if (bt == it) /* convert EAX+2*EAX to 3*EAX */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002182 bt = -1, bx = 0, s++;
2183 if (bt == -1 && s == 1 && !(hb == it && ht == EAH_NOTBASE)) {
2184 /* make single reg base, unless hint */
2185 bt = it, bx = ix, it = -1, ix = 0;
2186 }
H. Peter Anvinf5843c62007-09-10 18:59:26 +00002187 if (((s == 2 && it != REG_NUM_ESP
H. Peter Anvine2c80182005-01-15 22:15:51 +00002188 && !(input->eaflags & EAF_TIMESTWO)) || s == 3
Keith Kaniosb7a89542007-04-12 02:40:54 +00002189 || s == 5 || s == 9) && bt == -1)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002190 bt = it, bx = ix, s--; /* convert 3*EAX to EAX+2*EAX */
Keith Kanios48af1772007-08-17 07:37:52 +00002191 if (it == -1 && (bt & 7) != REG_NUM_ESP
H. Peter Anvine2c80182005-01-15 22:15:51 +00002192 && (input->eaflags & EAF_TIMESTWO))
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002193 it = bt, ix = bx, bt = -1, bx = 0, s = 1;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002194 /* convert [NOSPLIT EAX] to sib format with 0x0 displacement */
Keith Kanios48af1772007-08-17 07:37:52 +00002195 if (s == 1 && it == REG_NUM_ESP) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002196 /* swap ESP into base if scale is 1 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002197 t = it, it = bt, bt = t;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002198 t = ix, ix = bx, bx = t;
2199 }
Keith Kanios48af1772007-08-17 07:37:52 +00002200 if (it == REG_NUM_ESP
Keith Kaniosb7a89542007-04-12 02:40:54 +00002201 || (s != 1 && s != 2 && s != 4 && s != 8 && it != -1))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002202 return NULL; /* wrong, for various reasons */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002203
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002204 output->rex |= rexflags(it, ix, REX_X);
2205 output->rex |= rexflags(bt, bx, REX_B);
Keith Kaniosb7a89542007-04-12 02:40:54 +00002206
Keith Kanios48af1772007-08-17 07:37:52 +00002207 if (it == -1 && (bt & 7) != REG_NUM_ESP) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002208 /* no SIB needed */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002209 int mod, rm;
H. Peter Anvin70653092007-10-19 14:42:29 -07002210
Keith Kaniosb7a89542007-04-12 02:40:54 +00002211 if (bt == -1) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002212 rm = 5;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002213 mod = 0;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002214 } else {
2215 rm = (bt & 7);
Keith Kanios48af1772007-08-17 07:37:52 +00002216 if (rm != REG_NUM_EBP && o == 0 &&
Keith Kaniosb7a89542007-04-12 02:40:54 +00002217 seg == NO_SEG && !forw_ref &&
2218 !(input->eaflags &
2219 (EAF_BYTEOFFS | EAF_WORDOFFS)))
2220 mod = 0;
2221 else if (input->eaflags & EAF_BYTEOFFS ||
2222 (o >= -128 && o <= 127 && seg == NO_SEG
2223 && !forw_ref
2224 && !(input->eaflags & EAF_WORDOFFS)))
2225 mod = 1;
2226 else
2227 mod = 2;
2228 }
H. Peter Anvinea838272002-04-30 20:51:53 +00002229
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002230 output->sib_present = false;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002231 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2232 output->modrm = (mod << 6) | ((rfield & 7) << 3) | rm;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002233 } else {
2234 /* we need a SIB */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002235 int mod, scale, index, base;
H. Peter Anvin70653092007-10-19 14:42:29 -07002236
Keith Kaniosb7a89542007-04-12 02:40:54 +00002237 if (it == -1)
2238 index = 4, s = 1;
2239 else
2240 index = (it & 7);
H. Peter Anvin70653092007-10-19 14:42:29 -07002241
H. Peter Anvine2c80182005-01-15 22:15:51 +00002242 switch (s) {
2243 case 1:
2244 scale = 0;
2245 break;
2246 case 2:
2247 scale = 1;
2248 break;
2249 case 4:
2250 scale = 2;
2251 break;
2252 case 8:
2253 scale = 3;
2254 break;
2255 default: /* then what the smeg is it? */
2256 return NULL; /* panic */
2257 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002258
Keith Kaniosb7a89542007-04-12 02:40:54 +00002259 if (bt == -1) {
2260 base = 5;
2261 mod = 0;
2262 } else {
2263 base = (bt & 7);
Keith Kanios48af1772007-08-17 07:37:52 +00002264 if (base != REG_NUM_EBP && o == 0 &&
H. Peter Anvine2c80182005-01-15 22:15:51 +00002265 seg == NO_SEG && !forw_ref &&
2266 !(input->eaflags &
Keith Kaniosb7a89542007-04-12 02:40:54 +00002267 (EAF_BYTEOFFS | EAF_WORDOFFS)))
2268 mod = 0;
2269 else if (input->eaflags & EAF_BYTEOFFS ||
2270 (o >= -128 && o <= 127 && seg == NO_SEG
2271 && !forw_ref
2272 && !(input->eaflags & EAF_WORDOFFS)))
2273 mod = 1;
2274 else
2275 mod = 2;
2276 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002277
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002278 output->sib_present = true;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002279 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2280 output->modrm = (mod << 6) | ((rfield & 7) << 3) | 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002281 output->sib = (scale << 6) | (index << 3) | base;
2282 }
2283 } else { /* it's 16-bit */
2284 int mod, rm;
H. Peter Anvin70653092007-10-19 14:42:29 -07002285
Keith Kaniosb7a89542007-04-12 02:40:54 +00002286 /* check for 64-bit long mode */
2287 if (addrbits == 64)
2288 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002289
H. Peter Anvine2c80182005-01-15 22:15:51 +00002290 /* check all registers are BX, BP, SI or DI */
2291 if ((b != -1 && b != R_BP && b != R_BX && b != R_SI
2292 && b != R_DI) || (i != -1 && i != R_BP && i != R_BX
2293 && i != R_SI && i != R_DI))
2294 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002295
Keith Kaniosb7a89542007-04-12 02:40:54 +00002296 /* ensure the user didn't specify DWORD/QWORD */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002297 if (input->disp_size == 32 || input->disp_size == 64)
H. Peter Anvine2c80182005-01-15 22:15:51 +00002298 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002299
H. Peter Anvine2c80182005-01-15 22:15:51 +00002300 if (s != 1 && i != -1)
2301 return NULL; /* no can do, in 16-bit EA */
2302 if (b == -1 && i != -1) {
2303 int tmp = b;
2304 b = i;
2305 i = tmp;
2306 } /* swap */
2307 if ((b == R_SI || b == R_DI) && i != -1) {
2308 int tmp = b;
2309 b = i;
2310 i = tmp;
2311 }
2312 /* have BX/BP as base, SI/DI index */
2313 if (b == i)
2314 return NULL; /* shouldn't ever happen, in theory */
2315 if (i != -1 && b != -1 &&
2316 (i == R_BP || i == R_BX || b == R_SI || b == R_DI))
2317 return NULL; /* invalid combinations */
2318 if (b == -1) /* pure offset: handled above */
2319 return NULL; /* so if it gets to here, panic! */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002320
H. Peter Anvine2c80182005-01-15 22:15:51 +00002321 rm = -1;
2322 if (i != -1)
2323 switch (i * 256 + b) {
2324 case R_SI * 256 + R_BX:
2325 rm = 0;
2326 break;
2327 case R_DI * 256 + R_BX:
2328 rm = 1;
2329 break;
2330 case R_SI * 256 + R_BP:
2331 rm = 2;
2332 break;
2333 case R_DI * 256 + R_BP:
2334 rm = 3;
2335 break;
2336 } else
2337 switch (b) {
2338 case R_SI:
2339 rm = 4;
2340 break;
2341 case R_DI:
2342 rm = 5;
2343 break;
2344 case R_BP:
2345 rm = 6;
2346 break;
2347 case R_BX:
2348 rm = 7;
2349 break;
2350 }
2351 if (rm == -1) /* can't happen, in theory */
2352 return NULL; /* so panic if it does */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002353
H. Peter Anvine2c80182005-01-15 22:15:51 +00002354 if (o == 0 && seg == NO_SEG && !forw_ref && rm != 6 &&
2355 !(input->eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS)))
2356 mod = 0;
2357 else if (input->eaflags & EAF_BYTEOFFS ||
2358 (o >= -128 && o <= 127 && seg == NO_SEG
2359 && !forw_ref
2360 && !(input->eaflags & EAF_WORDOFFS)))
2361 mod = 1;
2362 else
2363 mod = 2;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002364
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002365 output->sib_present = false; /* no SIB - it's 16-bit */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002366 output->bytes = mod; /* bytes of offset needed */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002367 output->modrm = (mod << 6) | ((rfield & 7) << 3) | rm;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002368 }
2369 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002370 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002371
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002372 output->size = 1 + output->sib_present + output->bytes;
2373 return output;
2374}
2375
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002376static void add_asp(insn *ins, int addrbits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002377{
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002378 int j, valid;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002379 int defdisp;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002380
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002381 valid = (addrbits == 64) ? 64|32 : 32|16;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002382
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002383 switch (ins->prefixes[PPS_ASIZE]) {
2384 case P_A16:
2385 valid &= 16;
2386 break;
2387 case P_A32:
2388 valid &= 32;
2389 break;
2390 case P_A64:
2391 valid &= 64;
2392 break;
2393 case P_ASP:
2394 valid &= (addrbits == 32) ? 16 : 32;
2395 break;
2396 default:
2397 break;
2398 }
2399
2400 for (j = 0; j < ins->operands; j++) {
2401 if (!(MEMORY & ~ins->oprs[j].type)) {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002402 int32_t i, b;
H. Peter Anvin70653092007-10-19 14:42:29 -07002403
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002404 /* Verify as Register */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002405 if (ins->oprs[j].indexreg < EXPR_REG_START
2406 || ins->oprs[j].indexreg >= REG_ENUM_LIMIT)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002407 i = 0;
2408 else
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002409 i = reg_flags[ins->oprs[j].indexreg];
H. Peter Anvin70653092007-10-19 14:42:29 -07002410
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002411 /* Verify as Register */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002412 if (ins->oprs[j].basereg < EXPR_REG_START
2413 || ins->oprs[j].basereg >= REG_ENUM_LIMIT)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002414 b = 0;
2415 else
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002416 b = reg_flags[ins->oprs[j].basereg];
H. Peter Anvin70653092007-10-19 14:42:29 -07002417
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002418 if (ins->oprs[j].scale == 0)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002419 i = 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002420
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002421 if (!i && !b) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002422 int ds = ins->oprs[j].disp_size;
2423 if ((addrbits != 64 && ds > 8) ||
2424 (addrbits == 64 && ds == 16))
2425 valid &= ds;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002426 } else {
2427 if (!(REG16 & ~b))
2428 valid &= 16;
2429 if (!(REG32 & ~b))
2430 valid &= 32;
2431 if (!(REG64 & ~b))
2432 valid &= 64;
H. Peter Anvin70653092007-10-19 14:42:29 -07002433
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002434 if (!(REG16 & ~i))
2435 valid &= 16;
2436 if (!(REG32 & ~i))
2437 valid &= 32;
2438 if (!(REG64 & ~i))
2439 valid &= 64;
2440 }
2441 }
2442 }
2443
2444 if (valid & addrbits) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002445 ins->addr_size = addrbits;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002446 } else if (valid & ((addrbits == 32) ? 16 : 32)) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002447 /* Add an address size prefix */
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002448 enum prefixes pref = (addrbits == 32) ? P_A16 : P_A32;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002449 ins->prefixes[PPS_ASIZE] = pref;
2450 ins->addr_size = (addrbits == 32) ? 16 : 32;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002451 } else {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002452 /* Impossible... */
2453 errfunc(ERR_NONFATAL, "impossible combination of address sizes");
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002454 ins->addr_size = addrbits; /* Error recovery */
2455 }
2456
2457 defdisp = ins->addr_size == 16 ? 16 : 32;
2458
2459 for (j = 0; j < ins->operands; j++) {
2460 if (!(MEM_OFFS & ~ins->oprs[j].type) &&
2461 (ins->oprs[j].disp_size ? ins->oprs[j].disp_size : defdisp)
2462 != ins->addr_size) {
2463 /* mem_offs sizes must match the address size; if not,
2464 strip the MEM_OFFS bit and match only EA instructions */
2465 ins->oprs[j].type &= ~(MEM_OFFS & ~MEMORY);
2466 }
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002467 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002468}