blob: d10e5b06ca135d7c28a6c59299c0e10b26e22c1a [file] [log] [blame]
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001/* assemble.c code generation for the Netwide Assembler
2 *
3 * The Netwide Assembler is copyright (C) 1996 Simon Tatham and
4 * Julian Hall. All rights reserved. The software is
Beroset095e6a22007-12-29 09:44:23 -05005 * redistributable under the license given in the file "LICENSE"
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00006 * distributed in the NASM archive.
7 *
8 * the actual codes (C syntax, i.e. octal):
9 * \0 - terminates the code. (Unless it's a literal of course.)
10 * \1, \2, \3 - that many literal bytes follow in the code stream
11 * \4, \6 - the POP/PUSH (respectively) codes for CS, DS, ES, SS
12 * (POP is never used for CS) depending on operand 0
13 * \5, \7 - the second byte of POP/PUSH codes for FS, GS, depending
14 * on operand 0
H. Peter Anvin7eb4a382007-09-17 15:49:30 -070015 * \10..\13 - a literal byte follows in the code stream, to be added
16 * to the register value of operand 0..3
17 * \14..\17 - a signed byte immediate operand, from operand 0..3
18 * \20..\23 - a byte immediate operand, from operand 0..3
19 * \24..\27 - an unsigned byte immediate operand, from operand 0..3
20 * \30..\33 - a word immediate operand, from operand 0..3
21 * \34..\37 - select between \3[0-3] and \4[0-3] depending on 16/32 bit
H. Peter Anvin3ba46772002-05-27 23:19:35 +000022 * assembly mode or the operand-size override on the operand
H. Peter Anvin7eb4a382007-09-17 15:49:30 -070023 * \40..\43 - a long immediate operand, from operand 0..3
24 * \44..\47 - select between \3[0-3], \4[0-3] and \5[4-7]
H. Peter Anvinde4b89b2007-10-01 15:41:25 -070025 * depending on the address size of the instruction.
H. Peter Anvin7eb4a382007-09-17 15:49:30 -070026 * \50..\53 - a byte relative operand, from operand 0..3
27 * \54..\57 - a qword immediate operand, from operand 0..3
28 * \60..\63 - a word relative operand, from operand 0..3
29 * \64..\67 - select between \6[0-3] and \7[0-3] depending on 16/32 bit
H. Peter Anvin17799b42002-05-21 03:31:21 +000030 * assembly mode or the operand-size override on the operand
H. Peter Anvin7eb4a382007-09-17 15:49:30 -070031 * \70..\73 - a long relative operand, from operand 0..3
32 * \74..\77 - a word constant, from the _segment_ part of operand 0..3
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000033 * \1ab - a ModRM, calculated on EA in operand a, with the spare
34 * field the register value of operand b.
H. Peter Anvin7eb4a382007-09-17 15:49:30 -070035 * \140..\143 - an immediate word or signed byte for operand 0..3
H. Peter Anvina30cc072007-11-18 21:55:26 -080036 * \144..\147 - or 2 (s-field) into opcode byte if operand 0..3
37 * is a signed byte rather than a word. Opcode byte follows.
H. Peter Anvin7eb4a382007-09-17 15:49:30 -070038 * \150..\153 - an immediate dword or signed byte for operand 0..3
H. Peter Anvina30cc072007-11-18 21:55:26 -080039 * \154..\157 - or 2 (s-field) into opcode byte if operand 0..3
H. Peter Anvin32cd4c22008-04-04 13:34:53 -070040 * is a signed byte rather than a dword. Opcode byte follows.
H. Peter Anvin401c07e2007-09-17 16:55:04 -070041 * \160..\163 - this instruction uses DREX rather than REX, with the
42 * OC0 field set to 0, and the dest field taken from
43 * operand 0..3.
44 * \164..\167 - this instruction uses DREX rather than REX, with the
45 * OC0 field set to 1, and the dest field taken from
46 * operand 0..3.
H. Peter Anvin401c07e2007-09-17 16:55:04 -070047 * \171 - placement of DREX suffix in the absence of an EA
H. Peter Anvind85d2502008-05-04 17:53:31 -070048 * \172\ab - the register number from operand a in bits 7..4, with
49 * the 4-bit immediate from operand b in bits 0..3.
H. Peter Anvind58656f2008-05-06 20:11:14 -070050 * \173\xab - the register number from operand a in bits 7..4, with
51 * the value b in bits 0..3.
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000052 * \2ab - a ModRM, calculated on EA in operand a, with the spare
53 * field equal to digit b.
H. Peter Anvin32cd4c22008-04-04 13:34:53 -070054 * \250..\253 - same as \150..\153, except warn if the 64-bit operand
55 * is not equal to the truncated and sign-extended 32-bit
56 * operand; used for 32-bit immediates in 64-bit mode.
H. Peter Anvind85d2502008-05-04 17:53:31 -070057 * \260..\263 - this instruction uses VEX rather than REX, with the
58 * V field taken from operand 0..3.
59 * \270 - this instruction uses VEX rather than REX, with the
60 * V field set to 1111b.
61 *
62 * VEX prefixes are followed by the sequence:
H. Peter Anvinaaa088f2008-05-12 11:13:41 -070063 * \mm\wlp where mm is the M field; and wlp is:
64 * 00 0ww lpp
H. Peter Anvind85d2502008-05-04 17:53:31 -070065 * ww = 0 for W = 0
66 * ww = 1 for W = 1
67 * ww = 2 for W used as REX.W
68 *
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000069 * \310 - indicates fixed 16-bit address size, i.e. optional 0x67.
70 * \311 - indicates fixed 32-bit address size, i.e. optional 0x67.
Keith Kanios48af1772007-08-17 07:37:52 +000071 * \312 - (disassembler only) marker on LOOP, LOOPxx instructions.
H. Peter Anvince2b3972007-05-30 22:21:11 +000072 * \313 - indicates fixed 64-bit address size, 0x67 invalid.
H. Peter Anvin23440102007-11-12 21:02:33 -080073 * \314 - (disassembler only) invalid with REX.B
74 * \315 - (disassembler only) invalid with REX.X
75 * \316 - (disassembler only) invalid with REX.R
76 * \317 - (disassembler only) invalid with REX.W
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000077 * \320 - indicates fixed 16-bit operand size, i.e. optional 0x66.
78 * \321 - indicates fixed 32-bit operand size, i.e. optional 0x66.
79 * \322 - indicates that this instruction is only valid when the
80 * operand size is the default (instruction to disassembler,
81 * generates no code in the assembler)
H. Peter Anvince2b3972007-05-30 22:21:11 +000082 * \323 - indicates fixed 64-bit operand size, REX on extensions only.
Keith Kaniosb7a89542007-04-12 02:40:54 +000083 * \324 - indicates 64-bit operand size requiring REX prefix.
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000084 * \330 - a literal byte follows in the code stream, to be added
85 * to the condition code value of the instruction.
Keith Kanios48af1772007-08-17 07:37:52 +000086 * \331 - instruction not valid with REP prefix. Hint for
H. Peter Anvinef7468f2002-04-30 20:57:59 +000087 * disassembler only; for SSE instructions.
H. Peter Anvincb9b6902007-09-12 21:58:51 -070088 * \332 - REP prefix (0xF2 byte) used as opcode extension.
89 * \333 - REP prefix (0xF3 byte) used as opcode extension.
Keith Kanios48af1772007-08-17 07:37:52 +000090 * \334 - LOCK prefix used instead of REX.R
H. Peter Anvincb9b6902007-09-12 21:58:51 -070091 * \335 - disassemble a rep (0xF3 byte) prefix as repe not rep.
Keith Kaniosb7a89542007-04-12 02:40:54 +000092 * \340 - reserve <operand 0> bytes of uninitialized storage.
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000093 * Operand 0 had better be a segmentless constant.
H. Peter Anvinfff5a472008-05-20 09:46:24 -070094 * \360 - no SSE prefix (== \364\331)
95 * \361 - 66 SSE prefix (== \366\331)
96 * \362 - F2 SSE prefix (== \364\332)
97 * \363 - F3 SSE prefix (== \364\333)
H. Peter Anvin62cb6062007-09-11 22:44:03 +000098 * \364 - operand-size prefix (0x66) not permitted
99 * \365 - address-size prefix (0x67) not permitted
100 * \366 - operand-size prefix (0x66) used as opcode extension
101 * \367 - address-size prefix (0x67) used as opcode extension
H. Peter Anvin788e6c12002-04-30 21:02:01 +0000102 * \370,\371,\372 - match only if operand 0 meets byte jump criteria.
103 * 370 is used for Jcc, 371 is used for JMP.
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000104 * \373 - assemble 0x03 if bits==16, 0x05 if bits==32;
105 * used for conditional jump over longer jump
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000106 */
107
H. Peter Anvinfe501952007-10-02 21:53:51 -0700108#include "compiler.h"
109
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000110#include <stdio.h>
111#include <string.h>
Keith Kaniosb7a89542007-04-12 02:40:54 +0000112#include <inttypes.h>
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000113
114#include "nasm.h"
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000115#include "nasmlib.h"
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000116#include "assemble.h"
117#include "insns.h"
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000118#include "preproc.h"
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000119#include "regflags.c"
Keith Kaniosb7a89542007-04-12 02:40:54 +0000120#include "regvals.c"
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000121
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000122typedef struct {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000123 int sib_present; /* is a SIB byte necessary? */
124 int bytes; /* # of bytes of offset needed */
125 int size; /* lazy - this is sib+bytes+1 */
126 uint8_t modrm, sib, rex, rip; /* the bytes themselves */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000127} ea;
128
Keith Kaniosb7a89542007-04-12 02:40:54 +0000129static uint32_t cpu; /* cpu level received from nasm.c */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000130static efunc errfunc;
131static struct ofmt *outfmt;
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000132static ListGen *list;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000133
H. Peter Anvin3720f7b2008-05-12 11:00:50 -0700134static int64_t calcsize(int32_t, int64_t, int, insn *, const uint8_t *);
135static void gencode(int32_t, int64_t, int, insn *, const uint8_t *, int64_t);
H. Peter Anvin3360d792007-09-11 04:16:57 +0000136static int matches(const struct itemplate *, insn *, int bits);
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000137static int32_t regflag(const operand *);
138static int32_t regval(const operand *);
139static int rexflags(int, int32_t, int);
140static int op_rexflags(const operand *, int);
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700141static ea *process_ea(operand *, ea *, int, int, int, int32_t, int);
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700142static void add_asp(insn *, int);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000143
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700144static int has_prefix(insn * ins, enum prefix_pos pos, enum prefixes prefix)
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000145{
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700146 return ins->prefixes[pos] == prefix;
147}
148
149static void assert_no_prefix(insn * ins, enum prefix_pos pos)
150{
151 if (ins->prefixes[pos])
152 errfunc(ERR_NONFATAL, "invalid %s prefix",
153 prefix_name(ins->prefixes[pos]));
154}
155
156static const char *size_name(int size)
157{
158 switch (size) {
159 case 1:
160 return "byte";
161 case 2:
162 return "word";
163 case 4:
164 return "dword";
165 case 8:
166 return "qword";
167 case 10:
168 return "tword";
169 case 16:
170 return "oword";
171 default:
172 return "???";
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000173 }
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700174}
175
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700176static void warn_overflow(int size, int64_t data)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700177{
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700178 if (size < 8) {
Charles Craynedd462c82007-11-04 15:28:30 -0800179 int64_t lim = ((int64_t)1 << (size*8))-1;
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000180
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700181 if (data < ~lim || data > lim)
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700182 errfunc(ERR_WARNING | ERR_WARN_NOV,
183 "%s data exceeds bounds", size_name(size));
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700184 }
185}
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000186/*
187 * This routine wrappers the real output format's output routine,
188 * in order to pass a copy of the data off to the listing file
189 * generator at the same time.
190 */
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800191static void out(int64_t offset, int32_t segto, const void *data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800192 enum out_type type, uint64_t size,
193 int32_t segment, int32_t wrt)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000194{
Keith Kaniosb7a89542007-04-12 02:40:54 +0000195 static int32_t lineno = 0; /* static!!! */
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000196 static char *lnfname = NULL;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800197 uint8_t p[8];
H. Peter Anvineba20a72002-04-30 20:53:55 +0000198
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800199 if (type == OUT_ADDRESS && segment == NO_SEG && wrt == NO_SEG) {
200 /*
201 * This is a non-relocated address, and we're going to
202 * convert it into RAWDATA format.
203 */
204 uint8_t *q = p;
H. Peter Anvind1fb15c2007-11-13 09:37:59 -0800205
206 if (size > 8) {
207 errfunc(ERR_PANIC, "OUT_ADDRESS with size > 8");
208 return;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800209 }
H. Peter Anvind85d2502008-05-04 17:53:31 -0700210
H. Peter Anvind1fb15c2007-11-13 09:37:59 -0800211 WRITEADDR(q, *(int64_t *)data, size);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800212 data = p;
213 type = OUT_RAWDATA;
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000214 }
215
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800216 list->output(offset, data, type, size);
217
Frank Kotlerabebb082003-09-06 04:45:37 +0000218 /*
219 * this call to src_get determines when we call the
220 * debug-format-specific "linenum" function
221 * it updates lineno and lnfname to the current values
222 * returning 0 if "same as last time", -2 if lnfname
223 * changed, and the amount by which lineno changed,
224 * if it did. thus, these variables must be static
225 */
226
H. Peter Anvine2c80182005-01-15 22:15:51 +0000227 if (src_get(&lineno, &lnfname)) {
228 outfmt->current_dfmt->linenum(lnfname, lineno, segto);
H. Peter Anvince616072002-04-30 21:02:23 +0000229 }
H. Peter Anvineba20a72002-04-30 20:53:55 +0000230
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800231 outfmt->output(segto, data, type, size, segment, wrt);
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000232}
233
Charles Crayne5fbbc8c2007-11-07 19:03:46 -0800234static int jmp_match(int32_t segment, int64_t offset, int bits,
H. Peter Anvin3720f7b2008-05-12 11:00:50 -0700235 insn * ins, const uint8_t *code)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000236{
Charles Crayne5fbbc8c2007-11-07 19:03:46 -0800237 int64_t isize;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000238 uint8_t c = code[0];
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000239
H. Peter Anvine2c80182005-01-15 22:15:51 +0000240 if (c != 0370 && c != 0371)
241 return 0;
H. Peter Anvin788e6c12002-04-30 21:02:01 +0000242 if (ins->oprs[0].opflags & OPFLAG_FORWARD) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000243 if ((optimizing < 0 || (ins->oprs[0].type & STRICT))
244 && c == 0370)
245 return 1;
246 else
247 return (pass0 == 0); /* match a forward reference */
H. Peter Anvin788e6c12002-04-30 21:02:01 +0000248 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000249 isize = calcsize(segment, offset, bits, ins, code);
250 if (ins->oprs[0].segment != segment)
251 return 0;
252 isize = ins->oprs[0].offset - offset - isize; /* isize is now the delta */
253 if (isize >= -128L && isize <= 127L)
254 return 1; /* it is byte size */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000255
256 return 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000257}
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000258
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800259int64_t assemble(int32_t segment, int64_t offset, int bits, uint32_t cp,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000260 insn * instruction, struct ofmt *output, efunc error,
261 ListGen * listgen)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000262{
H. Peter Anvin3360d792007-09-11 04:16:57 +0000263 const struct itemplate *temp;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000264 int j;
265 int size_prob;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800266 int64_t insn_end;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000267 int32_t itimes;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800268 int64_t start = offset;
269 int64_t wsize = 0; /* size for DB etc. */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000270
H. Peter Anvine2c80182005-01-15 22:15:51 +0000271 errfunc = error; /* to pass to other functions */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000272 cpu = cp;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000273 outfmt = output; /* likewise */
274 list = listgen; /* and again */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000275
H. Peter Anvine2c80182005-01-15 22:15:51 +0000276 switch (instruction->opcode) {
277 case -1:
278 return 0;
279 case I_DB:
280 wsize = 1;
281 break;
282 case I_DW:
283 wsize = 2;
284 break;
285 case I_DD:
286 wsize = 4;
287 break;
288 case I_DQ:
289 wsize = 8;
290 break;
291 case I_DT:
292 wsize = 10;
293 break;
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700294 case I_DO:
295 wsize = 16;
296 break;
H. Peter Anvin16b0a332007-09-12 20:27:41 -0700297 default:
298 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000299 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000300
H. Peter Anvineba20a72002-04-30 20:53:55 +0000301 if (wsize) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000302 extop *e;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000303 int32_t t = instruction->times;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000304 if (t < 0)
305 errfunc(ERR_PANIC,
306 "instruction->times < 0 (%ld) in assemble()", t);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000307
H. Peter Anvine2c80182005-01-15 22:15:51 +0000308 while (t--) { /* repeat TIMES times */
309 for (e = instruction->eops; e; e = e->next) {
310 if (e->type == EOT_DB_NUMBER) {
311 if (wsize == 1) {
312 if (e->segment != NO_SEG)
313 errfunc(ERR_NONFATAL,
314 "one-byte relocation attempted");
315 else {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000316 uint8_t out_byte = e->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000317 out(offset, segment, &out_byte,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800318 OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000319 }
Keith Kanios61ff53c2007-04-14 18:54:52 +0000320 } else if (wsize > 8) {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700321 errfunc(ERR_NONFATAL, "integer supplied to a DT or DO"
Keith Kanios61ff53c2007-04-14 18:54:52 +0000322 " instruction");
H. Peter Anvine2c80182005-01-15 22:15:51 +0000323 } else
324 out(offset, segment, &e->offset,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800325 OUT_ADDRESS, wsize, e->segment, e->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000326 offset += wsize;
327 } else if (e->type == EOT_DB_STRING) {
328 int align;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000329
H. Peter Anvine2c80182005-01-15 22:15:51 +0000330 out(offset, segment, e->stringval,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800331 OUT_RAWDATA, e->stringlen, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000332 align = e->stringlen % wsize;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000333
H. Peter Anvine2c80182005-01-15 22:15:51 +0000334 if (align) {
335 align = wsize - align;
H. Peter Anvind387b8c2008-01-27 16:39:26 -0800336 out(offset, segment,
337 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0",
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800338 OUT_RAWDATA, align, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000339 }
340 offset += e->stringlen + align;
341 }
342 }
343 if (t > 0 && t == instruction->times - 1) {
344 /*
345 * Dummy call to list->output to give the offset to the
346 * listing module.
347 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800348 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000349 list->uplevel(LIST_TIMES);
350 }
351 }
352 if (instruction->times > 1)
353 list->downlevel(LIST_TIMES);
354 return offset - start;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000355 }
356
H. Peter Anvine2c80182005-01-15 22:15:51 +0000357 if (instruction->opcode == I_INCBIN) {
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000358 static char fname[FILENAME_MAX];
H. Peter Anvine2c80182005-01-15 22:15:51 +0000359 FILE *fp;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000360 int32_t len;
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000361 char *prefix = "", *combine;
362 char **pPrevPath = NULL;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000363
H. Peter Anvine2c80182005-01-15 22:15:51 +0000364 len = FILENAME_MAX - 1;
365 if (len > instruction->eops->stringlen)
366 len = instruction->eops->stringlen;
367 strncpy(fname, instruction->eops->stringval, len);
368 fname[len] = '\0';
H. Peter Anvineba20a72002-04-30 20:53:55 +0000369
Keith Kaniosb7a89542007-04-12 02:40:54 +0000370 while (1) { /* added by alexfru: 'incbin' uses include paths */
H. Peter Anvine2c80182005-01-15 22:15:51 +0000371 combine = nasm_malloc(strlen(prefix) + len + 1);
372 strcpy(combine, prefix);
373 strcat(combine, fname);
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000374
H. Peter Anvine2c80182005-01-15 22:15:51 +0000375 if ((fp = fopen(combine, "rb")) != NULL) {
376 nasm_free(combine);
377 break;
378 }
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000379
H. Peter Anvine2c80182005-01-15 22:15:51 +0000380 nasm_free(combine);
381 pPrevPath = pp_get_include_path_ptr(pPrevPath);
382 if (pPrevPath == NULL)
383 break;
384 prefix = *pPrevPath;
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000385 }
386
387 if (fp == NULL)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000388 error(ERR_NONFATAL, "`incbin': unable to open file `%s'",
389 fname);
390 else if (fseek(fp, 0L, SEEK_END) < 0)
391 error(ERR_NONFATAL, "`incbin': unable to seek on file `%s'",
392 fname);
393 else {
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000394 static char buf[2048];
Keith Kaniosb7a89542007-04-12 02:40:54 +0000395 int32_t t = instruction->times;
396 int32_t base = 0;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000397
H. Peter Anvine2c80182005-01-15 22:15:51 +0000398 len = ftell(fp);
399 if (instruction->eops->next) {
400 base = instruction->eops->next->offset;
401 len -= base;
402 if (instruction->eops->next->next &&
403 len > instruction->eops->next->next->offset)
404 len = instruction->eops->next->next->offset;
405 }
406 /*
407 * Dummy call to list->output to give the offset to the
408 * listing module.
409 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800410 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000411 list->uplevel(LIST_INCBIN);
412 while (t--) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000413 int32_t l;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000414
H. Peter Anvine2c80182005-01-15 22:15:51 +0000415 fseek(fp, base, SEEK_SET);
416 l = len;
417 while (l > 0) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000418 int32_t m =
Charles Crayne192d5b52007-10-18 19:02:42 -0700419 fread(buf, 1, (l > (int32_t) sizeof(buf) ? (int32_t) sizeof(buf) : l),
H. Peter Anvine2c80182005-01-15 22:15:51 +0000420 fp);
421 if (!m) {
422 /*
423 * This shouldn't happen unless the file
424 * actually changes while we are reading
425 * it.
426 */
427 error(ERR_NONFATAL,
428 "`incbin': unexpected EOF while"
429 " reading file `%s'", fname);
430 t = 0; /* Try to exit cleanly */
431 break;
432 }
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800433 out(offset, segment, buf, OUT_RAWDATA, m,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000434 NO_SEG, NO_SEG);
435 l -= m;
436 }
437 }
438 list->downlevel(LIST_INCBIN);
439 if (instruction->times > 1) {
440 /*
441 * Dummy call to list->output to give the offset to the
442 * listing module.
443 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800444 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000445 list->uplevel(LIST_TIMES);
446 list->downlevel(LIST_TIMES);
447 }
448 fclose(fp);
449 return instruction->times * len;
450 }
451 return 0; /* if we're here, there's an error */
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000452 }
453
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700454 /* Check to see if we need an address-size prefix */
455 add_asp(instruction, bits);
456
H. Peter Anvin6867acc2007-10-10 14:58:45 -0700457 size_prob = false;
H. Peter Anvin70653092007-10-19 14:42:29 -0700458
459 for (temp = nasm_instructions[instruction->opcode]; temp->opcode != -1; temp++){
Keith Kaniosb7a89542007-04-12 02:40:54 +0000460 int m = matches(temp, instruction, bits);
H. Peter Anvin70653092007-10-19 14:42:29 -0700461
H. Peter Anvine2c80182005-01-15 22:15:51 +0000462 if (m == 99)
463 m += jmp_match(segment, offset, bits, instruction, temp->code);
H. Peter Anvineba20a72002-04-30 20:53:55 +0000464
H. Peter Anvine2c80182005-01-15 22:15:51 +0000465 if (m == 100) { /* matches! */
H. Peter Anvin3720f7b2008-05-12 11:00:50 -0700466 const uint8_t *codes = temp->code;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800467 int64_t insn_size = calcsize(segment, offset, bits,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000468 instruction, codes);
469 itimes = instruction->times;
470 if (insn_size < 0) /* shouldn't be, on pass two */
471 error(ERR_PANIC, "errors made it through from pass one");
472 else
473 while (itimes--) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700474 for (j = 0; j < MAXPREFIX; j++) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000475 uint8_t c = 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000476 switch (instruction->prefixes[j]) {
477 case P_LOCK:
478 c = 0xF0;
479 break;
480 case P_REPNE:
481 case P_REPNZ:
482 c = 0xF2;
483 break;
484 case P_REPE:
485 case P_REPZ:
486 case P_REP:
487 c = 0xF3;
488 break;
489 case R_CS:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000490 if (bits == 64) {
491 error(ERR_WARNING,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800492 "cs segment base generated, but will be ignored in 64-bit mode");
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000493 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000494 c = 0x2E;
495 break;
496 case R_DS:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000497 if (bits == 64) {
498 error(ERR_WARNING,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800499 "ds segment base generated, but will be ignored in 64-bit mode");
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000500 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000501 c = 0x3E;
502 break;
503 case R_ES:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000504 if (bits == 64) {
505 error(ERR_WARNING,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800506 "es segment base generated, but will be ignored in 64-bit mode");
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000507 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000508 c = 0x26;
509 break;
510 case R_FS:
511 c = 0x64;
512 break;
513 case R_GS:
514 c = 0x65;
515 break;
516 case R_SS:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000517 if (bits == 64) {
518 error(ERR_WARNING,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800519 "ss segment base generated, but will be ignored in 64-bit mode");
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000520 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000521 c = 0x36;
522 break;
523 case R_SEGR6:
524 case R_SEGR7:
525 error(ERR_NONFATAL,
526 "segr6 and segr7 cannot be used as prefixes");
527 break;
528 case P_A16:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000529 if (bits == 64) {
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000530 error(ERR_NONFATAL,
531 "16-bit addressing is not supported "
532 "in 64-bit mode");
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700533 } else if (bits != 16)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000534 c = 0x67;
535 break;
536 case P_A32:
537 if (bits != 32)
538 c = 0x67;
539 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700540 case P_A64:
541 if (bits != 64) {
542 error(ERR_NONFATAL,
543 "64-bit addressing is only supported "
544 "in 64-bit mode");
545 }
546 break;
547 case P_ASP:
548 c = 0x67;
549 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000550 case P_O16:
551 if (bits != 16)
552 c = 0x66;
553 break;
554 case P_O32:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000555 if (bits == 16)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000556 c = 0x66;
557 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700558 case P_O64:
559 /* REX.W */
560 break;
561 case P_OSP:
562 c = 0x66;
563 break;
564 case P_none:
565 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000566 default:
567 error(ERR_PANIC, "invalid instruction prefix");
568 }
569 if (c != 0) {
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800570 out(offset, segment, &c, OUT_RAWDATA, 1,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000571 NO_SEG, NO_SEG);
572 offset++;
573 }
H. Peter Anvin70653092007-10-19 14:42:29 -0700574 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000575 insn_end = offset + insn_size;
576 gencode(segment, offset, bits, instruction, codes,
577 insn_end);
578 offset += insn_size;
579 if (itimes > 0 && itimes == instruction->times - 1) {
580 /*
581 * Dummy call to list->output to give the offset to the
582 * listing module.
583 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800584 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000585 list->uplevel(LIST_TIMES);
586 }
587 }
588 if (instruction->times > 1)
589 list->downlevel(LIST_TIMES);
590 return offset - start;
591 } else if (m > 0 && m > size_prob) {
592 size_prob = m;
593 }
Keith Kaniosb7a89542007-04-12 02:40:54 +0000594// temp++;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000595 }
H. Peter Anvineba20a72002-04-30 20:53:55 +0000596
H. Peter Anvine2c80182005-01-15 22:15:51 +0000597 if (temp->opcode == -1) { /* didn't match any instruction */
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000598 switch (size_prob) {
599 case 1:
600 error(ERR_NONFATAL, "operation size not specified");
601 break;
602 case 2:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000603 error(ERR_NONFATAL, "mismatch in operand sizes");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000604 break;
605 case 3:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000606 error(ERR_NONFATAL, "no instruction for this cpu level");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000607 break;
608 case 4:
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000609 error(ERR_NONFATAL, "instruction not supported in 64-bit mode");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000610 break;
611 default:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000612 error(ERR_NONFATAL,
613 "invalid combination of opcode and operands");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000614 break;
615 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000616 }
617 return 0;
618}
619
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800620int64_t insn_size(int32_t segment, int64_t offset, int bits, uint32_t cp,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000621 insn * instruction, efunc error)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000622{
H. Peter Anvin3360d792007-09-11 04:16:57 +0000623 const struct itemplate *temp;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000624
H. Peter Anvine2c80182005-01-15 22:15:51 +0000625 errfunc = error; /* to pass to other functions */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000626 cpu = cp;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000627
628 if (instruction->opcode == -1)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000629 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000630
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700631 if (instruction->opcode == I_DB || instruction->opcode == I_DW ||
632 instruction->opcode == I_DD || instruction->opcode == I_DQ ||
633 instruction->opcode == I_DT || instruction->opcode == I_DO) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000634 extop *e;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000635 int32_t isize, osize, wsize = 0; /* placate gcc */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000636
H. Peter Anvine2c80182005-01-15 22:15:51 +0000637 isize = 0;
638 switch (instruction->opcode) {
639 case I_DB:
640 wsize = 1;
641 break;
642 case I_DW:
643 wsize = 2;
644 break;
645 case I_DD:
646 wsize = 4;
647 break;
648 case I_DQ:
649 wsize = 8;
650 break;
651 case I_DT:
652 wsize = 10;
653 break;
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700654 case I_DO:
655 wsize = 16;
656 break;
H. Peter Anvin16b0a332007-09-12 20:27:41 -0700657 default:
658 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000659 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000660
H. Peter Anvine2c80182005-01-15 22:15:51 +0000661 for (e = instruction->eops; e; e = e->next) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000662 int32_t align;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000663
H. Peter Anvine2c80182005-01-15 22:15:51 +0000664 osize = 0;
665 if (e->type == EOT_DB_NUMBER)
666 osize = 1;
667 else if (e->type == EOT_DB_STRING)
668 osize = e->stringlen;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000669
H. Peter Anvine2c80182005-01-15 22:15:51 +0000670 align = (-osize) % wsize;
671 if (align < 0)
672 align += wsize;
673 isize += osize + align;
674 }
675 return isize * instruction->times;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000676 }
677
H. Peter Anvine2c80182005-01-15 22:15:51 +0000678 if (instruction->opcode == I_INCBIN) {
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000679 char fname[FILENAME_MAX];
H. Peter Anvine2c80182005-01-15 22:15:51 +0000680 FILE *fp;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000681 int32_t len;
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000682 char *prefix = "", *combine;
683 char **pPrevPath = NULL;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000684
H. Peter Anvine2c80182005-01-15 22:15:51 +0000685 len = FILENAME_MAX - 1;
686 if (len > instruction->eops->stringlen)
687 len = instruction->eops->stringlen;
688 strncpy(fname, instruction->eops->stringval, len);
689 fname[len] = '\0';
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000690
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700691 /* added by alexfru: 'incbin' uses include paths */
692 while (1) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000693 combine = nasm_malloc(strlen(prefix) + len + 1);
694 strcpy(combine, prefix);
695 strcat(combine, fname);
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000696
H. Peter Anvine2c80182005-01-15 22:15:51 +0000697 if ((fp = fopen(combine, "rb")) != NULL) {
698 nasm_free(combine);
699 break;
700 }
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000701
H. Peter Anvine2c80182005-01-15 22:15:51 +0000702 nasm_free(combine);
703 pPrevPath = pp_get_include_path_ptr(pPrevPath);
704 if (pPrevPath == NULL)
705 break;
706 prefix = *pPrevPath;
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000707 }
708
709 if (fp == NULL)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000710 error(ERR_NONFATAL, "`incbin': unable to open file `%s'",
711 fname);
712 else if (fseek(fp, 0L, SEEK_END) < 0)
713 error(ERR_NONFATAL, "`incbin': unable to seek on file `%s'",
714 fname);
715 else {
716 len = ftell(fp);
717 fclose(fp);
718 if (instruction->eops->next) {
719 len -= instruction->eops->next->offset;
720 if (instruction->eops->next->next &&
721 len > instruction->eops->next->next->offset) {
722 len = instruction->eops->next->next->offset;
723 }
724 }
725 return instruction->times * len;
726 }
727 return 0; /* if we're here, there's an error */
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000728 }
729
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700730 /* Check to see if we need an address-size prefix */
731 add_asp(instruction, bits);
732
Keith Kaniosb7a89542007-04-12 02:40:54 +0000733 for (temp = nasm_instructions[instruction->opcode]; temp->opcode != -1; temp++) {
734 int m = matches(temp, instruction, bits);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000735 if (m == 99)
736 m += jmp_match(segment, offset, bits, instruction, temp->code);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000737
H. Peter Anvine2c80182005-01-15 22:15:51 +0000738 if (m == 100) {
739 /* we've matched an instruction. */
Charles Crayne5fbbc8c2007-11-07 19:03:46 -0800740 int64_t isize;
H. Peter Anvin3720f7b2008-05-12 11:00:50 -0700741 const uint8_t *codes = temp->code;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000742 int j;
743
744 isize = calcsize(segment, offset, bits, instruction, codes);
745 if (isize < 0)
746 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700747 for (j = 0; j < MAXPREFIX; j++) {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700748 switch (instruction->prefixes[j]) {
749 case P_A16:
750 if (bits != 16)
751 isize++;
752 break;
753 case P_A32:
754 if (bits != 32)
755 isize++;
756 break;
757 case P_O16:
758 if (bits != 16)
759 isize++;
760 break;
761 case P_O32:
762 if (bits == 16)
763 isize++;
764 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700765 case P_A64:
766 case P_O64:
767 case P_none:
768 break;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700769 default:
770 isize++;
771 break;
772 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000773 }
774 return isize * instruction->times;
775 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000776 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000777 return -1; /* didn't match any instruction */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000778}
779
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700780static bool possible_sbyte(insn * ins, int op)
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000781{
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700782 return !(ins->forw_ref && ins->oprs[op].opflags) &&
H. Peter Anvine2c80182005-01-15 22:15:51 +0000783 optimizing >= 0 &&
784 !(ins->oprs[op].type & STRICT) &&
785 ins->oprs[op].wrt == NO_SEG && ins->oprs[op].segment == NO_SEG;
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000786}
787
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700788/* check that opn[op] is a signed byte of size 16 or 32 */
789static bool is_sbyte16(insn * ins, int op)
790{
791 int16_t v;
792
793 if (!possible_sbyte(ins, op))
794 return false;
795
796 v = ins->oprs[op].offset;
797 return v >= -128 && v <= 127;
798}
799
800static bool is_sbyte32(insn * ins, int op)
801{
802 int32_t v;
803
804 if (!possible_sbyte(ins, op))
805 return false;
806
807 v = ins->oprs[op].offset;
808 return v >= -128 && v <= 127;
809}
810
811/* check that opn[op] is a signed byte of size 32; warn if this is not
812 the original value when extended to 64 bits */
813static bool is_sbyte64(insn * ins, int op)
814{
815 int64_t v64;
816 int32_t v32;
817
818 /* dead in the water on forward reference or External */
819 if (!possible_sbyte(ins, op))
820 return false;
821
822 v64 = ins->oprs[op].offset;
823 v32 = (int32_t)v64;
824
825 warn_overflow(32, v64);
826
827 return v32 >= -128 && v32 <= 127;
828}
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800829static int64_t calcsize(int32_t segment, int64_t offset, int bits,
H. Peter Anvin3720f7b2008-05-12 11:00:50 -0700830 insn * ins, const uint8_t *codes)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000831{
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800832 int64_t length = 0;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000833 uint8_t c;
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000834 int rex_mask = ~0;
H. Peter Anvin839eca22007-10-29 23:12:47 -0700835 struct operand *opx;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000836
H. Peter Anvine3917fc2007-11-01 14:53:32 -0700837 ins->rex = 0; /* Ensure REX is reset */
838
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700839 if (ins->prefixes[PPS_OSIZE] == P_O64)
840 ins->rex |= REX_W;
841
H. Peter Anvine2c80182005-01-15 22:15:51 +0000842 (void)segment; /* Don't warn that this parameter is unused */
843 (void)offset; /* Don't warn that this parameter is unused */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000844
H. Peter Anvin839eca22007-10-29 23:12:47 -0700845 while (*codes) {
846 c = *codes++;
847 opx = &ins->oprs[c & 3];
848 switch (c) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000849 case 01:
850 case 02:
851 case 03:
852 codes += c, length += c;
853 break;
854 case 04:
855 case 05:
856 case 06:
857 case 07:
858 length++;
859 break;
860 case 010:
861 case 011:
862 case 012:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700863 case 013:
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000864 ins->rex |=
H. Peter Anvin839eca22007-10-29 23:12:47 -0700865 op_rexflags(opx, REX_B|REX_H|REX_P|REX_W);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000866 codes++, length++;
867 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000868 case 014:
869 case 015:
870 case 016:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700871 case 017:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000872 length++;
873 break;
874 case 020:
875 case 021:
876 case 022:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700877 case 023:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000878 length++;
879 break;
880 case 024:
881 case 025:
882 case 026:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700883 case 027:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000884 length++;
885 break;
886 case 030:
887 case 031:
888 case 032:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700889 case 033:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000890 length += 2;
891 break;
892 case 034:
893 case 035:
894 case 036:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700895 case 037:
H. Peter Anvin839eca22007-10-29 23:12:47 -0700896 if (opx->type & (BITS16 | BITS32 | BITS64))
897 length += (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000898 else
899 length += (bits == 16) ? 2 : 4;
900 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000901 case 040:
902 case 041:
903 case 042:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700904 case 043:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000905 length += 4;
906 break;
907 case 044:
908 case 045:
909 case 046:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700910 case 047:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700911 length += ins->addr_size >> 3;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000912 break;
913 case 050:
914 case 051:
915 case 052:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700916 case 053:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000917 length++;
918 break;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000919 case 054:
920 case 055:
921 case 056:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700922 case 057:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000923 length += 8; /* MOV reg64/imm */
924 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000925 case 060:
926 case 061:
927 case 062:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700928 case 063:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000929 length += 2;
930 break;
931 case 064:
932 case 065:
933 case 066:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700934 case 067:
H. Peter Anvin839eca22007-10-29 23:12:47 -0700935 if (opx->type & (BITS16 | BITS32 | BITS64))
936 length += (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000937 else
938 length += (bits == 16) ? 2 : 4;
939 break;
940 case 070:
941 case 071:
942 case 072:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700943 case 073:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000944 length += 4;
945 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700946 case 074:
947 case 075:
948 case 076:
949 case 077:
950 length += 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000951 break;
952 case 0140:
953 case 0141:
954 case 0142:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700955 case 0143:
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700956 length += is_sbyte16(ins, c & 3) ? 1 : 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000957 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000958 case 0144:
959 case 0145:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700960 case 0146:
961 case 0147:
H. Peter Anvina30cc072007-11-18 21:55:26 -0800962 codes++;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000963 length++;
964 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700965 case 0150:
966 case 0151:
967 case 0152:
968 case 0153:
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700969 length += is_sbyte32(ins, c & 3) ? 1 : 4;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700970 break;
971 case 0154:
972 case 0155:
973 case 0156:
974 case 0157:
H. Peter Anvina30cc072007-11-18 21:55:26 -0800975 codes++;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700976 length++;
977 break;
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700978 case 0160:
979 case 0161:
980 case 0162:
981 case 0163:
982 length++;
983 ins->rex |= REX_D;
H. Peter Anvind85d2502008-05-04 17:53:31 -0700984 ins->drexdst = regval(opx);
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700985 break;
986 case 0164:
987 case 0165:
988 case 0166:
989 case 0167:
990 length++;
991 ins->rex |= REX_D|REX_OC;
H. Peter Anvind85d2502008-05-04 17:53:31 -0700992 ins->drexdst = regval(opx);
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700993 break;
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700994 case 0171:
995 break;
H. Peter Anvind85d2502008-05-04 17:53:31 -0700996 case 0172:
H. Peter Anvind58656f2008-05-06 20:11:14 -0700997 case 0173:
H. Peter Anvind85d2502008-05-04 17:53:31 -0700998 codes++;
999 length++;
1000 break;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001001 case 0250:
1002 case 0251:
1003 case 0252:
1004 case 0253:
1005 length += is_sbyte64(ins, c & 3) ? 1 : 4;
1006 break;
H. Peter Anvind85d2502008-05-04 17:53:31 -07001007 case 0260:
1008 case 0261:
1009 case 0262:
1010 case 0263:
1011 length += 2;
1012 ins->rex |= REX_V;
1013 ins->drexdst = regval(opx);
1014 ins->vex_m = *codes++;
1015 ins->vex_wlp = *codes++;
1016 break;
1017 case 0270:
1018 length += 2;
1019 ins->rex |= REX_V;
1020 ins->drexdst = 0;
1021 ins->vex_m = *codes++;
1022 ins->vex_wlp = *codes++;
1023 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001024 case 0300:
1025 case 0301:
H. Peter Anvin70653092007-10-19 14:42:29 -07001026 case 0302:
1027 case 0303:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001028 break;
1029 case 0310:
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07001030 if (bits == 64)
1031 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001032 length += (bits != 16) && !has_prefix(ins, PPS_ASIZE, P_A16);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001033 break;
1034 case 0311:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001035 length += (bits != 32) && !has_prefix(ins, PPS_ASIZE, P_A32);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001036 break;
1037 case 0312:
H. Peter Anvin70653092007-10-19 14:42:29 -07001038 break;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001039 case 0313:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001040 if (bits != 64 || has_prefix(ins, PPS_ASIZE, P_A16) ||
1041 has_prefix(ins, PPS_ASIZE, P_A32))
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07001042 return -1;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001043 break;
H. Peter Anvin23440102007-11-12 21:02:33 -08001044 case 0314:
1045 case 0315:
1046 case 0316:
1047 case 0317:
1048 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001049 case 0320:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001050 length += (bits != 16);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001051 break;
1052 case 0321:
1053 length += (bits == 16);
1054 break;
1055 case 0322:
1056 break;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001057 case 0323:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001058 rex_mask &= ~REX_W;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001059 break;
1060 case 0324:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001061 ins->rex |= REX_W;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001062 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001063 case 0330:
1064 codes++, length++;
1065 break;
1066 case 0331:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001067 break;
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001068 case 0332:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001069 case 0333:
1070 length++;
1071 break;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001072 case 0334:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001073 ins->rex |= REX_L;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001074 break;
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001075 case 0335:
1076 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001077 case 0340:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001078 if (ins->oprs[0].segment != NO_SEG)
1079 errfunc(ERR_NONFATAL, "attempt to reserve non-constant"
1080 " quantity of BSS space");
1081 else
H. Peter Anvin428fd672007-11-15 10:25:52 -08001082 length += ins->oprs[0].offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001083 break;
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001084 case 0360:
1085 break;
1086 case 0361:
1087 case 0362:
1088 case 0363:
1089 length++;
1090 break;
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001091 case 0364:
1092 case 0365:
1093 break;
Keith Kanios48af1772007-08-17 07:37:52 +00001094 case 0366:
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001095 case 0367:
1096 length++;
1097 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001098 case 0370:
1099 case 0371:
1100 case 0372:
1101 break;
1102 case 0373:
1103 length++;
1104 break;
1105 default: /* can't do it by 'case' statements */
1106 if (c >= 0100 && c <= 0277) { /* it's an EA */
1107 ea ea_data;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001108 int rfield;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001109 int32_t rflags;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001110 ea_data.rex = 0; /* Ensure ea.REX is initially 0 */
H. Peter Anvin70653092007-10-19 14:42:29 -07001111
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001112 if (c <= 0177) {
1113 /* pick rfield from operand b */
1114 rflags = regflag(&ins->oprs[c & 7]);
1115 rfield = regvals[ins->oprs[c & 7].basereg];
1116 } else {
1117 rflags = 0;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001118 rfield = c & 7;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001119 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00001120
H. Peter Anvine2c80182005-01-15 22:15:51 +00001121 if (!process_ea
Keith Kaniosb7a89542007-04-12 02:40:54 +00001122 (&ins->oprs[(c >> 3) & 7], &ea_data, bits,
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001123 ins->addr_size, rfield, rflags, ins->forw_ref)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001124 errfunc(ERR_NONFATAL, "invalid effective address");
1125 return -1;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001126 } else {
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001127 ins->rex |= ea_data.rex;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001128 length += ea_data.size;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001129 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001130 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001131 errfunc(ERR_PANIC, "internal instruction table corrupt"
1132 ": instruction code 0x%02X given", c);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001133 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001134 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001135 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001136
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001137 ins->rex &= rex_mask;
H. Peter Anvin70653092007-10-19 14:42:29 -07001138
H. Peter Anvind85d2502008-05-04 17:53:31 -07001139 if (ins->rex & REX_V) {
1140 int bad32 = REX_R|REX_W|REX_X|REX_B;
1141
1142 if (ins->rex & REX_H) {
1143 errfunc(ERR_NONFATAL, "cannot use high register in vex instruction");
1144 return -1;
1145 }
1146 switch (ins->vex_wlp & 030) {
1147 case 000:
1148 ins->rex &= ~REX_W;
1149 break;
1150 case 010:
1151 ins->rex |= REX_W;
1152 bad32 &= ~REX_W;
1153 break;
1154 default:
1155 /* Follow REX_W */
1156 break;
1157 }
1158
1159 if (bits != 64 && ((ins->rex & bad32) || ins->drexdst > 7)) {
1160 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1161 return -1;
1162 }
1163 if (ins->vex_m != 1 || (ins->rex & (REX_W|REX_R|REX_B)))
1164 length += 3;
1165 else
1166 length += 2;
1167 } else if (ins->rex & REX_D) {
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001168 if (ins->rex & REX_H) {
1169 errfunc(ERR_NONFATAL, "cannot use high register in drex instruction");
1170 return -1;
1171 }
H. Peter Anvind85d2502008-05-04 17:53:31 -07001172 if (bits != 64 && ((ins->rex & (REX_R|REX_W|REX_X|REX_B)) ||
H. Peter Anvincf5180a2007-09-17 17:25:27 -07001173 ins->drexdst > 7)) {
1174 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1175 return -1;
1176 }
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001177 length++;
1178 } else if (ins->rex & REX_REAL) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001179 if (ins->rex & REX_H) {
1180 errfunc(ERR_NONFATAL, "cannot use high register in rex instruction");
1181 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001182 } else if (bits == 64) {
1183 length++;
1184 } else if ((ins->rex & REX_L) &&
1185 !(ins->rex & (REX_P|REX_W|REX_X|REX_B)) &&
1186 cpu >= IF_X86_64) {
1187 /* LOCK-as-REX.R */
1188 assert_no_prefix(ins, PPS_LREP);
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001189 length++;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001190 } else {
H. Peter Anvincf5180a2007-09-17 17:25:27 -07001191 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1192 return -1;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001193 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00001194 }
1195
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001196 return length;
1197}
Keith Kaniosb7a89542007-04-12 02:40:54 +00001198
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001199#define EMIT_REX() \
H. Peter Anvind85d2502008-05-04 17:53:31 -07001200 if (!(ins->rex & (REX_D|REX_V)) && (ins->rex & REX_REAL) && (bits == 64)) { \
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001201 ins->rex = (ins->rex & REX_REAL)|REX_P; \
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001202 out(offset, segment, &ins->rex, OUT_RAWDATA, 1, NO_SEG, NO_SEG); \
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001203 ins->rex = 0; \
1204 offset += 1; \
1205 }
1206
Charles Crayne1f8bc4c2007-11-06 18:27:23 -08001207static void gencode(int32_t segment, int64_t offset, int bits,
H. Peter Anvin3720f7b2008-05-12 11:00:50 -07001208 insn * ins, const uint8_t *codes, int64_t insn_end)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001209{
Keith Kaniosa6dfa782007-04-13 16:47:53 +00001210 static char condval[] = { /* conditional opcodes */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001211 0x7, 0x3, 0x2, 0x6, 0x2, 0x4, 0xF, 0xD, 0xC, 0xE, 0x6, 0x2,
1212 0x3, 0x7, 0x3, 0x5, 0xE, 0xC, 0xD, 0xF, 0x1, 0xB, 0x9, 0x5,
1213 0x0, 0xA, 0xA, 0xB, 0x8, 0x4
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001214 };
Keith Kaniosb7a89542007-04-12 02:40:54 +00001215 uint8_t c;
1216 uint8_t bytes[4];
Charles Crayne1f8bc4c2007-11-06 18:27:23 -08001217 int64_t size;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001218 int64_t data;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001219 struct operand *opx;
H. Peter Anvin70653092007-10-19 14:42:29 -07001220
H. Peter Anvin839eca22007-10-29 23:12:47 -07001221 while (*codes) {
1222 c = *codes++;
1223 opx = &ins->oprs[c & 3];
1224 switch (c) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001225 case 01:
1226 case 02:
1227 case 03:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001228 EMIT_REX();
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001229 out(offset, segment, codes, OUT_RAWDATA, c, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001230 codes += c;
1231 offset += c;
1232 break;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001233
H. Peter Anvine2c80182005-01-15 22:15:51 +00001234 case 04:
1235 case 06:
1236 switch (ins->oprs[0].basereg) {
1237 case R_CS:
1238 bytes[0] = 0x0E + (c == 0x04 ? 1 : 0);
1239 break;
1240 case R_DS:
1241 bytes[0] = 0x1E + (c == 0x04 ? 1 : 0);
1242 break;
1243 case R_ES:
1244 bytes[0] = 0x06 + (c == 0x04 ? 1 : 0);
1245 break;
1246 case R_SS:
1247 bytes[0] = 0x16 + (c == 0x04 ? 1 : 0);
1248 break;
1249 default:
1250 errfunc(ERR_PANIC,
1251 "bizarre 8086 segment register received");
1252 }
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001253 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001254 offset++;
1255 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001256
H. Peter Anvine2c80182005-01-15 22:15:51 +00001257 case 05:
1258 case 07:
1259 switch (ins->oprs[0].basereg) {
1260 case R_FS:
1261 bytes[0] = 0xA0 + (c == 0x05 ? 1 : 0);
1262 break;
1263 case R_GS:
1264 bytes[0] = 0xA8 + (c == 0x05 ? 1 : 0);
1265 break;
1266 default:
1267 errfunc(ERR_PANIC,
1268 "bizarre 386 segment register received");
1269 }
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001270 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001271 offset++;
1272 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001273
H. Peter Anvine2c80182005-01-15 22:15:51 +00001274 case 010:
1275 case 011:
1276 case 012:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001277 case 013:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001278 EMIT_REX();
H. Peter Anvin839eca22007-10-29 23:12:47 -07001279 bytes[0] = *codes++ + ((regval(opx)) & 7);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001280 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001281 offset += 1;
1282 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001283
H. Peter Anvine2c80182005-01-15 22:15:51 +00001284 case 014:
1285 case 015:
1286 case 016:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001287 case 017:
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001288 /* XXX: warns for legitimate optimizer actions */
H. Peter Anvin839eca22007-10-29 23:12:47 -07001289 if (opx->offset < -128 || opx->offset > 127) {
H. Peter Anvin72c64372008-01-08 22:13:48 -08001290 errfunc(ERR_WARNING | ERR_WARN_NOV,
1291 "signed byte value exceeds bounds");
H. Peter Anvine2c80182005-01-15 22:15:51 +00001292 }
H. Peter Anvineba20a72002-04-30 20:53:55 +00001293
H. Peter Anvin839eca22007-10-29 23:12:47 -07001294 if (opx->segment != NO_SEG) {
1295 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001296 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001297 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001298 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001299 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001300 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001301 NO_SEG);
1302 }
1303 offset += 1;
1304 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001305
H. Peter Anvine2c80182005-01-15 22:15:51 +00001306 case 020:
1307 case 021:
1308 case 022:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001309 case 023:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001310 if (opx->offset < -256 || opx->offset > 255) {
H. Peter Anvin72c64372008-01-08 22:13:48 -08001311 errfunc(ERR_WARNING | ERR_WARN_NOV,
1312 "byte value exceeds bounds");
H. Peter Anvine2c80182005-01-15 22:15:51 +00001313 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001314 if (opx->segment != NO_SEG) {
1315 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001316 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001317 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001318 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001319 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001320 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001321 NO_SEG);
1322 }
1323 offset += 1;
1324 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001325
H. Peter Anvine2c80182005-01-15 22:15:51 +00001326 case 024:
1327 case 025:
1328 case 026:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001329 case 027:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001330 if (opx->offset < 0 || opx->offset > 255)
H. Peter Anvin72c64372008-01-08 22:13:48 -08001331 errfunc(ERR_WARNING | ERR_WARN_NOV,
1332 "unsigned byte value exceeds bounds");
H. Peter Anvin839eca22007-10-29 23:12:47 -07001333 if (opx->segment != NO_SEG) {
1334 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001335 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001336 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001337 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001338 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001339 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001340 NO_SEG);
1341 }
1342 offset += 1;
1343 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001344
H. Peter Anvine2c80182005-01-15 22:15:51 +00001345 case 030:
1346 case 031:
1347 case 032:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001348 case 033:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001349 data = opx->offset;
1350 if (opx->segment == NO_SEG && opx->wrt == NO_SEG)
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001351 warn_overflow(2, data);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001352 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001353 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001354 offset += 2;
1355 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001356
H. Peter Anvine2c80182005-01-15 22:15:51 +00001357 case 034:
1358 case 035:
1359 case 036:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001360 case 037:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001361 if (opx->type & (BITS16 | BITS32))
1362 size = (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001363 else
1364 size = (bits == 16) ? 2 : 4;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001365 data = opx->offset;
1366 if (opx->segment == NO_SEG && opx->wrt == NO_SEG)
H. Peter Anvin10e27272007-10-29 22:56:08 -07001367 warn_overflow(size, data);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001368 out(offset, segment, &data, OUT_ADDRESS, size,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001369 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001370 offset += size;
1371 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001372
H. Peter Anvine2c80182005-01-15 22:15:51 +00001373 case 040:
1374 case 041:
1375 case 042:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001376 case 043:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001377 data = opx->offset;
H. Peter Anvin72c64372008-01-08 22:13:48 -08001378 if (opx->segment == NO_SEG && opx->wrt == NO_SEG)
1379 warn_overflow(4, data);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001380 out(offset, segment, &data, OUT_ADDRESS, 4,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001381 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001382 offset += 4;
1383 break;
H. Peter Anvin3ba46772002-05-27 23:19:35 +00001384
H. Peter Anvine2c80182005-01-15 22:15:51 +00001385 case 044:
1386 case 045:
1387 case 046:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001388 case 047:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001389 data = opx->offset;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001390 size = ins->addr_size >> 3;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001391 if (opx->segment == NO_SEG &&
1392 opx->wrt == NO_SEG)
H. Peter Anvin10e27272007-10-29 22:56:08 -07001393 warn_overflow(size, data);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001394 out(offset, segment, &data, OUT_ADDRESS, size,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001395 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001396 offset += size;
1397 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001398
H. Peter Anvine2c80182005-01-15 22:15:51 +00001399 case 050:
1400 case 051:
1401 case 052:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001402 case 053:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001403 if (opx->segment != segment)
H. Peter Anvine2c80182005-01-15 22:15:51 +00001404 errfunc(ERR_NONFATAL,
1405 "short relative jump outside segment");
H. Peter Anvin839eca22007-10-29 23:12:47 -07001406 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001407 if (data > 127 || data < -128)
1408 errfunc(ERR_NONFATAL, "short jump is out of range");
1409 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001410 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001411 offset += 1;
1412 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001413
Keith Kaniosb7a89542007-04-12 02:40:54 +00001414 case 054:
1415 case 055:
1416 case 056:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001417 case 057:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001418 data = (int64_t)opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001419 out(offset, segment, &data, OUT_ADDRESS, 8,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001420 opx->segment, opx->wrt);
Keith Kaniosb7a89542007-04-12 02:40:54 +00001421 offset += 8;
1422 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001423
H. Peter Anvine2c80182005-01-15 22:15:51 +00001424 case 060:
1425 case 061:
1426 case 062:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001427 case 063:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001428 if (opx->segment != segment) {
1429 data = opx->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001430 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001431 OUT_REL2ADR, insn_end - offset,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001432 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001433 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001434 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001435 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001436 OUT_ADDRESS, 2, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001437 }
1438 offset += 2;
1439 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001440
H. Peter Anvine2c80182005-01-15 22:15:51 +00001441 case 064:
1442 case 065:
1443 case 066:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001444 case 067:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001445 if (opx->type & (BITS16 | BITS32 | BITS64))
1446 size = (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001447 else
1448 size = (bits == 16) ? 2 : 4;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001449 if (opx->segment != segment) {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001450 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001451 out(offset, segment, &data,
1452 size == 2 ? OUT_REL2ADR : OUT_REL4ADR,
1453 insn_end - offset, opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001454 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001455 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001456 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001457 OUT_ADDRESS, size, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001458 }
1459 offset += size;
1460 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001461
H. Peter Anvine2c80182005-01-15 22:15:51 +00001462 case 070:
1463 case 071:
1464 case 072:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001465 case 073:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001466 if (opx->segment != segment) {
1467 data = opx->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001468 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001469 OUT_REL4ADR, insn_end - offset,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001470 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001471 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001472 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001473 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001474 OUT_ADDRESS, 4, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001475 }
1476 offset += 4;
1477 break;
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001478
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001479 case 074:
1480 case 075:
1481 case 076:
1482 case 077:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001483 if (opx->segment == NO_SEG)
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001484 errfunc(ERR_NONFATAL, "value referenced by FAR is not"
1485 " relocatable");
1486 data = 0L;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001487 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001488 outfmt->segbase(1 + opx->segment),
1489 opx->wrt);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001490 offset += 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001491 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001492
H. Peter Anvine2c80182005-01-15 22:15:51 +00001493 case 0140:
1494 case 0141:
1495 case 0142:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001496 case 0143:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001497 data = opx->offset;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001498 if (is_sbyte16(ins, c & 3)) {
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001499 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001500 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001501 NO_SEG);
1502 offset++;
1503 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001504 if (opx->segment == NO_SEG &&
1505 opx->wrt == NO_SEG)
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001506 warn_overflow(2, data);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001507 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001508 opx->segment, opx->wrt);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001509 offset += 2;
1510 }
1511 break;
1512
1513 case 0144:
1514 case 0145:
1515 case 0146:
1516 case 0147:
1517 EMIT_REX();
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001518 bytes[0] = *codes++;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001519 if (is_sbyte16(ins, c & 3))
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001520 bytes[0] |= 2; /* s-bit */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001521 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001522 offset++;
1523 break;
1524
1525 case 0150:
1526 case 0151:
1527 case 0152:
1528 case 0153:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001529 data = opx->offset;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001530 if (is_sbyte32(ins, c & 3)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001531 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001532 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001533 NO_SEG);
1534 offset++;
1535 } else {
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001536 out(offset, segment, &data, OUT_ADDRESS, 4,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001537 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001538 offset += 4;
1539 }
1540 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001541
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001542 case 0154:
1543 case 0155:
1544 case 0156:
1545 case 0157:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001546 EMIT_REX();
H. Peter Anvine2c80182005-01-15 22:15:51 +00001547 bytes[0] = *codes++;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001548 if (is_sbyte32(ins, c & 3))
H. Peter Anvine2c80182005-01-15 22:15:51 +00001549 bytes[0] |= 2; /* s-bit */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001550 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001551 offset++;
1552 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001553
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001554 case 0160:
1555 case 0161:
1556 case 0162:
1557 case 0163:
1558 case 0164:
1559 case 0165:
1560 case 0166:
1561 case 0167:
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001562 break;
1563
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001564 case 0171:
1565 bytes[0] =
1566 (ins->drexdst << 4) |
1567 (ins->rex & REX_OC ? 0x08 : 0) |
1568 (ins->rex & (REX_R|REX_X|REX_B));
1569 ins->rex = 0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001570 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001571 offset++;
1572 break;
1573
H. Peter Anvind85d2502008-05-04 17:53:31 -07001574 case 0172:
1575 c = *codes++;
1576 opx = &ins->oprs[c >> 3];
1577 bytes[0] = regvals[opx->basereg] << 4;
1578 opx = &ins->oprs[c & 7];
1579 if (opx->segment != NO_SEG || opx->wrt != NO_SEG) {
1580 errfunc(ERR_NONFATAL,
1581 "non-absolute expression not permitted as argument %d",
1582 c & 7);
1583 } else {
1584 if (opx->offset & ~15) {
1585 errfunc(ERR_WARNING | ERR_WARN_NOV,
1586 "four-bit argument exceeds bounds");
1587 }
1588 bytes[0] |= opx->offset & 15;
1589 }
1590 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1591 offset++;
1592 break;
1593
H. Peter Anvind58656f2008-05-06 20:11:14 -07001594 case 0173:
1595 c = *codes++;
1596 opx = &ins->oprs[c >> 4];
1597 bytes[0] = regvals[opx->basereg] << 4;
1598 bytes[0] |= c & 15;
1599 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1600 offset++;
1601 break;
1602
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001603 case 0250:
1604 case 0251:
1605 case 0252:
1606 case 0253:
1607 data = opx->offset;
1608 /* is_sbyte32() is right here, we have already warned */
1609 if (is_sbyte32(ins, c & 3)) {
1610 bytes[0] = data;
1611 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
1612 NO_SEG);
1613 offset++;
1614 } else {
1615 out(offset, segment, &data, OUT_ADDRESS, 4,
1616 opx->segment, opx->wrt);
1617 offset += 4;
1618 }
1619 break;
1620
H. Peter Anvind85d2502008-05-04 17:53:31 -07001621 case 0260:
1622 case 0261:
1623 case 0262:
1624 case 0263:
1625 case 0270:
1626 codes += 2;
1627 if (ins->vex_m != 1 || (ins->rex & (REX_W|REX_X|REX_B))) {
1628 bytes[0] = 0xc4;
H. Peter Anvin4d2c38c2008-05-04 23:15:13 -07001629 bytes[1] = ins->vex_m | ((~ins->rex & 7) << 5);
H. Peter Anvind85d2502008-05-04 17:53:31 -07001630 bytes[2] = ((ins->rex & REX_W) << (7-3)) |
H. Peter Anvin4d2c38c2008-05-04 23:15:13 -07001631 ((~ins->drexdst & 15)<< 3) | (ins->vex_wlp & 07);
H. Peter Anvind85d2502008-05-04 17:53:31 -07001632 out(offset, segment, &bytes, OUT_RAWDATA, 3, NO_SEG, NO_SEG);
1633 offset += 3;
1634 } else {
1635 bytes[0] = 0xc5;
H. Peter Anvin4d2c38c2008-05-04 23:15:13 -07001636 bytes[1] = ((~ins->rex & REX_R) << (7-2)) |
1637 ((~ins->drexdst & 15) << 3) | (ins->vex_wlp & 07);
H. Peter Anvind85d2502008-05-04 17:53:31 -07001638 out(offset, segment, &bytes, OUT_RAWDATA, 2, NO_SEG, NO_SEG);
1639 offset += 2;
1640 }
1641 break;
1642
H. Peter Anvine2c80182005-01-15 22:15:51 +00001643 case 0300:
1644 case 0301:
1645 case 0302:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001646 case 0303:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001647 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001648
H. Peter Anvine2c80182005-01-15 22:15:51 +00001649 case 0310:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001650 if (bits == 32 && !has_prefix(ins, PPS_ASIZE, P_A16)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001651 *bytes = 0x67;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001652 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001653 offset += 1;
1654 } else
1655 offset += 0;
1656 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001657
H. Peter Anvine2c80182005-01-15 22:15:51 +00001658 case 0311:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001659 if (bits != 32 && !has_prefix(ins, PPS_ASIZE, P_A32)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001660 *bytes = 0x67;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001661 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001662 offset += 1;
1663 } else
1664 offset += 0;
1665 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001666
H. Peter Anvine2c80182005-01-15 22:15:51 +00001667 case 0312:
1668 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001669
Keith Kaniosb7a89542007-04-12 02:40:54 +00001670 case 0313:
1671 ins->rex = 0;
1672 break;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07001673
H. Peter Anvin23440102007-11-12 21:02:33 -08001674 case 0314:
1675 case 0315:
1676 case 0316:
1677 case 0317:
1678 break;
1679
H. Peter Anvine2c80182005-01-15 22:15:51 +00001680 case 0320:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001681 if (bits != 16) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001682 *bytes = 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001683 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001684 offset += 1;
1685 } else
1686 offset += 0;
1687 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001688
H. Peter Anvine2c80182005-01-15 22:15:51 +00001689 case 0321:
1690 if (bits == 16) {
1691 *bytes = 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001692 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001693 offset += 1;
1694 } else
1695 offset += 0;
1696 break;
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001697
H. Peter Anvine2c80182005-01-15 22:15:51 +00001698 case 0322:
H. Peter Anvin70653092007-10-19 14:42:29 -07001699 case 0323:
1700 break;
1701
Keith Kaniosb7a89542007-04-12 02:40:54 +00001702 case 0324:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001703 ins->rex |= REX_W;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001704 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001705
H. Peter Anvine2c80182005-01-15 22:15:51 +00001706 case 0330:
1707 *bytes = *codes++ ^ condval[ins->condition];
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001708 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001709 offset += 1;
1710 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001711
H. Peter Anvine2c80182005-01-15 22:15:51 +00001712 case 0331:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001713 break;
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001714
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001715 case 0332:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001716 case 0333:
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001717 *bytes = c - 0332 + 0xF2;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001718 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001719 offset += 1;
1720 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001721
Keith Kanios48af1772007-08-17 07:37:52 +00001722 case 0334:
1723 if (ins->rex & REX_R) {
1724 *bytes = 0xF0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001725 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
Keith Kanios48af1772007-08-17 07:37:52 +00001726 offset += 1;
1727 }
1728 ins->rex &= ~(REX_L|REX_R);
1729 break;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001730
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001731 case 0335:
1732 break;
1733
H. Peter Anvine2c80182005-01-15 22:15:51 +00001734 case 0340:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001735 if (ins->oprs[0].segment != NO_SEG)
1736 errfunc(ERR_PANIC, "non-constant BSS size in pass two");
1737 else {
H. Peter Anvin428fd672007-11-15 10:25:52 -08001738 int64_t size = ins->oprs[0].offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001739 if (size > 0)
1740 out(offset, segment, NULL,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001741 OUT_RESERVE, size, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001742 offset += size;
1743 }
1744 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001745
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001746 case 0360:
1747 break;
1748
1749 case 0361:
1750 bytes[0] = 0x66;
1751 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1752 offset += 1;
1753 break;
1754
1755 case 0362:
1756 case 0363:
1757 bytes[0] = c - 0362 + 0xf2;
1758 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1759 offset += 1;
1760 break;
1761
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001762 case 0364:
1763 case 0365:
1764 break;
1765
Keith Kanios48af1772007-08-17 07:37:52 +00001766 case 0366:
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001767 case 0367:
1768 *bytes = c - 0366 + 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001769 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
Keith Kanios48af1772007-08-17 07:37:52 +00001770 offset += 1;
1771 break;
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001772
H. Peter Anvine2c80182005-01-15 22:15:51 +00001773 case 0370:
1774 case 0371:
1775 case 0372:
1776 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001777
H. Peter Anvine2c80182005-01-15 22:15:51 +00001778 case 0373:
1779 *bytes = bits == 16 ? 3 : 5;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001780 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001781 offset += 1;
1782 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001783
H. Peter Anvine2c80182005-01-15 22:15:51 +00001784 default: /* can't do it by 'case' statements */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001785 if (c >= 0100 && c <= 0277) { /* it's an EA */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001786 ea ea_data;
1787 int rfield;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001788 int32_t rflags;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001789 uint8_t *p;
1790 int32_t s;
H. Peter Anvin70653092007-10-19 14:42:29 -07001791
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001792 if (c <= 0177) {
1793 /* pick rfield from operand b */
1794 rflags = regflag(&ins->oprs[c & 7]);
1795 rfield = regvals[ins->oprs[c & 7].basereg];
1796 } else {
1797 /* rfield is constant */
1798 rflags = 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001799 rfield = c & 7;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001800 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001801
1802 if (!process_ea
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001803 (&ins->oprs[(c >> 3) & 7], &ea_data, bits,
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001804 ins->addr_size, rfield, rflags, ins->forw_ref)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001805 errfunc(ERR_NONFATAL, "invalid effective address");
1806 }
H. Peter Anvin70653092007-10-19 14:42:29 -07001807
Charles Crayne7e975552007-11-03 22:06:13 -07001808
H. Peter Anvine2c80182005-01-15 22:15:51 +00001809 p = bytes;
1810 *p++ = ea_data.modrm;
1811 if (ea_data.sib_present)
1812 *p++ = ea_data.sib;
1813
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001814 /* DREX suffixes come between the SIB and the displacement */
1815 if (ins->rex & REX_D) {
1816 *p++ =
1817 (ins->drexdst << 4) |
1818 (ins->rex & REX_OC ? 0x08 : 0) |
1819 (ins->rex & (REX_R|REX_X|REX_B));
1820 ins->rex = 0;
1821 }
1822
H. Peter Anvine2c80182005-01-15 22:15:51 +00001823 s = p - bytes;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001824 out(offset, segment, bytes, OUT_RAWDATA, s, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001825
1826 switch (ea_data.bytes) {
1827 case 0:
1828 break;
1829 case 1:
1830 if (ins->oprs[(c >> 3) & 7].segment != NO_SEG) {
1831 data = ins->oprs[(c >> 3) & 7].offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001832 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001833 ins->oprs[(c >> 3) & 7].segment,
1834 ins->oprs[(c >> 3) & 7].wrt);
1835 } else {
1836 *bytes = ins->oprs[(c >> 3) & 7].offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001837 out(offset, segment, bytes, OUT_RAWDATA, 1,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001838 NO_SEG, NO_SEG);
1839 }
1840 s++;
1841 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001842 case 8:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001843 case 2:
1844 case 4:
1845 data = ins->oprs[(c >> 3) & 7].offset;
Charles Crayne7e975552007-11-03 22:06:13 -07001846 warn_overflow(ea_data.bytes, data);
H. Peter Anvind0b0d282007-09-28 17:17:20 -07001847 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001848 ea_data.rip ? OUT_REL4ADR : OUT_ADDRESS,
1849 ea_data.bytes,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001850 ins->oprs[(c >> 3) & 7].segment,
1851 ins->oprs[(c >> 3) & 7].wrt);
1852 s += ea_data.bytes;
1853 break;
1854 }
1855 offset += s;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001856 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001857 errfunc(ERR_PANIC, "internal instruction table corrupt"
1858 ": instruction code 0x%02X given", c);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001859 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001860 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001861 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001862}
1863
H. Peter Anvin0ec60e62007-07-07 01:59:52 +00001864static int32_t regflag(const operand * o)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001865{
1866 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1867 errfunc(ERR_PANIC, "invalid operand passed to regflag()");
1868 }
1869 return reg_flags[o->basereg];
1870}
1871
H. Peter Anvin5b0e3ec2007-07-07 02:01:08 +00001872static int32_t regval(const operand * o)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001873{
H. Peter Anvine2c80182005-01-15 22:15:51 +00001874 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1875 errfunc(ERR_PANIC, "invalid operand passed to regval()");
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001876 }
H. Peter Anvin232badb2002-06-06 02:41:20 +00001877 return regvals[o->basereg];
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001878}
1879
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001880static int op_rexflags(const operand * o, int mask)
1881{
1882 int32_t flags;
1883 int val;
1884
1885 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1886 errfunc(ERR_PANIC, "invalid operand passed to op_rexflags()");
1887 }
1888
1889 flags = reg_flags[o->basereg];
1890 val = regvals[o->basereg];
1891
1892 return rexflags(val, flags, mask);
1893}
1894
1895static int rexflags(int val, int32_t flags, int mask)
1896{
1897 int rex = 0;
1898
1899 if (val >= 8)
1900 rex |= REX_B|REX_X|REX_R;
1901 if (flags & BITS64)
1902 rex |= REX_W;
1903 if (!(REG_HIGH & ~flags)) /* AH, CH, DH, BH */
1904 rex |= REX_H;
1905 else if (!(REG8 & ~flags) && val >= 4) /* SPL, BPL, SIL, DIL */
1906 rex |= REX_P;
1907
1908 return rex & mask;
1909}
1910
H. Peter Anvin3360d792007-09-11 04:16:57 +00001911static int matches(const struct itemplate *itemp, insn * instruction, int bits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001912{
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001913 int i, size[MAX_OPERANDS], asize, oprs, ret;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001914
1915 ret = 100;
1916
1917 /*
1918 * Check the opcode
1919 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001920 if (itemp->opcode != instruction->opcode)
1921 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001922
1923 /*
1924 * Count the operands
1925 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001926 if (itemp->operands != instruction->operands)
1927 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001928
1929 /*
1930 * Check that no spurious colons or TOs are present
1931 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001932 for (i = 0; i < itemp->operands; i++)
1933 if (instruction->oprs[i].type & ~itemp->opd[i] & (COLON | TO))
1934 return 0;
H. Peter Anvin70653092007-10-19 14:42:29 -07001935
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001936 /*
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001937 * Process size flags
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001938 */
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001939 if (itemp->flags & IF_ARMASK) {
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001940 memset(size, 0, sizeof size);
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001941
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001942 i = ((itemp->flags & IF_ARMASK) >> IF_ARSHFT) - 1;
1943
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001944 switch (itemp->flags & IF_SMASK) {
1945 case IF_SB:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001946 size[i] = BITS8;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001947 break;
1948 case IF_SW:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001949 size[i] = BITS16;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001950 break;
1951 case IF_SD:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001952 size[i] = BITS32;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001953 break;
1954 case IF_SQ:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001955 size[i] = BITS64;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001956 break;
H. Peter Anvin41c9f6f2007-09-18 13:01:32 -07001957 case IF_SO:
1958 size[i] = BITS128;
1959 break;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001960 case IF_SZ:
1961 switch (bits) {
1962 case 16:
1963 size[i] = BITS16;
1964 break;
1965 case 32:
1966 size[i] = BITS32;
1967 break;
1968 case 64:
1969 size[i] = BITS64;
1970 break;
1971 }
1972 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001973 default:
1974 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001975 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001976 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001977 asize = 0;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001978 switch (itemp->flags & IF_SMASK) {
1979 case IF_SB:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001980 asize = BITS8;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001981 break;
1982 case IF_SW:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001983 asize = BITS16;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001984 break;
1985 case IF_SD:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001986 asize = BITS32;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001987 break;
1988 case IF_SQ:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001989 asize = BITS64;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001990 break;
H. Peter Anvin41c9f6f2007-09-18 13:01:32 -07001991 case IF_SO:
1992 asize = BITS128;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001993 break;
1994 case IF_SZ:
1995 switch (bits) {
1996 case 16:
1997 asize = BITS16;
1998 break;
1999 case 32:
2000 asize = BITS32;
2001 break;
2002 case 64:
2003 asize = BITS64;
2004 break;
2005 }
H. Peter Anvin41c9f6f2007-09-18 13:01:32 -07002006 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07002007 default:
2008 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002009 }
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07002010 for (i = 0; i < MAX_OPERANDS; i++)
2011 size[i] = asize;
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002012 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002013
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002014 /*
2015 * Check that the operand flags all match up
2016 */
2017 for (i = 0; i < itemp->operands; i++) {
2018 int32_t type = instruction->oprs[i].type;
2019 if (!(type & SIZE_MASK))
2020 type |= size[i];
H. Peter Anvind85d2502008-05-04 17:53:31 -07002021
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002022 if (itemp->opd[i] & SAME_AS) {
2023 int j = itemp->opd[i] & ~SAME_AS;
2024 if (type != instruction->oprs[j].type ||
2025 instruction->oprs[i].basereg != instruction->oprs[j].basereg)
2026 return 0;
2027 } else if (itemp->opd[i] & ~type ||
2028 ((itemp->opd[i] & SIZE_MASK) &&
2029 ((itemp->opd[i] ^ type) & SIZE_MASK))) {
2030 if ((itemp->opd[i] & ~type & ~SIZE_MASK) ||
2031 (type & SIZE_MASK))
2032 return 0;
2033 else
2034 return 1;
2035 }
2036 }
2037
2038 /*
2039 * Check operand sizes
2040 */
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002041 if (itemp->flags & (IF_SM | IF_SM2)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002042 oprs = (itemp->flags & IF_SM2 ? 2 : itemp->operands);
2043 asize = 0;
2044 for (i = 0; i < oprs; i++) {
2045 if ((asize = itemp->opd[i] & SIZE_MASK) != 0) {
2046 int j;
2047 for (j = 0; j < oprs; j++)
2048 size[j] = asize;
2049 break;
2050 }
2051 }
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002052 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002053 oprs = itemp->operands;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002054 }
2055
Keith Kaniosb7a89542007-04-12 02:40:54 +00002056 for (i = 0; i < itemp->operands; i++) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002057 if (!(itemp->opd[i] & SIZE_MASK) &&
2058 (instruction->oprs[i].type & SIZE_MASK & ~size[i]))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002059 return 2;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002060 }
2061
H. Peter Anvinaf535c12002-04-30 20:59:21 +00002062 /*
2063 * Check template is okay at the set cpu level
2064 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002065 if (((itemp->flags & IF_PLEVEL) > cpu))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002066 return 3;
H. Peter Anvin70653092007-10-19 14:42:29 -07002067
Keith Kaniosb7a89542007-04-12 02:40:54 +00002068 /*
2069 * Check if instruction is available in long mode
2070 */
2071 if ((itemp->flags & IF_NOLONG) && (bits == 64))
2072 return 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002073
H. Peter Anvinaf535c12002-04-30 20:59:21 +00002074 /*
2075 * Check if special handling needed for Jumps
2076 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002077 if ((uint8_t)(itemp->code[0]) >= 0370)
H. Peter Anvine2c80182005-01-15 22:15:51 +00002078 return 99;
2079
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002080 return ret;
2081}
2082
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002083static ea *process_ea(operand * input, ea * output, int bits,
2084 int addrbits, int rfield, int32_t rflags, int forw_ref)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002085{
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002086 output->rip = false;
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00002087
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002088 /* REX flags for the rfield operand */
2089 output->rex |= rexflags(rfield, rflags, REX_R|REX_P|REX_W|REX_H);
2090
Keith Kaniosb7a89542007-04-12 02:40:54 +00002091 if (!(REGISTER & ~input->type)) { /* register direct */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002092 int i;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002093 int32_t f;
2094
2095 if (input->basereg < EXPR_REG_START /* Verify as Register */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002096 || input->basereg >= REG_ENUM_LIMIT)
H. Peter Anvine2c80182005-01-15 22:15:51 +00002097 return NULL;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002098 f = regflag(input);
Keith Kaniosb7a89542007-04-12 02:40:54 +00002099 i = regvals[input->basereg];
Keith Kaniosb7a89542007-04-12 02:40:54 +00002100
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002101 if (REG_EA & ~f)
2102 return NULL; /* Invalid EA register */
H. Peter Anvin70653092007-10-19 14:42:29 -07002103
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002104 output->rex |= op_rexflags(input, REX_B|REX_P|REX_W|REX_H);
2105
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002106 output->sib_present = false; /* no SIB necessary */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002107 output->bytes = 0; /* no offset necessary either */
2108 output->modrm = 0xC0 | ((rfield & 7) << 3) | (i & 7);
H. Peter Anvine2c80182005-01-15 22:15:51 +00002109 } else { /* it's a memory reference */
2110 if (input->basereg == -1
2111 && (input->indexreg == -1 || input->scale == 0)) {
2112 /* it's a pure offset */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002113 if (bits == 64 && (~input->type & IP_REL)) {
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002114 int scale, index, base;
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002115 output->sib_present = true;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002116 scale = 0;
2117 index = 4;
2118 base = 5;
2119 output->sib = (scale << 6) | (index << 3) | base;
2120 output->bytes = 4;
2121 output->modrm = 4 | ((rfield & 7) << 3);
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002122 output->rip = false;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002123 } else {
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002124 output->sib_present = false;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002125 output->bytes = (addrbits != 16 ? 4 : 2);
2126 output->modrm = (addrbits != 16 ? 5 : 6) | ((rfield & 7) << 3);
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002127 output->rip = bits == 64;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002128 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00002129 } else { /* it's an indirection */
2130 int i = input->indexreg, b = input->basereg, s = input->scale;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002131 int32_t o = input->offset, seg = input->segment;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002132 int hb = input->hintbase, ht = input->hinttype;
2133 int t;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002134 int it, bt;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002135 int32_t ix, bx; /* register flags */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002136
H. Peter Anvine2c80182005-01-15 22:15:51 +00002137 if (s == 0)
2138 i = -1; /* make this easy, at least */
H. Peter Anvin70653092007-10-19 14:42:29 -07002139
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002140 if (i >= EXPR_REG_START && i < REG_ENUM_LIMIT) {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002141 it = regvals[i];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002142 ix = reg_flags[i];
2143 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002144 it = -1;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002145 ix = 0;
2146 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002147
H. Peter Anvinb0c54622007-10-28 23:21:46 -07002148 if (b >= EXPR_REG_START && b < REG_ENUM_LIMIT) {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002149 bt = regvals[b];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002150 bx = reg_flags[b];
2151 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002152 bt = -1;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002153 bx = 0;
2154 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002155
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002156 /* check for a 32/64-bit memory reference... */
2157 if ((ix|bx) & (BITS32|BITS64)) {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002158 /* it must be a 32/64-bit memory reference. Firstly we have
2159 * to check that all registers involved are type E/Rxx. */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002160 int32_t sok = BITS32|BITS64;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002161
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002162 if (it != -1) {
2163 if (!(REG64 & ~ix) || !(REG32 & ~ix))
2164 sok &= ix;
2165 else
2166 return NULL;
2167 }
2168
2169 if (bt != -1) {
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00002170 if (REG_GPR & ~bx)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002171 return NULL; /* Invalid register */
H. Peter Anvina57e8d42007-05-30 03:44:02 +00002172 if (~sok & bx & SIZE_MASK)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002173 return NULL; /* Invalid size */
H. Peter Anvinb0c54622007-10-28 23:21:46 -07002174 sok &= bx;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002175 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002176
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002177 /* While we're here, ensure the user didn't specify
2178 WORD or QWORD. */
2179 if (input->disp_size == 16 || input->disp_size == 64)
2180 return NULL;
2181
2182 if (addrbits == 16 ||
2183 (addrbits == 32 && !(sok & BITS32)) ||
2184 (addrbits == 64 && !(sok & BITS64)))
2185 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002186
Keith Kaniosb7a89542007-04-12 02:40:54 +00002187 /* now reorganize base/index */
2188 if (s == 1 && bt != it && bt != -1 && it != -1 &&
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002189 ((hb == b && ht == EAH_NOTBASE)
2190 || (hb == i && ht == EAH_MAKEBASE))) {
2191 /* swap if hints say so */
2192 t = bt, bt = it, it = t;
2193 t = bx, bx = ix, ix = t;
2194 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00002195 if (bt == it) /* convert EAX+2*EAX to 3*EAX */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002196 bt = -1, bx = 0, s++;
2197 if (bt == -1 && s == 1 && !(hb == it && ht == EAH_NOTBASE)) {
2198 /* make single reg base, unless hint */
2199 bt = it, bx = ix, it = -1, ix = 0;
2200 }
H. Peter Anvinf5843c62007-09-10 18:59:26 +00002201 if (((s == 2 && it != REG_NUM_ESP
H. Peter Anvine2c80182005-01-15 22:15:51 +00002202 && !(input->eaflags & EAF_TIMESTWO)) || s == 3
Keith Kaniosb7a89542007-04-12 02:40:54 +00002203 || s == 5 || s == 9) && bt == -1)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002204 bt = it, bx = ix, s--; /* convert 3*EAX to EAX+2*EAX */
Keith Kanios48af1772007-08-17 07:37:52 +00002205 if (it == -1 && (bt & 7) != REG_NUM_ESP
H. Peter Anvine2c80182005-01-15 22:15:51 +00002206 && (input->eaflags & EAF_TIMESTWO))
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002207 it = bt, ix = bx, bt = -1, bx = 0, s = 1;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002208 /* convert [NOSPLIT EAX] to sib format with 0x0 displacement */
Keith Kanios48af1772007-08-17 07:37:52 +00002209 if (s == 1 && it == REG_NUM_ESP) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002210 /* swap ESP into base if scale is 1 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002211 t = it, it = bt, bt = t;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002212 t = ix, ix = bx, bx = t;
2213 }
Keith Kanios48af1772007-08-17 07:37:52 +00002214 if (it == REG_NUM_ESP
Keith Kaniosb7a89542007-04-12 02:40:54 +00002215 || (s != 1 && s != 2 && s != 4 && s != 8 && it != -1))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002216 return NULL; /* wrong, for various reasons */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002217
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002218 output->rex |= rexflags(it, ix, REX_X);
2219 output->rex |= rexflags(bt, bx, REX_B);
Keith Kaniosb7a89542007-04-12 02:40:54 +00002220
Keith Kanios48af1772007-08-17 07:37:52 +00002221 if (it == -1 && (bt & 7) != REG_NUM_ESP) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002222 /* no SIB needed */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002223 int mod, rm;
H. Peter Anvin70653092007-10-19 14:42:29 -07002224
Keith Kaniosb7a89542007-04-12 02:40:54 +00002225 if (bt == -1) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002226 rm = 5;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002227 mod = 0;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002228 } else {
2229 rm = (bt & 7);
Keith Kanios48af1772007-08-17 07:37:52 +00002230 if (rm != REG_NUM_EBP && o == 0 &&
Keith Kaniosb7a89542007-04-12 02:40:54 +00002231 seg == NO_SEG && !forw_ref &&
2232 !(input->eaflags &
2233 (EAF_BYTEOFFS | EAF_WORDOFFS)))
2234 mod = 0;
2235 else if (input->eaflags & EAF_BYTEOFFS ||
2236 (o >= -128 && o <= 127 && seg == NO_SEG
2237 && !forw_ref
2238 && !(input->eaflags & EAF_WORDOFFS)))
2239 mod = 1;
2240 else
2241 mod = 2;
2242 }
H. Peter Anvinea838272002-04-30 20:51:53 +00002243
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002244 output->sib_present = false;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002245 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2246 output->modrm = (mod << 6) | ((rfield & 7) << 3) | rm;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002247 } else {
2248 /* we need a SIB */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002249 int mod, scale, index, base;
H. Peter Anvin70653092007-10-19 14:42:29 -07002250
Keith Kaniosb7a89542007-04-12 02:40:54 +00002251 if (it == -1)
2252 index = 4, s = 1;
2253 else
2254 index = (it & 7);
H. Peter Anvin70653092007-10-19 14:42:29 -07002255
H. Peter Anvine2c80182005-01-15 22:15:51 +00002256 switch (s) {
2257 case 1:
2258 scale = 0;
2259 break;
2260 case 2:
2261 scale = 1;
2262 break;
2263 case 4:
2264 scale = 2;
2265 break;
2266 case 8:
2267 scale = 3;
2268 break;
2269 default: /* then what the smeg is it? */
2270 return NULL; /* panic */
2271 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002272
Keith Kaniosb7a89542007-04-12 02:40:54 +00002273 if (bt == -1) {
2274 base = 5;
2275 mod = 0;
2276 } else {
2277 base = (bt & 7);
Keith Kanios48af1772007-08-17 07:37:52 +00002278 if (base != REG_NUM_EBP && o == 0 &&
H. Peter Anvine2c80182005-01-15 22:15:51 +00002279 seg == NO_SEG && !forw_ref &&
2280 !(input->eaflags &
Keith Kaniosb7a89542007-04-12 02:40:54 +00002281 (EAF_BYTEOFFS | EAF_WORDOFFS)))
2282 mod = 0;
2283 else if (input->eaflags & EAF_BYTEOFFS ||
2284 (o >= -128 && o <= 127 && seg == NO_SEG
2285 && !forw_ref
2286 && !(input->eaflags & EAF_WORDOFFS)))
2287 mod = 1;
2288 else
2289 mod = 2;
2290 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002291
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002292 output->sib_present = true;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002293 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2294 output->modrm = (mod << 6) | ((rfield & 7) << 3) | 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002295 output->sib = (scale << 6) | (index << 3) | base;
2296 }
2297 } else { /* it's 16-bit */
2298 int mod, rm;
H. Peter Anvin70653092007-10-19 14:42:29 -07002299
Keith Kaniosb7a89542007-04-12 02:40:54 +00002300 /* check for 64-bit long mode */
2301 if (addrbits == 64)
2302 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002303
H. Peter Anvine2c80182005-01-15 22:15:51 +00002304 /* check all registers are BX, BP, SI or DI */
2305 if ((b != -1 && b != R_BP && b != R_BX && b != R_SI
2306 && b != R_DI) || (i != -1 && i != R_BP && i != R_BX
2307 && i != R_SI && i != R_DI))
2308 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002309
Keith Kaniosb7a89542007-04-12 02:40:54 +00002310 /* ensure the user didn't specify DWORD/QWORD */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002311 if (input->disp_size == 32 || input->disp_size == 64)
H. Peter Anvine2c80182005-01-15 22:15:51 +00002312 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002313
H. Peter Anvine2c80182005-01-15 22:15:51 +00002314 if (s != 1 && i != -1)
2315 return NULL; /* no can do, in 16-bit EA */
2316 if (b == -1 && i != -1) {
2317 int tmp = b;
2318 b = i;
2319 i = tmp;
2320 } /* swap */
2321 if ((b == R_SI || b == R_DI) && i != -1) {
2322 int tmp = b;
2323 b = i;
2324 i = tmp;
2325 }
2326 /* have BX/BP as base, SI/DI index */
2327 if (b == i)
2328 return NULL; /* shouldn't ever happen, in theory */
2329 if (i != -1 && b != -1 &&
2330 (i == R_BP || i == R_BX || b == R_SI || b == R_DI))
2331 return NULL; /* invalid combinations */
2332 if (b == -1) /* pure offset: handled above */
2333 return NULL; /* so if it gets to here, panic! */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002334
H. Peter Anvine2c80182005-01-15 22:15:51 +00002335 rm = -1;
2336 if (i != -1)
2337 switch (i * 256 + b) {
2338 case R_SI * 256 + R_BX:
2339 rm = 0;
2340 break;
2341 case R_DI * 256 + R_BX:
2342 rm = 1;
2343 break;
2344 case R_SI * 256 + R_BP:
2345 rm = 2;
2346 break;
2347 case R_DI * 256 + R_BP:
2348 rm = 3;
2349 break;
2350 } else
2351 switch (b) {
2352 case R_SI:
2353 rm = 4;
2354 break;
2355 case R_DI:
2356 rm = 5;
2357 break;
2358 case R_BP:
2359 rm = 6;
2360 break;
2361 case R_BX:
2362 rm = 7;
2363 break;
2364 }
2365 if (rm == -1) /* can't happen, in theory */
2366 return NULL; /* so panic if it does */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002367
H. Peter Anvine2c80182005-01-15 22:15:51 +00002368 if (o == 0 && seg == NO_SEG && !forw_ref && rm != 6 &&
2369 !(input->eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS)))
2370 mod = 0;
2371 else if (input->eaflags & EAF_BYTEOFFS ||
2372 (o >= -128 && o <= 127 && seg == NO_SEG
2373 && !forw_ref
2374 && !(input->eaflags & EAF_WORDOFFS)))
2375 mod = 1;
2376 else
2377 mod = 2;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002378
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002379 output->sib_present = false; /* no SIB - it's 16-bit */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002380 output->bytes = mod; /* bytes of offset needed */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002381 output->modrm = (mod << 6) | ((rfield & 7) << 3) | rm;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002382 }
2383 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002384 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002385
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002386 output->size = 1 + output->sib_present + output->bytes;
2387 return output;
2388}
2389
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002390static void add_asp(insn *ins, int addrbits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002391{
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002392 int j, valid;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002393 int defdisp;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002394
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002395 valid = (addrbits == 64) ? 64|32 : 32|16;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002396
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002397 switch (ins->prefixes[PPS_ASIZE]) {
2398 case P_A16:
2399 valid &= 16;
2400 break;
2401 case P_A32:
2402 valid &= 32;
2403 break;
2404 case P_A64:
2405 valid &= 64;
2406 break;
2407 case P_ASP:
2408 valid &= (addrbits == 32) ? 16 : 32;
2409 break;
2410 default:
2411 break;
2412 }
2413
2414 for (j = 0; j < ins->operands; j++) {
2415 if (!(MEMORY & ~ins->oprs[j].type)) {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002416 int32_t i, b;
H. Peter Anvin70653092007-10-19 14:42:29 -07002417
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002418 /* Verify as Register */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002419 if (ins->oprs[j].indexreg < EXPR_REG_START
2420 || ins->oprs[j].indexreg >= REG_ENUM_LIMIT)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002421 i = 0;
2422 else
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002423 i = reg_flags[ins->oprs[j].indexreg];
H. Peter Anvin70653092007-10-19 14:42:29 -07002424
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002425 /* Verify as Register */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002426 if (ins->oprs[j].basereg < EXPR_REG_START
2427 || ins->oprs[j].basereg >= REG_ENUM_LIMIT)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002428 b = 0;
2429 else
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002430 b = reg_flags[ins->oprs[j].basereg];
H. Peter Anvin70653092007-10-19 14:42:29 -07002431
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002432 if (ins->oprs[j].scale == 0)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002433 i = 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002434
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002435 if (!i && !b) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002436 int ds = ins->oprs[j].disp_size;
2437 if ((addrbits != 64 && ds > 8) ||
2438 (addrbits == 64 && ds == 16))
2439 valid &= ds;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002440 } else {
2441 if (!(REG16 & ~b))
2442 valid &= 16;
2443 if (!(REG32 & ~b))
2444 valid &= 32;
2445 if (!(REG64 & ~b))
2446 valid &= 64;
H. Peter Anvin70653092007-10-19 14:42:29 -07002447
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002448 if (!(REG16 & ~i))
2449 valid &= 16;
2450 if (!(REG32 & ~i))
2451 valid &= 32;
2452 if (!(REG64 & ~i))
2453 valid &= 64;
2454 }
2455 }
2456 }
2457
2458 if (valid & addrbits) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002459 ins->addr_size = addrbits;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002460 } else if (valid & ((addrbits == 32) ? 16 : 32)) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002461 /* Add an address size prefix */
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002462 enum prefixes pref = (addrbits == 32) ? P_A16 : P_A32;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002463 ins->prefixes[PPS_ASIZE] = pref;
2464 ins->addr_size = (addrbits == 32) ? 16 : 32;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002465 } else {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002466 /* Impossible... */
2467 errfunc(ERR_NONFATAL, "impossible combination of address sizes");
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002468 ins->addr_size = addrbits; /* Error recovery */
2469 }
2470
2471 defdisp = ins->addr_size == 16 ? 16 : 32;
2472
2473 for (j = 0; j < ins->operands; j++) {
2474 if (!(MEM_OFFS & ~ins->oprs[j].type) &&
2475 (ins->oprs[j].disp_size ? ins->oprs[j].disp_size : defdisp)
2476 != ins->addr_size) {
2477 /* mem_offs sizes must match the address size; if not,
2478 strip the MEM_OFFS bit and match only EA instructions */
2479 ins->oprs[j].type &= ~(MEM_OFFS & ~MEMORY);
2480 }
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002481 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002482}