blob: 63ac21e109a2a2f5ee7f4cc1965343f227da1a5a [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 Anvindfb91802008-05-20 11:43:53 -0700122/* Initialized to zero by the C standard */
123static const uint8_t const_zero_buf[256];
124
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000125typedef struct {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000126 int sib_present; /* is a SIB byte necessary? */
127 int bytes; /* # of bytes of offset needed */
128 int size; /* lazy - this is sib+bytes+1 */
129 uint8_t modrm, sib, rex, rip; /* the bytes themselves */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000130} ea;
131
Keith Kaniosb7a89542007-04-12 02:40:54 +0000132static uint32_t cpu; /* cpu level received from nasm.c */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000133static efunc errfunc;
134static struct ofmt *outfmt;
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000135static ListGen *list;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000136
H. Peter Anvin3720f7b2008-05-12 11:00:50 -0700137static int64_t calcsize(int32_t, int64_t, int, insn *, const uint8_t *);
138static void gencode(int32_t, int64_t, int, insn *, const uint8_t *, int64_t);
H. Peter Anvin3360d792007-09-11 04:16:57 +0000139static int matches(const struct itemplate *, insn *, int bits);
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000140static int32_t regflag(const operand *);
141static int32_t regval(const operand *);
142static int rexflags(int, int32_t, int);
143static int op_rexflags(const operand *, int);
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700144static ea *process_ea(operand *, ea *, int, int, int, int32_t, int);
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700145static void add_asp(insn *, int);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000146
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700147static int has_prefix(insn * ins, enum prefix_pos pos, enum prefixes prefix)
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000148{
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700149 return ins->prefixes[pos] == prefix;
150}
151
152static void assert_no_prefix(insn * ins, enum prefix_pos pos)
153{
154 if (ins->prefixes[pos])
155 errfunc(ERR_NONFATAL, "invalid %s prefix",
156 prefix_name(ins->prefixes[pos]));
157}
158
159static const char *size_name(int size)
160{
161 switch (size) {
162 case 1:
163 return "byte";
164 case 2:
165 return "word";
166 case 4:
167 return "dword";
168 case 8:
169 return "qword";
170 case 10:
171 return "tword";
172 case 16:
173 return "oword";
H. Peter Anvindfb91802008-05-20 11:43:53 -0700174 case 32:
175 return "yword";
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700176 default:
177 return "???";
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000178 }
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700179}
180
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700181static void warn_overflow(int size, int64_t data)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700182{
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700183 if (size < 8) {
Charles Craynedd462c82007-11-04 15:28:30 -0800184 int64_t lim = ((int64_t)1 << (size*8))-1;
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000185
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700186 if (data < ~lim || data > lim)
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700187 errfunc(ERR_WARNING | ERR_WARN_NOV,
188 "%s data exceeds bounds", size_name(size));
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700189 }
190}
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000191/*
192 * This routine wrappers the real output format's output routine,
193 * in order to pass a copy of the data off to the listing file
194 * generator at the same time.
195 */
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800196static void out(int64_t offset, int32_t segto, const void *data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800197 enum out_type type, uint64_t size,
198 int32_t segment, int32_t wrt)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000199{
Keith Kaniosb7a89542007-04-12 02:40:54 +0000200 static int32_t lineno = 0; /* static!!! */
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000201 static char *lnfname = NULL;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800202 uint8_t p[8];
H. Peter Anvineba20a72002-04-30 20:53:55 +0000203
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800204 if (type == OUT_ADDRESS && segment == NO_SEG && wrt == NO_SEG) {
205 /*
206 * This is a non-relocated address, and we're going to
207 * convert it into RAWDATA format.
208 */
209 uint8_t *q = p;
H. Peter Anvind1fb15c2007-11-13 09:37:59 -0800210
211 if (size > 8) {
212 errfunc(ERR_PANIC, "OUT_ADDRESS with size > 8");
213 return;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800214 }
H. Peter Anvind85d2502008-05-04 17:53:31 -0700215
H. Peter Anvind1fb15c2007-11-13 09:37:59 -0800216 WRITEADDR(q, *(int64_t *)data, size);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800217 data = p;
218 type = OUT_RAWDATA;
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000219 }
220
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800221 list->output(offset, data, type, size);
222
Frank Kotlerabebb082003-09-06 04:45:37 +0000223 /*
224 * this call to src_get determines when we call the
225 * debug-format-specific "linenum" function
226 * it updates lineno and lnfname to the current values
227 * returning 0 if "same as last time", -2 if lnfname
228 * changed, and the amount by which lineno changed,
229 * if it did. thus, these variables must be static
230 */
231
H. Peter Anvine2c80182005-01-15 22:15:51 +0000232 if (src_get(&lineno, &lnfname)) {
233 outfmt->current_dfmt->linenum(lnfname, lineno, segto);
H. Peter Anvince616072002-04-30 21:02:23 +0000234 }
H. Peter Anvineba20a72002-04-30 20:53:55 +0000235
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800236 outfmt->output(segto, data, type, size, segment, wrt);
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000237}
238
Charles Crayne5fbbc8c2007-11-07 19:03:46 -0800239static int jmp_match(int32_t segment, int64_t offset, int bits,
H. Peter Anvin3720f7b2008-05-12 11:00:50 -0700240 insn * ins, const uint8_t *code)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000241{
Charles Crayne5fbbc8c2007-11-07 19:03:46 -0800242 int64_t isize;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000243 uint8_t c = code[0];
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000244
H. Peter Anvine2c80182005-01-15 22:15:51 +0000245 if (c != 0370 && c != 0371)
246 return 0;
H. Peter Anvin788e6c12002-04-30 21:02:01 +0000247 if (ins->oprs[0].opflags & OPFLAG_FORWARD) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000248 if ((optimizing < 0 || (ins->oprs[0].type & STRICT))
249 && c == 0370)
250 return 1;
251 else
252 return (pass0 == 0); /* match a forward reference */
H. Peter Anvin788e6c12002-04-30 21:02:01 +0000253 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000254 isize = calcsize(segment, offset, bits, ins, code);
255 if (ins->oprs[0].segment != segment)
256 return 0;
257 isize = ins->oprs[0].offset - offset - isize; /* isize is now the delta */
258 if (isize >= -128L && isize <= 127L)
259 return 1; /* it is byte size */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000260
261 return 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000262}
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000263
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800264int64_t assemble(int32_t segment, int64_t offset, int bits, uint32_t cp,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000265 insn * instruction, struct ofmt *output, efunc error,
266 ListGen * listgen)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000267{
H. Peter Anvin3360d792007-09-11 04:16:57 +0000268 const struct itemplate *temp;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000269 int j;
270 int size_prob;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800271 int64_t insn_end;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000272 int32_t itimes;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800273 int64_t start = offset;
274 int64_t wsize = 0; /* size for DB etc. */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000275
H. Peter Anvine2c80182005-01-15 22:15:51 +0000276 errfunc = error; /* to pass to other functions */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000277 cpu = cp;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000278 outfmt = output; /* likewise */
279 list = listgen; /* and again */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000280
H. Peter Anvine2c80182005-01-15 22:15:51 +0000281 switch (instruction->opcode) {
282 case -1:
283 return 0;
284 case I_DB:
285 wsize = 1;
286 break;
287 case I_DW:
288 wsize = 2;
289 break;
290 case I_DD:
291 wsize = 4;
292 break;
293 case I_DQ:
294 wsize = 8;
295 break;
296 case I_DT:
297 wsize = 10;
298 break;
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700299 case I_DO:
300 wsize = 16;
301 break;
H. Peter Anvindfb91802008-05-20 11:43:53 -0700302 case I_DY:
303 wsize = 32;
304 break;
H. Peter Anvin16b0a332007-09-12 20:27:41 -0700305 default:
306 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000307 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000308
H. Peter Anvineba20a72002-04-30 20:53:55 +0000309 if (wsize) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000310 extop *e;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000311 int32_t t = instruction->times;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000312 if (t < 0)
313 errfunc(ERR_PANIC,
314 "instruction->times < 0 (%ld) in assemble()", t);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000315
H. Peter Anvine2c80182005-01-15 22:15:51 +0000316 while (t--) { /* repeat TIMES times */
317 for (e = instruction->eops; e; e = e->next) {
318 if (e->type == EOT_DB_NUMBER) {
319 if (wsize == 1) {
320 if (e->segment != NO_SEG)
321 errfunc(ERR_NONFATAL,
322 "one-byte relocation attempted");
323 else {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000324 uint8_t out_byte = e->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000325 out(offset, segment, &out_byte,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800326 OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000327 }
Keith Kanios61ff53c2007-04-14 18:54:52 +0000328 } else if (wsize > 8) {
H. Peter Anvindfb91802008-05-20 11:43:53 -0700329 errfunc(ERR_NONFATAL, "integer supplied to a DT, DO or DY"
Keith Kanios61ff53c2007-04-14 18:54:52 +0000330 " instruction");
H. Peter Anvine2c80182005-01-15 22:15:51 +0000331 } else
332 out(offset, segment, &e->offset,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800333 OUT_ADDRESS, wsize, e->segment, e->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000334 offset += wsize;
335 } else if (e->type == EOT_DB_STRING) {
336 int align;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000337
H. Peter Anvine2c80182005-01-15 22:15:51 +0000338 out(offset, segment, e->stringval,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800339 OUT_RAWDATA, e->stringlen, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000340 align = e->stringlen % wsize;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000341
H. Peter Anvine2c80182005-01-15 22:15:51 +0000342 if (align) {
343 align = wsize - align;
H. Peter Anvindfb91802008-05-20 11:43:53 -0700344 out(offset, segment, const_zero_buf,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800345 OUT_RAWDATA, align, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000346 }
347 offset += e->stringlen + align;
348 }
349 }
350 if (t > 0 && t == instruction->times - 1) {
351 /*
352 * Dummy call to list->output to give the offset to the
353 * listing module.
354 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800355 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000356 list->uplevel(LIST_TIMES);
357 }
358 }
359 if (instruction->times > 1)
360 list->downlevel(LIST_TIMES);
361 return offset - start;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000362 }
363
H. Peter Anvine2c80182005-01-15 22:15:51 +0000364 if (instruction->opcode == I_INCBIN) {
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000365 static char fname[FILENAME_MAX];
H. Peter Anvine2c80182005-01-15 22:15:51 +0000366 FILE *fp;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000367 int32_t len;
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000368 char *prefix = "", *combine;
369 char **pPrevPath = NULL;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000370
H. Peter Anvine2c80182005-01-15 22:15:51 +0000371 len = FILENAME_MAX - 1;
372 if (len > instruction->eops->stringlen)
373 len = instruction->eops->stringlen;
374 strncpy(fname, instruction->eops->stringval, len);
375 fname[len] = '\0';
H. Peter Anvineba20a72002-04-30 20:53:55 +0000376
Keith Kaniosb7a89542007-04-12 02:40:54 +0000377 while (1) { /* added by alexfru: 'incbin' uses include paths */
H. Peter Anvine2c80182005-01-15 22:15:51 +0000378 combine = nasm_malloc(strlen(prefix) + len + 1);
379 strcpy(combine, prefix);
380 strcat(combine, fname);
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000381
H. Peter Anvine2c80182005-01-15 22:15:51 +0000382 if ((fp = fopen(combine, "rb")) != NULL) {
383 nasm_free(combine);
384 break;
385 }
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000386
H. Peter Anvine2c80182005-01-15 22:15:51 +0000387 nasm_free(combine);
388 pPrevPath = pp_get_include_path_ptr(pPrevPath);
389 if (pPrevPath == NULL)
390 break;
391 prefix = *pPrevPath;
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000392 }
393
394 if (fp == NULL)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000395 error(ERR_NONFATAL, "`incbin': unable to open file `%s'",
396 fname);
397 else if (fseek(fp, 0L, SEEK_END) < 0)
398 error(ERR_NONFATAL, "`incbin': unable to seek on file `%s'",
399 fname);
400 else {
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000401 static char buf[2048];
Keith Kaniosb7a89542007-04-12 02:40:54 +0000402 int32_t t = instruction->times;
403 int32_t base = 0;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000404
H. Peter Anvine2c80182005-01-15 22:15:51 +0000405 len = ftell(fp);
406 if (instruction->eops->next) {
407 base = instruction->eops->next->offset;
408 len -= base;
409 if (instruction->eops->next->next &&
410 len > instruction->eops->next->next->offset)
411 len = instruction->eops->next->next->offset;
412 }
413 /*
414 * Dummy call to list->output to give the offset to the
415 * listing module.
416 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800417 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000418 list->uplevel(LIST_INCBIN);
419 while (t--) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000420 int32_t l;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000421
H. Peter Anvine2c80182005-01-15 22:15:51 +0000422 fseek(fp, base, SEEK_SET);
423 l = len;
424 while (l > 0) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000425 int32_t m =
Charles Crayne192d5b52007-10-18 19:02:42 -0700426 fread(buf, 1, (l > (int32_t) sizeof(buf) ? (int32_t) sizeof(buf) : l),
H. Peter Anvine2c80182005-01-15 22:15:51 +0000427 fp);
428 if (!m) {
429 /*
430 * This shouldn't happen unless the file
431 * actually changes while we are reading
432 * it.
433 */
434 error(ERR_NONFATAL,
435 "`incbin': unexpected EOF while"
436 " reading file `%s'", fname);
437 t = 0; /* Try to exit cleanly */
438 break;
439 }
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800440 out(offset, segment, buf, OUT_RAWDATA, m,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000441 NO_SEG, NO_SEG);
442 l -= m;
443 }
444 }
445 list->downlevel(LIST_INCBIN);
446 if (instruction->times > 1) {
447 /*
448 * Dummy call to list->output to give the offset to the
449 * listing module.
450 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800451 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000452 list->uplevel(LIST_TIMES);
453 list->downlevel(LIST_TIMES);
454 }
455 fclose(fp);
456 return instruction->times * len;
457 }
458 return 0; /* if we're here, there's an error */
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000459 }
460
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700461 /* Check to see if we need an address-size prefix */
462 add_asp(instruction, bits);
463
H. Peter Anvin6867acc2007-10-10 14:58:45 -0700464 size_prob = false;
H. Peter Anvin70653092007-10-19 14:42:29 -0700465
466 for (temp = nasm_instructions[instruction->opcode]; temp->opcode != -1; temp++){
Keith Kaniosb7a89542007-04-12 02:40:54 +0000467 int m = matches(temp, instruction, bits);
H. Peter Anvin70653092007-10-19 14:42:29 -0700468
H. Peter Anvine2c80182005-01-15 22:15:51 +0000469 if (m == 99)
470 m += jmp_match(segment, offset, bits, instruction, temp->code);
H. Peter Anvineba20a72002-04-30 20:53:55 +0000471
H. Peter Anvine2c80182005-01-15 22:15:51 +0000472 if (m == 100) { /* matches! */
H. Peter Anvin3720f7b2008-05-12 11:00:50 -0700473 const uint8_t *codes = temp->code;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800474 int64_t insn_size = calcsize(segment, offset, bits,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000475 instruction, codes);
476 itimes = instruction->times;
477 if (insn_size < 0) /* shouldn't be, on pass two */
478 error(ERR_PANIC, "errors made it through from pass one");
479 else
480 while (itimes--) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700481 for (j = 0; j < MAXPREFIX; j++) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000482 uint8_t c = 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000483 switch (instruction->prefixes[j]) {
484 case P_LOCK:
485 c = 0xF0;
486 break;
487 case P_REPNE:
488 case P_REPNZ:
489 c = 0xF2;
490 break;
491 case P_REPE:
492 case P_REPZ:
493 case P_REP:
494 c = 0xF3;
495 break;
496 case R_CS:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000497 if (bits == 64) {
498 error(ERR_WARNING,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800499 "cs 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 = 0x2E;
502 break;
503 case R_DS:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000504 if (bits == 64) {
505 error(ERR_WARNING,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800506 "ds 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 = 0x3E;
509 break;
510 case R_ES:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000511 if (bits == 64) {
512 error(ERR_WARNING,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800513 "es segment base generated, but will be ignored in 64-bit mode");
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000514 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000515 c = 0x26;
516 break;
517 case R_FS:
518 c = 0x64;
519 break;
520 case R_GS:
521 c = 0x65;
522 break;
523 case R_SS:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000524 if (bits == 64) {
525 error(ERR_WARNING,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800526 "ss segment base generated, but will be ignored in 64-bit mode");
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000527 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000528 c = 0x36;
529 break;
530 case R_SEGR6:
531 case R_SEGR7:
532 error(ERR_NONFATAL,
533 "segr6 and segr7 cannot be used as prefixes");
534 break;
535 case P_A16:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000536 if (bits == 64) {
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000537 error(ERR_NONFATAL,
538 "16-bit addressing is not supported "
539 "in 64-bit mode");
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700540 } else if (bits != 16)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000541 c = 0x67;
542 break;
543 case P_A32:
544 if (bits != 32)
545 c = 0x67;
546 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700547 case P_A64:
548 if (bits != 64) {
549 error(ERR_NONFATAL,
550 "64-bit addressing is only supported "
551 "in 64-bit mode");
552 }
553 break;
554 case P_ASP:
555 c = 0x67;
556 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000557 case P_O16:
558 if (bits != 16)
559 c = 0x66;
560 break;
561 case P_O32:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000562 if (bits == 16)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000563 c = 0x66;
564 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700565 case P_O64:
566 /* REX.W */
567 break;
568 case P_OSP:
569 c = 0x66;
570 break;
571 case P_none:
572 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000573 default:
574 error(ERR_PANIC, "invalid instruction prefix");
575 }
576 if (c != 0) {
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800577 out(offset, segment, &c, OUT_RAWDATA, 1,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000578 NO_SEG, NO_SEG);
579 offset++;
580 }
H. Peter Anvin70653092007-10-19 14:42:29 -0700581 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000582 insn_end = offset + insn_size;
583 gencode(segment, offset, bits, instruction, codes,
584 insn_end);
585 offset += insn_size;
586 if (itimes > 0 && itimes == instruction->times - 1) {
587 /*
588 * Dummy call to list->output to give the offset to the
589 * listing module.
590 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800591 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000592 list->uplevel(LIST_TIMES);
593 }
594 }
595 if (instruction->times > 1)
596 list->downlevel(LIST_TIMES);
597 return offset - start;
598 } else if (m > 0 && m > size_prob) {
599 size_prob = m;
600 }
Keith Kaniosb7a89542007-04-12 02:40:54 +0000601// temp++;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000602 }
H. Peter Anvineba20a72002-04-30 20:53:55 +0000603
H. Peter Anvine2c80182005-01-15 22:15:51 +0000604 if (temp->opcode == -1) { /* didn't match any instruction */
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000605 switch (size_prob) {
606 case 1:
607 error(ERR_NONFATAL, "operation size not specified");
608 break;
609 case 2:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000610 error(ERR_NONFATAL, "mismatch in operand sizes");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000611 break;
612 case 3:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000613 error(ERR_NONFATAL, "no instruction for this cpu level");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000614 break;
615 case 4:
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000616 error(ERR_NONFATAL, "instruction not supported in 64-bit mode");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000617 break;
618 default:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000619 error(ERR_NONFATAL,
620 "invalid combination of opcode and operands");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000621 break;
622 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000623 }
624 return 0;
625}
626
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800627int64_t insn_size(int32_t segment, int64_t offset, int bits, uint32_t cp,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000628 insn * instruction, efunc error)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000629{
H. Peter Anvin3360d792007-09-11 04:16:57 +0000630 const struct itemplate *temp;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000631
H. Peter Anvine2c80182005-01-15 22:15:51 +0000632 errfunc = error; /* to pass to other functions */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000633 cpu = cp;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000634
635 if (instruction->opcode == -1)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000636 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000637
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700638 if (instruction->opcode == I_DB || instruction->opcode == I_DW ||
639 instruction->opcode == I_DD || instruction->opcode == I_DQ ||
H. Peter Anvindfb91802008-05-20 11:43:53 -0700640 instruction->opcode == I_DT || instruction->opcode == I_DO ||
641 instruction->opcode == I_DY) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000642 extop *e;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000643 int32_t isize, osize, wsize = 0; /* placate gcc */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000644
H. Peter Anvine2c80182005-01-15 22:15:51 +0000645 isize = 0;
646 switch (instruction->opcode) {
647 case I_DB:
648 wsize = 1;
649 break;
650 case I_DW:
651 wsize = 2;
652 break;
653 case I_DD:
654 wsize = 4;
655 break;
656 case I_DQ:
657 wsize = 8;
658 break;
659 case I_DT:
660 wsize = 10;
661 break;
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700662 case I_DO:
663 wsize = 16;
664 break;
H. Peter Anvindfb91802008-05-20 11:43:53 -0700665 case I_DY:
666 wsize = 32;
667 break;
H. Peter Anvin16b0a332007-09-12 20:27:41 -0700668 default:
669 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000670 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000671
H. Peter Anvine2c80182005-01-15 22:15:51 +0000672 for (e = instruction->eops; e; e = e->next) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000673 int32_t align;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000674
H. Peter Anvine2c80182005-01-15 22:15:51 +0000675 osize = 0;
676 if (e->type == EOT_DB_NUMBER)
677 osize = 1;
678 else if (e->type == EOT_DB_STRING)
679 osize = e->stringlen;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000680
H. Peter Anvine2c80182005-01-15 22:15:51 +0000681 align = (-osize) % wsize;
682 if (align < 0)
683 align += wsize;
684 isize += osize + align;
685 }
686 return isize * instruction->times;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000687 }
688
H. Peter Anvine2c80182005-01-15 22:15:51 +0000689 if (instruction->opcode == I_INCBIN) {
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000690 char fname[FILENAME_MAX];
H. Peter Anvine2c80182005-01-15 22:15:51 +0000691 FILE *fp;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000692 int32_t len;
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000693 char *prefix = "", *combine;
694 char **pPrevPath = NULL;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000695
H. Peter Anvine2c80182005-01-15 22:15:51 +0000696 len = FILENAME_MAX - 1;
697 if (len > instruction->eops->stringlen)
698 len = instruction->eops->stringlen;
699 strncpy(fname, instruction->eops->stringval, len);
700 fname[len] = '\0';
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000701
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700702 /* added by alexfru: 'incbin' uses include paths */
703 while (1) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000704 combine = nasm_malloc(strlen(prefix) + len + 1);
705 strcpy(combine, prefix);
706 strcat(combine, fname);
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000707
H. Peter Anvine2c80182005-01-15 22:15:51 +0000708 if ((fp = fopen(combine, "rb")) != NULL) {
709 nasm_free(combine);
710 break;
711 }
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000712
H. Peter Anvine2c80182005-01-15 22:15:51 +0000713 nasm_free(combine);
714 pPrevPath = pp_get_include_path_ptr(pPrevPath);
715 if (pPrevPath == NULL)
716 break;
717 prefix = *pPrevPath;
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000718 }
719
720 if (fp == NULL)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000721 error(ERR_NONFATAL, "`incbin': unable to open file `%s'",
722 fname);
723 else if (fseek(fp, 0L, SEEK_END) < 0)
724 error(ERR_NONFATAL, "`incbin': unable to seek on file `%s'",
725 fname);
726 else {
727 len = ftell(fp);
728 fclose(fp);
729 if (instruction->eops->next) {
730 len -= instruction->eops->next->offset;
731 if (instruction->eops->next->next &&
732 len > instruction->eops->next->next->offset) {
733 len = instruction->eops->next->next->offset;
734 }
735 }
736 return instruction->times * len;
737 }
738 return 0; /* if we're here, there's an error */
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000739 }
740
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700741 /* Check to see if we need an address-size prefix */
742 add_asp(instruction, bits);
743
Keith Kaniosb7a89542007-04-12 02:40:54 +0000744 for (temp = nasm_instructions[instruction->opcode]; temp->opcode != -1; temp++) {
745 int m = matches(temp, instruction, bits);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000746 if (m == 99)
747 m += jmp_match(segment, offset, bits, instruction, temp->code);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000748
H. Peter Anvine2c80182005-01-15 22:15:51 +0000749 if (m == 100) {
750 /* we've matched an instruction. */
Charles Crayne5fbbc8c2007-11-07 19:03:46 -0800751 int64_t isize;
H. Peter Anvin3720f7b2008-05-12 11:00:50 -0700752 const uint8_t *codes = temp->code;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000753 int j;
754
755 isize = calcsize(segment, offset, bits, instruction, codes);
756 if (isize < 0)
757 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700758 for (j = 0; j < MAXPREFIX; j++) {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700759 switch (instruction->prefixes[j]) {
760 case P_A16:
761 if (bits != 16)
762 isize++;
763 break;
764 case P_A32:
765 if (bits != 32)
766 isize++;
767 break;
768 case P_O16:
769 if (bits != 16)
770 isize++;
771 break;
772 case P_O32:
773 if (bits == 16)
774 isize++;
775 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700776 case P_A64:
777 case P_O64:
778 case P_none:
779 break;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700780 default:
781 isize++;
782 break;
783 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000784 }
785 return isize * instruction->times;
786 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000787 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000788 return -1; /* didn't match any instruction */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000789}
790
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700791static bool possible_sbyte(insn * ins, int op)
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000792{
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700793 return !(ins->forw_ref && ins->oprs[op].opflags) &&
H. Peter Anvine2c80182005-01-15 22:15:51 +0000794 optimizing >= 0 &&
795 !(ins->oprs[op].type & STRICT) &&
796 ins->oprs[op].wrt == NO_SEG && ins->oprs[op].segment == NO_SEG;
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000797}
798
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700799/* check that opn[op] is a signed byte of size 16 or 32 */
800static bool is_sbyte16(insn * ins, int op)
801{
802 int16_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
811static bool is_sbyte32(insn * ins, int op)
812{
813 int32_t v;
814
815 if (!possible_sbyte(ins, op))
816 return false;
817
818 v = ins->oprs[op].offset;
819 return v >= -128 && v <= 127;
820}
821
822/* check that opn[op] is a signed byte of size 32; warn if this is not
823 the original value when extended to 64 bits */
824static bool is_sbyte64(insn * ins, int op)
825{
826 int64_t v64;
827 int32_t v32;
828
829 /* dead in the water on forward reference or External */
830 if (!possible_sbyte(ins, op))
831 return false;
832
833 v64 = ins->oprs[op].offset;
834 v32 = (int32_t)v64;
835
836 warn_overflow(32, v64);
837
838 return v32 >= -128 && v32 <= 127;
839}
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800840static int64_t calcsize(int32_t segment, int64_t offset, int bits,
H. Peter Anvin3720f7b2008-05-12 11:00:50 -0700841 insn * ins, const uint8_t *codes)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000842{
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800843 int64_t length = 0;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000844 uint8_t c;
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000845 int rex_mask = ~0;
H. Peter Anvin839eca22007-10-29 23:12:47 -0700846 struct operand *opx;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000847
H. Peter Anvine3917fc2007-11-01 14:53:32 -0700848 ins->rex = 0; /* Ensure REX is reset */
849
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700850 if (ins->prefixes[PPS_OSIZE] == P_O64)
851 ins->rex |= REX_W;
852
H. Peter Anvine2c80182005-01-15 22:15:51 +0000853 (void)segment; /* Don't warn that this parameter is unused */
854 (void)offset; /* Don't warn that this parameter is unused */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000855
H. Peter Anvin839eca22007-10-29 23:12:47 -0700856 while (*codes) {
857 c = *codes++;
858 opx = &ins->oprs[c & 3];
859 switch (c) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000860 case 01:
861 case 02:
862 case 03:
863 codes += c, length += c;
864 break;
865 case 04:
866 case 05:
867 case 06:
868 case 07:
869 length++;
870 break;
871 case 010:
872 case 011:
873 case 012:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700874 case 013:
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000875 ins->rex |=
H. Peter Anvin839eca22007-10-29 23:12:47 -0700876 op_rexflags(opx, REX_B|REX_H|REX_P|REX_W);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000877 codes++, length++;
878 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000879 case 014:
880 case 015:
881 case 016:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700882 case 017:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000883 length++;
884 break;
885 case 020:
886 case 021:
887 case 022:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700888 case 023:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000889 length++;
890 break;
891 case 024:
892 case 025:
893 case 026:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700894 case 027:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000895 length++;
896 break;
897 case 030:
898 case 031:
899 case 032:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700900 case 033:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000901 length += 2;
902 break;
903 case 034:
904 case 035:
905 case 036:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700906 case 037:
H. Peter Anvin839eca22007-10-29 23:12:47 -0700907 if (opx->type & (BITS16 | BITS32 | BITS64))
908 length += (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000909 else
910 length += (bits == 16) ? 2 : 4;
911 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000912 case 040:
913 case 041:
914 case 042:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700915 case 043:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000916 length += 4;
917 break;
918 case 044:
919 case 045:
920 case 046:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700921 case 047:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700922 length += ins->addr_size >> 3;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000923 break;
924 case 050:
925 case 051:
926 case 052:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700927 case 053:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000928 length++;
929 break;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000930 case 054:
931 case 055:
932 case 056:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700933 case 057:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000934 length += 8; /* MOV reg64/imm */
935 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000936 case 060:
937 case 061:
938 case 062:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700939 case 063:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000940 length += 2;
941 break;
942 case 064:
943 case 065:
944 case 066:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700945 case 067:
H. Peter Anvin839eca22007-10-29 23:12:47 -0700946 if (opx->type & (BITS16 | BITS32 | BITS64))
947 length += (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000948 else
949 length += (bits == 16) ? 2 : 4;
950 break;
951 case 070:
952 case 071:
953 case 072:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700954 case 073:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000955 length += 4;
956 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700957 case 074:
958 case 075:
959 case 076:
960 case 077:
961 length += 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000962 break;
963 case 0140:
964 case 0141:
965 case 0142:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700966 case 0143:
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700967 length += is_sbyte16(ins, c & 3) ? 1 : 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000968 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000969 case 0144:
970 case 0145:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700971 case 0146:
972 case 0147:
H. Peter Anvina30cc072007-11-18 21:55:26 -0800973 codes++;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000974 length++;
975 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700976 case 0150:
977 case 0151:
978 case 0152:
979 case 0153:
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700980 length += is_sbyte32(ins, c & 3) ? 1 : 4;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700981 break;
982 case 0154:
983 case 0155:
984 case 0156:
985 case 0157:
H. Peter Anvina30cc072007-11-18 21:55:26 -0800986 codes++;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700987 length++;
988 break;
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700989 case 0160:
990 case 0161:
991 case 0162:
992 case 0163:
993 length++;
994 ins->rex |= REX_D;
H. Peter Anvind85d2502008-05-04 17:53:31 -0700995 ins->drexdst = regval(opx);
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700996 break;
997 case 0164:
998 case 0165:
999 case 0166:
1000 case 0167:
1001 length++;
1002 ins->rex |= REX_D|REX_OC;
H. Peter Anvind85d2502008-05-04 17:53:31 -07001003 ins->drexdst = regval(opx);
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001004 break;
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001005 case 0171:
1006 break;
H. Peter Anvind85d2502008-05-04 17:53:31 -07001007 case 0172:
H. Peter Anvind58656f2008-05-06 20:11:14 -07001008 case 0173:
H. Peter Anvind85d2502008-05-04 17:53:31 -07001009 codes++;
1010 length++;
1011 break;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001012 case 0250:
1013 case 0251:
1014 case 0252:
1015 case 0253:
1016 length += is_sbyte64(ins, c & 3) ? 1 : 4;
1017 break;
H. Peter Anvind85d2502008-05-04 17:53:31 -07001018 case 0260:
1019 case 0261:
1020 case 0262:
1021 case 0263:
1022 length += 2;
1023 ins->rex |= REX_V;
1024 ins->drexdst = regval(opx);
1025 ins->vex_m = *codes++;
1026 ins->vex_wlp = *codes++;
1027 break;
1028 case 0270:
1029 length += 2;
1030 ins->rex |= REX_V;
1031 ins->drexdst = 0;
1032 ins->vex_m = *codes++;
1033 ins->vex_wlp = *codes++;
1034 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001035 case 0300:
1036 case 0301:
H. Peter Anvin70653092007-10-19 14:42:29 -07001037 case 0302:
1038 case 0303:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001039 break;
1040 case 0310:
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07001041 if (bits == 64)
1042 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001043 length += (bits != 16) && !has_prefix(ins, PPS_ASIZE, P_A16);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001044 break;
1045 case 0311:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001046 length += (bits != 32) && !has_prefix(ins, PPS_ASIZE, P_A32);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001047 break;
1048 case 0312:
H. Peter Anvin70653092007-10-19 14:42:29 -07001049 break;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001050 case 0313:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001051 if (bits != 64 || has_prefix(ins, PPS_ASIZE, P_A16) ||
1052 has_prefix(ins, PPS_ASIZE, P_A32))
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07001053 return -1;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001054 break;
H. Peter Anvin23440102007-11-12 21:02:33 -08001055 case 0314:
1056 case 0315:
1057 case 0316:
1058 case 0317:
1059 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001060 case 0320:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001061 length += (bits != 16);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001062 break;
1063 case 0321:
1064 length += (bits == 16);
1065 break;
1066 case 0322:
1067 break;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001068 case 0323:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001069 rex_mask &= ~REX_W;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001070 break;
1071 case 0324:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001072 ins->rex |= REX_W;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001073 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001074 case 0330:
1075 codes++, length++;
1076 break;
1077 case 0331:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001078 break;
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001079 case 0332:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001080 case 0333:
1081 length++;
1082 break;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001083 case 0334:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001084 ins->rex |= REX_L;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001085 break;
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001086 case 0335:
1087 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001088 case 0340:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001089 if (ins->oprs[0].segment != NO_SEG)
1090 errfunc(ERR_NONFATAL, "attempt to reserve non-constant"
1091 " quantity of BSS space");
1092 else
H. Peter Anvin428fd672007-11-15 10:25:52 -08001093 length += ins->oprs[0].offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001094 break;
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001095 case 0360:
1096 break;
1097 case 0361:
1098 case 0362:
1099 case 0363:
1100 length++;
1101 break;
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001102 case 0364:
1103 case 0365:
1104 break;
Keith Kanios48af1772007-08-17 07:37:52 +00001105 case 0366:
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001106 case 0367:
1107 length++;
1108 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001109 case 0370:
1110 case 0371:
1111 case 0372:
1112 break;
1113 case 0373:
1114 length++;
1115 break;
1116 default: /* can't do it by 'case' statements */
1117 if (c >= 0100 && c <= 0277) { /* it's an EA */
1118 ea ea_data;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001119 int rfield;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001120 int32_t rflags;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001121 ea_data.rex = 0; /* Ensure ea.REX is initially 0 */
H. Peter Anvin70653092007-10-19 14:42:29 -07001122
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001123 if (c <= 0177) {
1124 /* pick rfield from operand b */
1125 rflags = regflag(&ins->oprs[c & 7]);
1126 rfield = regvals[ins->oprs[c & 7].basereg];
1127 } else {
1128 rflags = 0;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001129 rfield = c & 7;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001130 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00001131
H. Peter Anvine2c80182005-01-15 22:15:51 +00001132 if (!process_ea
Keith Kaniosb7a89542007-04-12 02:40:54 +00001133 (&ins->oprs[(c >> 3) & 7], &ea_data, bits,
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001134 ins->addr_size, rfield, rflags, ins->forw_ref)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001135 errfunc(ERR_NONFATAL, "invalid effective address");
1136 return -1;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001137 } else {
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001138 ins->rex |= ea_data.rex;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001139 length += ea_data.size;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001140 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001141 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001142 errfunc(ERR_PANIC, "internal instruction table corrupt"
1143 ": instruction code 0x%02X given", c);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001144 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001145 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001146 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001147
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001148 ins->rex &= rex_mask;
H. Peter Anvin70653092007-10-19 14:42:29 -07001149
H. Peter Anvind85d2502008-05-04 17:53:31 -07001150 if (ins->rex & REX_V) {
1151 int bad32 = REX_R|REX_W|REX_X|REX_B;
1152
1153 if (ins->rex & REX_H) {
1154 errfunc(ERR_NONFATAL, "cannot use high register in vex instruction");
1155 return -1;
1156 }
1157 switch (ins->vex_wlp & 030) {
1158 case 000:
1159 ins->rex &= ~REX_W;
1160 break;
1161 case 010:
1162 ins->rex |= REX_W;
1163 bad32 &= ~REX_W;
1164 break;
1165 default:
1166 /* Follow REX_W */
1167 break;
1168 }
1169
1170 if (bits != 64 && ((ins->rex & bad32) || ins->drexdst > 7)) {
1171 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1172 return -1;
1173 }
1174 if (ins->vex_m != 1 || (ins->rex & (REX_W|REX_R|REX_B)))
1175 length += 3;
1176 else
1177 length += 2;
1178 } else if (ins->rex & REX_D) {
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001179 if (ins->rex & REX_H) {
1180 errfunc(ERR_NONFATAL, "cannot use high register in drex instruction");
1181 return -1;
1182 }
H. Peter Anvind85d2502008-05-04 17:53:31 -07001183 if (bits != 64 && ((ins->rex & (REX_R|REX_W|REX_X|REX_B)) ||
H. Peter Anvincf5180a2007-09-17 17:25:27 -07001184 ins->drexdst > 7)) {
1185 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1186 return -1;
1187 }
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001188 length++;
1189 } else if (ins->rex & REX_REAL) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001190 if (ins->rex & REX_H) {
1191 errfunc(ERR_NONFATAL, "cannot use high register in rex instruction");
1192 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001193 } else if (bits == 64) {
1194 length++;
1195 } else if ((ins->rex & REX_L) &&
1196 !(ins->rex & (REX_P|REX_W|REX_X|REX_B)) &&
1197 cpu >= IF_X86_64) {
1198 /* LOCK-as-REX.R */
1199 assert_no_prefix(ins, PPS_LREP);
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001200 length++;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001201 } else {
H. Peter Anvincf5180a2007-09-17 17:25:27 -07001202 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1203 return -1;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001204 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00001205 }
1206
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001207 return length;
1208}
Keith Kaniosb7a89542007-04-12 02:40:54 +00001209
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001210#define EMIT_REX() \
H. Peter Anvind85d2502008-05-04 17:53:31 -07001211 if (!(ins->rex & (REX_D|REX_V)) && (ins->rex & REX_REAL) && (bits == 64)) { \
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001212 ins->rex = (ins->rex & REX_REAL)|REX_P; \
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001213 out(offset, segment, &ins->rex, OUT_RAWDATA, 1, NO_SEG, NO_SEG); \
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001214 ins->rex = 0; \
1215 offset += 1; \
1216 }
1217
Charles Crayne1f8bc4c2007-11-06 18:27:23 -08001218static void gencode(int32_t segment, int64_t offset, int bits,
H. Peter Anvin3720f7b2008-05-12 11:00:50 -07001219 insn * ins, const uint8_t *codes, int64_t insn_end)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001220{
Keith Kaniosa6dfa782007-04-13 16:47:53 +00001221 static char condval[] = { /* conditional opcodes */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001222 0x7, 0x3, 0x2, 0x6, 0x2, 0x4, 0xF, 0xD, 0xC, 0xE, 0x6, 0x2,
1223 0x3, 0x7, 0x3, 0x5, 0xE, 0xC, 0xD, 0xF, 0x1, 0xB, 0x9, 0x5,
1224 0x0, 0xA, 0xA, 0xB, 0x8, 0x4
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001225 };
Keith Kaniosb7a89542007-04-12 02:40:54 +00001226 uint8_t c;
1227 uint8_t bytes[4];
Charles Crayne1f8bc4c2007-11-06 18:27:23 -08001228 int64_t size;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001229 int64_t data;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001230 struct operand *opx;
H. Peter Anvin70653092007-10-19 14:42:29 -07001231
H. Peter Anvin839eca22007-10-29 23:12:47 -07001232 while (*codes) {
1233 c = *codes++;
1234 opx = &ins->oprs[c & 3];
1235 switch (c) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001236 case 01:
1237 case 02:
1238 case 03:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001239 EMIT_REX();
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001240 out(offset, segment, codes, OUT_RAWDATA, c, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001241 codes += c;
1242 offset += c;
1243 break;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001244
H. Peter Anvine2c80182005-01-15 22:15:51 +00001245 case 04:
1246 case 06:
1247 switch (ins->oprs[0].basereg) {
1248 case R_CS:
1249 bytes[0] = 0x0E + (c == 0x04 ? 1 : 0);
1250 break;
1251 case R_DS:
1252 bytes[0] = 0x1E + (c == 0x04 ? 1 : 0);
1253 break;
1254 case R_ES:
1255 bytes[0] = 0x06 + (c == 0x04 ? 1 : 0);
1256 break;
1257 case R_SS:
1258 bytes[0] = 0x16 + (c == 0x04 ? 1 : 0);
1259 break;
1260 default:
1261 errfunc(ERR_PANIC,
1262 "bizarre 8086 segment register received");
1263 }
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001264 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001265 offset++;
1266 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001267
H. Peter Anvine2c80182005-01-15 22:15:51 +00001268 case 05:
1269 case 07:
1270 switch (ins->oprs[0].basereg) {
1271 case R_FS:
1272 bytes[0] = 0xA0 + (c == 0x05 ? 1 : 0);
1273 break;
1274 case R_GS:
1275 bytes[0] = 0xA8 + (c == 0x05 ? 1 : 0);
1276 break;
1277 default:
1278 errfunc(ERR_PANIC,
1279 "bizarre 386 segment register received");
1280 }
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001281 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001282 offset++;
1283 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001284
H. Peter Anvine2c80182005-01-15 22:15:51 +00001285 case 010:
1286 case 011:
1287 case 012:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001288 case 013:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001289 EMIT_REX();
H. Peter Anvin839eca22007-10-29 23:12:47 -07001290 bytes[0] = *codes++ + ((regval(opx)) & 7);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001291 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001292 offset += 1;
1293 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001294
H. Peter Anvine2c80182005-01-15 22:15:51 +00001295 case 014:
1296 case 015:
1297 case 016:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001298 case 017:
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001299 /* XXX: warns for legitimate optimizer actions */
H. Peter Anvin839eca22007-10-29 23:12:47 -07001300 if (opx->offset < -128 || opx->offset > 127) {
H. Peter Anvin72c64372008-01-08 22:13:48 -08001301 errfunc(ERR_WARNING | ERR_WARN_NOV,
1302 "signed byte value exceeds bounds");
H. Peter Anvine2c80182005-01-15 22:15:51 +00001303 }
H. Peter Anvineba20a72002-04-30 20:53:55 +00001304
H. Peter Anvin839eca22007-10-29 23:12:47 -07001305 if (opx->segment != NO_SEG) {
1306 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001307 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001308 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001309 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001310 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001311 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001312 NO_SEG);
1313 }
1314 offset += 1;
1315 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001316
H. Peter Anvine2c80182005-01-15 22:15:51 +00001317 case 020:
1318 case 021:
1319 case 022:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001320 case 023:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001321 if (opx->offset < -256 || opx->offset > 255) {
H. Peter Anvin72c64372008-01-08 22:13:48 -08001322 errfunc(ERR_WARNING | ERR_WARN_NOV,
1323 "byte value exceeds bounds");
H. Peter Anvine2c80182005-01-15 22:15:51 +00001324 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001325 if (opx->segment != NO_SEG) {
1326 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001327 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001328 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001329 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001330 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001331 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001332 NO_SEG);
1333 }
1334 offset += 1;
1335 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001336
H. Peter Anvine2c80182005-01-15 22:15:51 +00001337 case 024:
1338 case 025:
1339 case 026:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001340 case 027:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001341 if (opx->offset < 0 || opx->offset > 255)
H. Peter Anvin72c64372008-01-08 22:13:48 -08001342 errfunc(ERR_WARNING | ERR_WARN_NOV,
1343 "unsigned byte value exceeds bounds");
H. Peter Anvin839eca22007-10-29 23:12:47 -07001344 if (opx->segment != NO_SEG) {
1345 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001346 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001347 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001348 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001349 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001350 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001351 NO_SEG);
1352 }
1353 offset += 1;
1354 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001355
H. Peter Anvine2c80182005-01-15 22:15:51 +00001356 case 030:
1357 case 031:
1358 case 032:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001359 case 033:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001360 data = opx->offset;
1361 if (opx->segment == NO_SEG && opx->wrt == NO_SEG)
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001362 warn_overflow(2, data);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001363 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001364 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001365 offset += 2;
1366 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001367
H. Peter Anvine2c80182005-01-15 22:15:51 +00001368 case 034:
1369 case 035:
1370 case 036:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001371 case 037:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001372 if (opx->type & (BITS16 | BITS32))
1373 size = (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001374 else
1375 size = (bits == 16) ? 2 : 4;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001376 data = opx->offset;
1377 if (opx->segment == NO_SEG && opx->wrt == NO_SEG)
H. Peter Anvin10e27272007-10-29 22:56:08 -07001378 warn_overflow(size, data);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001379 out(offset, segment, &data, OUT_ADDRESS, size,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001380 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001381 offset += size;
1382 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001383
H. Peter Anvine2c80182005-01-15 22:15:51 +00001384 case 040:
1385 case 041:
1386 case 042:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001387 case 043:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001388 data = opx->offset;
H. Peter Anvin72c64372008-01-08 22:13:48 -08001389 if (opx->segment == NO_SEG && opx->wrt == NO_SEG)
1390 warn_overflow(4, data);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001391 out(offset, segment, &data, OUT_ADDRESS, 4,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001392 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001393 offset += 4;
1394 break;
H. Peter Anvin3ba46772002-05-27 23:19:35 +00001395
H. Peter Anvine2c80182005-01-15 22:15:51 +00001396 case 044:
1397 case 045:
1398 case 046:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001399 case 047:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001400 data = opx->offset;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001401 size = ins->addr_size >> 3;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001402 if (opx->segment == NO_SEG &&
1403 opx->wrt == NO_SEG)
H. Peter Anvin10e27272007-10-29 22:56:08 -07001404 warn_overflow(size, data);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001405 out(offset, segment, &data, OUT_ADDRESS, size,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001406 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001407 offset += size;
1408 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001409
H. Peter Anvine2c80182005-01-15 22:15:51 +00001410 case 050:
1411 case 051:
1412 case 052:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001413 case 053:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001414 if (opx->segment != segment)
H. Peter Anvine2c80182005-01-15 22:15:51 +00001415 errfunc(ERR_NONFATAL,
1416 "short relative jump outside segment");
H. Peter Anvin839eca22007-10-29 23:12:47 -07001417 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001418 if (data > 127 || data < -128)
1419 errfunc(ERR_NONFATAL, "short jump is out of range");
1420 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001421 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001422 offset += 1;
1423 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001424
Keith Kaniosb7a89542007-04-12 02:40:54 +00001425 case 054:
1426 case 055:
1427 case 056:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001428 case 057:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001429 data = (int64_t)opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001430 out(offset, segment, &data, OUT_ADDRESS, 8,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001431 opx->segment, opx->wrt);
Keith Kaniosb7a89542007-04-12 02:40:54 +00001432 offset += 8;
1433 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001434
H. Peter Anvine2c80182005-01-15 22:15:51 +00001435 case 060:
1436 case 061:
1437 case 062:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001438 case 063:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001439 if (opx->segment != segment) {
1440 data = opx->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001441 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001442 OUT_REL2ADR, insn_end - offset,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001443 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001444 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001445 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001446 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001447 OUT_ADDRESS, 2, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001448 }
1449 offset += 2;
1450 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001451
H. Peter Anvine2c80182005-01-15 22:15:51 +00001452 case 064:
1453 case 065:
1454 case 066:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001455 case 067:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001456 if (opx->type & (BITS16 | BITS32 | BITS64))
1457 size = (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001458 else
1459 size = (bits == 16) ? 2 : 4;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001460 if (opx->segment != segment) {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001461 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001462 out(offset, segment, &data,
1463 size == 2 ? OUT_REL2ADR : OUT_REL4ADR,
1464 insn_end - offset, opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001465 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001466 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001467 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001468 OUT_ADDRESS, size, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001469 }
1470 offset += size;
1471 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001472
H. Peter Anvine2c80182005-01-15 22:15:51 +00001473 case 070:
1474 case 071:
1475 case 072:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001476 case 073:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001477 if (opx->segment != segment) {
1478 data = opx->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001479 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001480 OUT_REL4ADR, insn_end - offset,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001481 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001482 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001483 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001484 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001485 OUT_ADDRESS, 4, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001486 }
1487 offset += 4;
1488 break;
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001489
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001490 case 074:
1491 case 075:
1492 case 076:
1493 case 077:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001494 if (opx->segment == NO_SEG)
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001495 errfunc(ERR_NONFATAL, "value referenced by FAR is not"
1496 " relocatable");
H. Peter Anvindfb91802008-05-20 11:43:53 -07001497 data = 0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001498 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001499 outfmt->segbase(1 + opx->segment),
1500 opx->wrt);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001501 offset += 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001502 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001503
H. Peter Anvine2c80182005-01-15 22:15:51 +00001504 case 0140:
1505 case 0141:
1506 case 0142:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001507 case 0143:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001508 data = opx->offset;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001509 if (is_sbyte16(ins, c & 3)) {
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001510 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001511 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001512 NO_SEG);
1513 offset++;
1514 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001515 if (opx->segment == NO_SEG &&
1516 opx->wrt == NO_SEG)
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001517 warn_overflow(2, data);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001518 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001519 opx->segment, opx->wrt);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001520 offset += 2;
1521 }
1522 break;
1523
1524 case 0144:
1525 case 0145:
1526 case 0146:
1527 case 0147:
1528 EMIT_REX();
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001529 bytes[0] = *codes++;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001530 if (is_sbyte16(ins, c & 3))
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001531 bytes[0] |= 2; /* s-bit */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001532 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001533 offset++;
1534 break;
1535
1536 case 0150:
1537 case 0151:
1538 case 0152:
1539 case 0153:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001540 data = opx->offset;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001541 if (is_sbyte32(ins, c & 3)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001542 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001543 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001544 NO_SEG);
1545 offset++;
1546 } else {
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001547 out(offset, segment, &data, OUT_ADDRESS, 4,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001548 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001549 offset += 4;
1550 }
1551 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001552
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001553 case 0154:
1554 case 0155:
1555 case 0156:
1556 case 0157:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001557 EMIT_REX();
H. Peter Anvine2c80182005-01-15 22:15:51 +00001558 bytes[0] = *codes++;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001559 if (is_sbyte32(ins, c & 3))
H. Peter Anvine2c80182005-01-15 22:15:51 +00001560 bytes[0] |= 2; /* s-bit */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001561 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001562 offset++;
1563 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001564
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001565 case 0160:
1566 case 0161:
1567 case 0162:
1568 case 0163:
1569 case 0164:
1570 case 0165:
1571 case 0166:
1572 case 0167:
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001573 break;
1574
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001575 case 0171:
1576 bytes[0] =
1577 (ins->drexdst << 4) |
1578 (ins->rex & REX_OC ? 0x08 : 0) |
1579 (ins->rex & (REX_R|REX_X|REX_B));
1580 ins->rex = 0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001581 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001582 offset++;
1583 break;
1584
H. Peter Anvind85d2502008-05-04 17:53:31 -07001585 case 0172:
1586 c = *codes++;
1587 opx = &ins->oprs[c >> 3];
1588 bytes[0] = regvals[opx->basereg] << 4;
1589 opx = &ins->oprs[c & 7];
1590 if (opx->segment != NO_SEG || opx->wrt != NO_SEG) {
1591 errfunc(ERR_NONFATAL,
1592 "non-absolute expression not permitted as argument %d",
1593 c & 7);
1594 } else {
1595 if (opx->offset & ~15) {
1596 errfunc(ERR_WARNING | ERR_WARN_NOV,
1597 "four-bit argument exceeds bounds");
1598 }
1599 bytes[0] |= opx->offset & 15;
1600 }
1601 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1602 offset++;
1603 break;
1604
H. Peter Anvind58656f2008-05-06 20:11:14 -07001605 case 0173:
1606 c = *codes++;
1607 opx = &ins->oprs[c >> 4];
1608 bytes[0] = regvals[opx->basereg] << 4;
1609 bytes[0] |= c & 15;
1610 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1611 offset++;
1612 break;
1613
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001614 case 0250:
1615 case 0251:
1616 case 0252:
1617 case 0253:
1618 data = opx->offset;
1619 /* is_sbyte32() is right here, we have already warned */
1620 if (is_sbyte32(ins, c & 3)) {
1621 bytes[0] = data;
1622 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
1623 NO_SEG);
1624 offset++;
1625 } else {
1626 out(offset, segment, &data, OUT_ADDRESS, 4,
1627 opx->segment, opx->wrt);
1628 offset += 4;
1629 }
1630 break;
1631
H. Peter Anvind85d2502008-05-04 17:53:31 -07001632 case 0260:
1633 case 0261:
1634 case 0262:
1635 case 0263:
1636 case 0270:
1637 codes += 2;
1638 if (ins->vex_m != 1 || (ins->rex & (REX_W|REX_X|REX_B))) {
1639 bytes[0] = 0xc4;
H. Peter Anvin4d2c38c2008-05-04 23:15:13 -07001640 bytes[1] = ins->vex_m | ((~ins->rex & 7) << 5);
H. Peter Anvind85d2502008-05-04 17:53:31 -07001641 bytes[2] = ((ins->rex & REX_W) << (7-3)) |
H. Peter Anvin4d2c38c2008-05-04 23:15:13 -07001642 ((~ins->drexdst & 15)<< 3) | (ins->vex_wlp & 07);
H. Peter Anvind85d2502008-05-04 17:53:31 -07001643 out(offset, segment, &bytes, OUT_RAWDATA, 3, NO_SEG, NO_SEG);
1644 offset += 3;
1645 } else {
1646 bytes[0] = 0xc5;
H. Peter Anvin4d2c38c2008-05-04 23:15:13 -07001647 bytes[1] = ((~ins->rex & REX_R) << (7-2)) |
1648 ((~ins->drexdst & 15) << 3) | (ins->vex_wlp & 07);
H. Peter Anvind85d2502008-05-04 17:53:31 -07001649 out(offset, segment, &bytes, OUT_RAWDATA, 2, NO_SEG, NO_SEG);
1650 offset += 2;
1651 }
1652 break;
1653
H. Peter Anvine2c80182005-01-15 22:15:51 +00001654 case 0300:
1655 case 0301:
1656 case 0302:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001657 case 0303:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001658 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001659
H. Peter Anvine2c80182005-01-15 22:15:51 +00001660 case 0310:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001661 if (bits == 32 && !has_prefix(ins, PPS_ASIZE, P_A16)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001662 *bytes = 0x67;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001663 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001664 offset += 1;
1665 } else
1666 offset += 0;
1667 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001668
H. Peter Anvine2c80182005-01-15 22:15:51 +00001669 case 0311:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001670 if (bits != 32 && !has_prefix(ins, PPS_ASIZE, P_A32)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001671 *bytes = 0x67;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001672 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001673 offset += 1;
1674 } else
1675 offset += 0;
1676 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001677
H. Peter Anvine2c80182005-01-15 22:15:51 +00001678 case 0312:
1679 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001680
Keith Kaniosb7a89542007-04-12 02:40:54 +00001681 case 0313:
1682 ins->rex = 0;
1683 break;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07001684
H. Peter Anvin23440102007-11-12 21:02:33 -08001685 case 0314:
1686 case 0315:
1687 case 0316:
1688 case 0317:
1689 break;
1690
H. Peter Anvine2c80182005-01-15 22:15:51 +00001691 case 0320:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001692 if (bits != 16) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001693 *bytes = 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001694 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001695 offset += 1;
1696 } else
1697 offset += 0;
1698 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001699
H. Peter Anvine2c80182005-01-15 22:15:51 +00001700 case 0321:
1701 if (bits == 16) {
1702 *bytes = 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001703 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001704 offset += 1;
1705 } else
1706 offset += 0;
1707 break;
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001708
H. Peter Anvine2c80182005-01-15 22:15:51 +00001709 case 0322:
H. Peter Anvin70653092007-10-19 14:42:29 -07001710 case 0323:
1711 break;
1712
Keith Kaniosb7a89542007-04-12 02:40:54 +00001713 case 0324:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001714 ins->rex |= REX_W;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001715 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001716
H. Peter Anvine2c80182005-01-15 22:15:51 +00001717 case 0330:
1718 *bytes = *codes++ ^ condval[ins->condition];
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001719 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001720 offset += 1;
1721 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001722
H. Peter Anvine2c80182005-01-15 22:15:51 +00001723 case 0331:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001724 break;
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001725
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001726 case 0332:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001727 case 0333:
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001728 *bytes = c - 0332 + 0xF2;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001729 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001730 offset += 1;
1731 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001732
Keith Kanios48af1772007-08-17 07:37:52 +00001733 case 0334:
1734 if (ins->rex & REX_R) {
1735 *bytes = 0xF0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001736 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
Keith Kanios48af1772007-08-17 07:37:52 +00001737 offset += 1;
1738 }
1739 ins->rex &= ~(REX_L|REX_R);
1740 break;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001741
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001742 case 0335:
1743 break;
1744
H. Peter Anvine2c80182005-01-15 22:15:51 +00001745 case 0340:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001746 if (ins->oprs[0].segment != NO_SEG)
1747 errfunc(ERR_PANIC, "non-constant BSS size in pass two");
1748 else {
H. Peter Anvin428fd672007-11-15 10:25:52 -08001749 int64_t size = ins->oprs[0].offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001750 if (size > 0)
1751 out(offset, segment, NULL,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001752 OUT_RESERVE, size, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001753 offset += size;
1754 }
1755 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001756
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001757 case 0360:
1758 break;
1759
1760 case 0361:
1761 bytes[0] = 0x66;
1762 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1763 offset += 1;
1764 break;
1765
1766 case 0362:
1767 case 0363:
1768 bytes[0] = c - 0362 + 0xf2;
1769 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1770 offset += 1;
1771 break;
1772
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001773 case 0364:
1774 case 0365:
1775 break;
1776
Keith Kanios48af1772007-08-17 07:37:52 +00001777 case 0366:
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001778 case 0367:
1779 *bytes = c - 0366 + 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001780 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
Keith Kanios48af1772007-08-17 07:37:52 +00001781 offset += 1;
1782 break;
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001783
H. Peter Anvine2c80182005-01-15 22:15:51 +00001784 case 0370:
1785 case 0371:
1786 case 0372:
1787 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001788
H. Peter Anvine2c80182005-01-15 22:15:51 +00001789 case 0373:
1790 *bytes = bits == 16 ? 3 : 5;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001791 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001792 offset += 1;
1793 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001794
H. Peter Anvine2c80182005-01-15 22:15:51 +00001795 default: /* can't do it by 'case' statements */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001796 if (c >= 0100 && c <= 0277) { /* it's an EA */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001797 ea ea_data;
1798 int rfield;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001799 int32_t rflags;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001800 uint8_t *p;
1801 int32_t s;
H. Peter Anvin70653092007-10-19 14:42:29 -07001802
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001803 if (c <= 0177) {
1804 /* pick rfield from operand b */
1805 rflags = regflag(&ins->oprs[c & 7]);
1806 rfield = regvals[ins->oprs[c & 7].basereg];
1807 } else {
1808 /* rfield is constant */
1809 rflags = 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001810 rfield = c & 7;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001811 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001812
1813 if (!process_ea
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001814 (&ins->oprs[(c >> 3) & 7], &ea_data, bits,
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001815 ins->addr_size, rfield, rflags, ins->forw_ref)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001816 errfunc(ERR_NONFATAL, "invalid effective address");
1817 }
H. Peter Anvin70653092007-10-19 14:42:29 -07001818
Charles Crayne7e975552007-11-03 22:06:13 -07001819
H. Peter Anvine2c80182005-01-15 22:15:51 +00001820 p = bytes;
1821 *p++ = ea_data.modrm;
1822 if (ea_data.sib_present)
1823 *p++ = ea_data.sib;
1824
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001825 /* DREX suffixes come between the SIB and the displacement */
1826 if (ins->rex & REX_D) {
1827 *p++ =
1828 (ins->drexdst << 4) |
1829 (ins->rex & REX_OC ? 0x08 : 0) |
1830 (ins->rex & (REX_R|REX_X|REX_B));
1831 ins->rex = 0;
1832 }
1833
H. Peter Anvine2c80182005-01-15 22:15:51 +00001834 s = p - bytes;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001835 out(offset, segment, bytes, OUT_RAWDATA, s, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001836
1837 switch (ea_data.bytes) {
1838 case 0:
1839 break;
1840 case 1:
1841 if (ins->oprs[(c >> 3) & 7].segment != NO_SEG) {
1842 data = ins->oprs[(c >> 3) & 7].offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001843 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001844 ins->oprs[(c >> 3) & 7].segment,
1845 ins->oprs[(c >> 3) & 7].wrt);
1846 } else {
1847 *bytes = ins->oprs[(c >> 3) & 7].offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001848 out(offset, segment, bytes, OUT_RAWDATA, 1,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001849 NO_SEG, NO_SEG);
1850 }
1851 s++;
1852 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001853 case 8:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001854 case 2:
1855 case 4:
1856 data = ins->oprs[(c >> 3) & 7].offset;
Charles Crayne7e975552007-11-03 22:06:13 -07001857 warn_overflow(ea_data.bytes, data);
H. Peter Anvind0b0d282007-09-28 17:17:20 -07001858 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001859 ea_data.rip ? OUT_REL4ADR : OUT_ADDRESS,
1860 ea_data.bytes,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001861 ins->oprs[(c >> 3) & 7].segment,
1862 ins->oprs[(c >> 3) & 7].wrt);
1863 s += ea_data.bytes;
1864 break;
1865 }
1866 offset += s;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001867 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001868 errfunc(ERR_PANIC, "internal instruction table corrupt"
1869 ": instruction code 0x%02X given", c);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001870 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001871 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001872 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001873}
1874
H. Peter Anvin0ec60e62007-07-07 01:59:52 +00001875static int32_t regflag(const operand * o)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001876{
1877 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1878 errfunc(ERR_PANIC, "invalid operand passed to regflag()");
1879 }
1880 return reg_flags[o->basereg];
1881}
1882
H. Peter Anvin5b0e3ec2007-07-07 02:01:08 +00001883static int32_t regval(const operand * o)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001884{
H. Peter Anvine2c80182005-01-15 22:15:51 +00001885 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1886 errfunc(ERR_PANIC, "invalid operand passed to regval()");
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001887 }
H. Peter Anvin232badb2002-06-06 02:41:20 +00001888 return regvals[o->basereg];
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001889}
1890
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001891static int op_rexflags(const operand * o, int mask)
1892{
1893 int32_t flags;
1894 int val;
1895
1896 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1897 errfunc(ERR_PANIC, "invalid operand passed to op_rexflags()");
1898 }
1899
1900 flags = reg_flags[o->basereg];
1901 val = regvals[o->basereg];
1902
1903 return rexflags(val, flags, mask);
1904}
1905
1906static int rexflags(int val, int32_t flags, int mask)
1907{
1908 int rex = 0;
1909
1910 if (val >= 8)
1911 rex |= REX_B|REX_X|REX_R;
1912 if (flags & BITS64)
1913 rex |= REX_W;
1914 if (!(REG_HIGH & ~flags)) /* AH, CH, DH, BH */
1915 rex |= REX_H;
1916 else if (!(REG8 & ~flags) && val >= 4) /* SPL, BPL, SIL, DIL */
1917 rex |= REX_P;
1918
1919 return rex & mask;
1920}
1921
H. Peter Anvin3360d792007-09-11 04:16:57 +00001922static int matches(const struct itemplate *itemp, insn * instruction, int bits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001923{
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001924 int i, size[MAX_OPERANDS], asize, oprs, ret;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001925
1926 ret = 100;
1927
1928 /*
1929 * Check the opcode
1930 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001931 if (itemp->opcode != instruction->opcode)
1932 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001933
1934 /*
1935 * Count the operands
1936 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001937 if (itemp->operands != instruction->operands)
1938 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001939
1940 /*
1941 * Check that no spurious colons or TOs are present
1942 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001943 for (i = 0; i < itemp->operands; i++)
1944 if (instruction->oprs[i].type & ~itemp->opd[i] & (COLON | TO))
1945 return 0;
H. Peter Anvin70653092007-10-19 14:42:29 -07001946
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001947 /*
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001948 * Process size flags
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001949 */
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001950 if (itemp->flags & IF_ARMASK) {
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001951 memset(size, 0, sizeof size);
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001952
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001953 i = ((itemp->flags & IF_ARMASK) >> IF_ARSHFT) - 1;
1954
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001955 switch (itemp->flags & IF_SMASK) {
1956 case IF_SB:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001957 size[i] = BITS8;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001958 break;
1959 case IF_SW:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001960 size[i] = BITS16;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001961 break;
1962 case IF_SD:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001963 size[i] = BITS32;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001964 break;
1965 case IF_SQ:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001966 size[i] = BITS64;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001967 break;
H. Peter Anvin41c9f6f2007-09-18 13:01:32 -07001968 case IF_SO:
1969 size[i] = BITS128;
1970 break;
H. Peter Anvindfb91802008-05-20 11:43:53 -07001971 case IF_SY:
1972 size[i] = BITS256;
1973 break;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001974 case IF_SZ:
1975 switch (bits) {
1976 case 16:
1977 size[i] = BITS16;
1978 break;
1979 case 32:
1980 size[i] = BITS32;
1981 break;
1982 case 64:
1983 size[i] = BITS64;
1984 break;
1985 }
1986 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001987 default:
1988 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001989 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001990 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001991 asize = 0;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001992 switch (itemp->flags & IF_SMASK) {
1993 case IF_SB:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001994 asize = BITS8;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001995 break;
1996 case IF_SW:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001997 asize = BITS16;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001998 break;
1999 case IF_SD:
H. Peter Anvine2c80182005-01-15 22:15:51 +00002000 asize = BITS32;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07002001 break;
2002 case IF_SQ:
Keith Kaniosb7a89542007-04-12 02:40:54 +00002003 asize = BITS64;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07002004 break;
H. Peter Anvin41c9f6f2007-09-18 13:01:32 -07002005 case IF_SO:
2006 asize = BITS128;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002007 break;
H. Peter Anvindfb91802008-05-20 11:43:53 -07002008 case IF_SY:
2009 asize = BITS256;
2010 break;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002011 case IF_SZ:
2012 switch (bits) {
2013 case 16:
2014 asize = BITS16;
2015 break;
2016 case 32:
2017 asize = BITS32;
2018 break;
2019 case 64:
2020 asize = BITS64;
2021 break;
2022 }
H. Peter Anvin41c9f6f2007-09-18 13:01:32 -07002023 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07002024 default:
2025 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002026 }
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07002027 for (i = 0; i < MAX_OPERANDS; i++)
2028 size[i] = asize;
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002029 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002030
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002031 /*
2032 * Check that the operand flags all match up
2033 */
2034 for (i = 0; i < itemp->operands; i++) {
2035 int32_t type = instruction->oprs[i].type;
2036 if (!(type & SIZE_MASK))
2037 type |= size[i];
H. Peter Anvind85d2502008-05-04 17:53:31 -07002038
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002039 if (itemp->opd[i] & SAME_AS) {
2040 int j = itemp->opd[i] & ~SAME_AS;
2041 if (type != instruction->oprs[j].type ||
2042 instruction->oprs[i].basereg != instruction->oprs[j].basereg)
2043 return 0;
2044 } else if (itemp->opd[i] & ~type ||
2045 ((itemp->opd[i] & SIZE_MASK) &&
2046 ((itemp->opd[i] ^ type) & SIZE_MASK))) {
2047 if ((itemp->opd[i] & ~type & ~SIZE_MASK) ||
2048 (type & SIZE_MASK))
2049 return 0;
2050 else
2051 return 1;
2052 }
2053 }
2054
2055 /*
2056 * Check operand sizes
2057 */
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002058 if (itemp->flags & (IF_SM | IF_SM2)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002059 oprs = (itemp->flags & IF_SM2 ? 2 : itemp->operands);
2060 asize = 0;
2061 for (i = 0; i < oprs; i++) {
2062 if ((asize = itemp->opd[i] & SIZE_MASK) != 0) {
2063 int j;
2064 for (j = 0; j < oprs; j++)
2065 size[j] = asize;
2066 break;
2067 }
2068 }
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002069 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002070 oprs = itemp->operands;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002071 }
2072
Keith Kaniosb7a89542007-04-12 02:40:54 +00002073 for (i = 0; i < itemp->operands; i++) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002074 if (!(itemp->opd[i] & SIZE_MASK) &&
2075 (instruction->oprs[i].type & SIZE_MASK & ~size[i]))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002076 return 2;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002077 }
2078
H. Peter Anvinaf535c12002-04-30 20:59:21 +00002079 /*
2080 * Check template is okay at the set cpu level
2081 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002082 if (((itemp->flags & IF_PLEVEL) > cpu))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002083 return 3;
H. Peter Anvin70653092007-10-19 14:42:29 -07002084
Keith Kaniosb7a89542007-04-12 02:40:54 +00002085 /*
2086 * Check if instruction is available in long mode
2087 */
2088 if ((itemp->flags & IF_NOLONG) && (bits == 64))
2089 return 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002090
H. Peter Anvinaf535c12002-04-30 20:59:21 +00002091 /*
2092 * Check if special handling needed for Jumps
2093 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002094 if ((uint8_t)(itemp->code[0]) >= 0370)
H. Peter Anvine2c80182005-01-15 22:15:51 +00002095 return 99;
2096
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002097 return ret;
2098}
2099
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002100static ea *process_ea(operand * input, ea * output, int bits,
2101 int addrbits, int rfield, int32_t rflags, int forw_ref)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002102{
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002103 output->rip = false;
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00002104
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002105 /* REX flags for the rfield operand */
2106 output->rex |= rexflags(rfield, rflags, REX_R|REX_P|REX_W|REX_H);
2107
Keith Kaniosb7a89542007-04-12 02:40:54 +00002108 if (!(REGISTER & ~input->type)) { /* register direct */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002109 int i;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002110 int32_t f;
2111
2112 if (input->basereg < EXPR_REG_START /* Verify as Register */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002113 || input->basereg >= REG_ENUM_LIMIT)
H. Peter Anvine2c80182005-01-15 22:15:51 +00002114 return NULL;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002115 f = regflag(input);
Keith Kaniosb7a89542007-04-12 02:40:54 +00002116 i = regvals[input->basereg];
Keith Kaniosb7a89542007-04-12 02:40:54 +00002117
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002118 if (REG_EA & ~f)
2119 return NULL; /* Invalid EA register */
H. Peter Anvin70653092007-10-19 14:42:29 -07002120
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002121 output->rex |= op_rexflags(input, REX_B|REX_P|REX_W|REX_H);
2122
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002123 output->sib_present = false; /* no SIB necessary */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002124 output->bytes = 0; /* no offset necessary either */
2125 output->modrm = 0xC0 | ((rfield & 7) << 3) | (i & 7);
H. Peter Anvine2c80182005-01-15 22:15:51 +00002126 } else { /* it's a memory reference */
2127 if (input->basereg == -1
2128 && (input->indexreg == -1 || input->scale == 0)) {
2129 /* it's a pure offset */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002130 if (bits == 64 && (~input->type & IP_REL)) {
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002131 int scale, index, base;
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002132 output->sib_present = true;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002133 scale = 0;
2134 index = 4;
2135 base = 5;
2136 output->sib = (scale << 6) | (index << 3) | base;
2137 output->bytes = 4;
2138 output->modrm = 4 | ((rfield & 7) << 3);
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002139 output->rip = false;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002140 } else {
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002141 output->sib_present = false;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002142 output->bytes = (addrbits != 16 ? 4 : 2);
2143 output->modrm = (addrbits != 16 ? 5 : 6) | ((rfield & 7) << 3);
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002144 output->rip = bits == 64;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002145 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00002146 } else { /* it's an indirection */
2147 int i = input->indexreg, b = input->basereg, s = input->scale;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002148 int32_t o = input->offset, seg = input->segment;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002149 int hb = input->hintbase, ht = input->hinttype;
2150 int t;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002151 int it, bt;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002152 int32_t ix, bx; /* register flags */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002153
H. Peter Anvine2c80182005-01-15 22:15:51 +00002154 if (s == 0)
2155 i = -1; /* make this easy, at least */
H. Peter Anvin70653092007-10-19 14:42:29 -07002156
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002157 if (i >= EXPR_REG_START && i < REG_ENUM_LIMIT) {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002158 it = regvals[i];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002159 ix = reg_flags[i];
2160 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002161 it = -1;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002162 ix = 0;
2163 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002164
H. Peter Anvinb0c54622007-10-28 23:21:46 -07002165 if (b >= EXPR_REG_START && b < REG_ENUM_LIMIT) {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002166 bt = regvals[b];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002167 bx = reg_flags[b];
2168 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002169 bt = -1;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002170 bx = 0;
2171 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002172
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002173 /* check for a 32/64-bit memory reference... */
2174 if ((ix|bx) & (BITS32|BITS64)) {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002175 /* it must be a 32/64-bit memory reference. Firstly we have
2176 * to check that all registers involved are type E/Rxx. */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002177 int32_t sok = BITS32|BITS64;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002178
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002179 if (it != -1) {
2180 if (!(REG64 & ~ix) || !(REG32 & ~ix))
2181 sok &= ix;
2182 else
2183 return NULL;
2184 }
2185
2186 if (bt != -1) {
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00002187 if (REG_GPR & ~bx)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002188 return NULL; /* Invalid register */
H. Peter Anvina57e8d42007-05-30 03:44:02 +00002189 if (~sok & bx & SIZE_MASK)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002190 return NULL; /* Invalid size */
H. Peter Anvinb0c54622007-10-28 23:21:46 -07002191 sok &= bx;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002192 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002193
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002194 /* While we're here, ensure the user didn't specify
2195 WORD or QWORD. */
2196 if (input->disp_size == 16 || input->disp_size == 64)
2197 return NULL;
2198
2199 if (addrbits == 16 ||
2200 (addrbits == 32 && !(sok & BITS32)) ||
2201 (addrbits == 64 && !(sok & BITS64)))
2202 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002203
Keith Kaniosb7a89542007-04-12 02:40:54 +00002204 /* now reorganize base/index */
2205 if (s == 1 && bt != it && bt != -1 && it != -1 &&
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002206 ((hb == b && ht == EAH_NOTBASE)
2207 || (hb == i && ht == EAH_MAKEBASE))) {
2208 /* swap if hints say so */
2209 t = bt, bt = it, it = t;
2210 t = bx, bx = ix, ix = t;
2211 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00002212 if (bt == it) /* convert EAX+2*EAX to 3*EAX */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002213 bt = -1, bx = 0, s++;
2214 if (bt == -1 && s == 1 && !(hb == it && ht == EAH_NOTBASE)) {
2215 /* make single reg base, unless hint */
2216 bt = it, bx = ix, it = -1, ix = 0;
2217 }
H. Peter Anvinf5843c62007-09-10 18:59:26 +00002218 if (((s == 2 && it != REG_NUM_ESP
H. Peter Anvine2c80182005-01-15 22:15:51 +00002219 && !(input->eaflags & EAF_TIMESTWO)) || s == 3
Keith Kaniosb7a89542007-04-12 02:40:54 +00002220 || s == 5 || s == 9) && bt == -1)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002221 bt = it, bx = ix, s--; /* convert 3*EAX to EAX+2*EAX */
Keith Kanios48af1772007-08-17 07:37:52 +00002222 if (it == -1 && (bt & 7) != REG_NUM_ESP
H. Peter Anvine2c80182005-01-15 22:15:51 +00002223 && (input->eaflags & EAF_TIMESTWO))
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002224 it = bt, ix = bx, bt = -1, bx = 0, s = 1;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002225 /* convert [NOSPLIT EAX] to sib format with 0x0 displacement */
Keith Kanios48af1772007-08-17 07:37:52 +00002226 if (s == 1 && it == REG_NUM_ESP) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002227 /* swap ESP into base if scale is 1 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002228 t = it, it = bt, bt = t;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002229 t = ix, ix = bx, bx = t;
2230 }
Keith Kanios48af1772007-08-17 07:37:52 +00002231 if (it == REG_NUM_ESP
Keith Kaniosb7a89542007-04-12 02:40:54 +00002232 || (s != 1 && s != 2 && s != 4 && s != 8 && it != -1))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002233 return NULL; /* wrong, for various reasons */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002234
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002235 output->rex |= rexflags(it, ix, REX_X);
2236 output->rex |= rexflags(bt, bx, REX_B);
Keith Kaniosb7a89542007-04-12 02:40:54 +00002237
Keith Kanios48af1772007-08-17 07:37:52 +00002238 if (it == -1 && (bt & 7) != REG_NUM_ESP) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002239 /* no SIB needed */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002240 int mod, rm;
H. Peter Anvin70653092007-10-19 14:42:29 -07002241
Keith Kaniosb7a89542007-04-12 02:40:54 +00002242 if (bt == -1) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002243 rm = 5;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002244 mod = 0;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002245 } else {
2246 rm = (bt & 7);
Keith Kanios48af1772007-08-17 07:37:52 +00002247 if (rm != REG_NUM_EBP && o == 0 &&
Keith Kaniosb7a89542007-04-12 02:40:54 +00002248 seg == NO_SEG && !forw_ref &&
2249 !(input->eaflags &
2250 (EAF_BYTEOFFS | EAF_WORDOFFS)))
2251 mod = 0;
2252 else if (input->eaflags & EAF_BYTEOFFS ||
2253 (o >= -128 && o <= 127 && seg == NO_SEG
2254 && !forw_ref
2255 && !(input->eaflags & EAF_WORDOFFS)))
2256 mod = 1;
2257 else
2258 mod = 2;
2259 }
H. Peter Anvinea838272002-04-30 20:51:53 +00002260
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002261 output->sib_present = false;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002262 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2263 output->modrm = (mod << 6) | ((rfield & 7) << 3) | rm;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002264 } else {
2265 /* we need a SIB */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002266 int mod, scale, index, base;
H. Peter Anvin70653092007-10-19 14:42:29 -07002267
Keith Kaniosb7a89542007-04-12 02:40:54 +00002268 if (it == -1)
2269 index = 4, s = 1;
2270 else
2271 index = (it & 7);
H. Peter Anvin70653092007-10-19 14:42:29 -07002272
H. Peter Anvine2c80182005-01-15 22:15:51 +00002273 switch (s) {
2274 case 1:
2275 scale = 0;
2276 break;
2277 case 2:
2278 scale = 1;
2279 break;
2280 case 4:
2281 scale = 2;
2282 break;
2283 case 8:
2284 scale = 3;
2285 break;
2286 default: /* then what the smeg is it? */
2287 return NULL; /* panic */
2288 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002289
Keith Kaniosb7a89542007-04-12 02:40:54 +00002290 if (bt == -1) {
2291 base = 5;
2292 mod = 0;
2293 } else {
2294 base = (bt & 7);
Keith Kanios48af1772007-08-17 07:37:52 +00002295 if (base != REG_NUM_EBP && o == 0 &&
H. Peter Anvine2c80182005-01-15 22:15:51 +00002296 seg == NO_SEG && !forw_ref &&
2297 !(input->eaflags &
Keith Kaniosb7a89542007-04-12 02:40:54 +00002298 (EAF_BYTEOFFS | EAF_WORDOFFS)))
2299 mod = 0;
2300 else if (input->eaflags & EAF_BYTEOFFS ||
2301 (o >= -128 && o <= 127 && seg == NO_SEG
2302 && !forw_ref
2303 && !(input->eaflags & EAF_WORDOFFS)))
2304 mod = 1;
2305 else
2306 mod = 2;
2307 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002308
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002309 output->sib_present = true;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002310 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2311 output->modrm = (mod << 6) | ((rfield & 7) << 3) | 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002312 output->sib = (scale << 6) | (index << 3) | base;
2313 }
2314 } else { /* it's 16-bit */
2315 int mod, rm;
H. Peter Anvin70653092007-10-19 14:42:29 -07002316
Keith Kaniosb7a89542007-04-12 02:40:54 +00002317 /* check for 64-bit long mode */
2318 if (addrbits == 64)
2319 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002320
H. Peter Anvine2c80182005-01-15 22:15:51 +00002321 /* check all registers are BX, BP, SI or DI */
2322 if ((b != -1 && b != R_BP && b != R_BX && b != R_SI
2323 && b != R_DI) || (i != -1 && i != R_BP && i != R_BX
2324 && i != R_SI && i != R_DI))
2325 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002326
Keith Kaniosb7a89542007-04-12 02:40:54 +00002327 /* ensure the user didn't specify DWORD/QWORD */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002328 if (input->disp_size == 32 || input->disp_size == 64)
H. Peter Anvine2c80182005-01-15 22:15:51 +00002329 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002330
H. Peter Anvine2c80182005-01-15 22:15:51 +00002331 if (s != 1 && i != -1)
2332 return NULL; /* no can do, in 16-bit EA */
2333 if (b == -1 && i != -1) {
2334 int tmp = b;
2335 b = i;
2336 i = tmp;
2337 } /* swap */
2338 if ((b == R_SI || b == R_DI) && i != -1) {
2339 int tmp = b;
2340 b = i;
2341 i = tmp;
2342 }
2343 /* have BX/BP as base, SI/DI index */
2344 if (b == i)
2345 return NULL; /* shouldn't ever happen, in theory */
2346 if (i != -1 && b != -1 &&
2347 (i == R_BP || i == R_BX || b == R_SI || b == R_DI))
2348 return NULL; /* invalid combinations */
2349 if (b == -1) /* pure offset: handled above */
2350 return NULL; /* so if it gets to here, panic! */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002351
H. Peter Anvine2c80182005-01-15 22:15:51 +00002352 rm = -1;
2353 if (i != -1)
2354 switch (i * 256 + b) {
2355 case R_SI * 256 + R_BX:
2356 rm = 0;
2357 break;
2358 case R_DI * 256 + R_BX:
2359 rm = 1;
2360 break;
2361 case R_SI * 256 + R_BP:
2362 rm = 2;
2363 break;
2364 case R_DI * 256 + R_BP:
2365 rm = 3;
2366 break;
2367 } else
2368 switch (b) {
2369 case R_SI:
2370 rm = 4;
2371 break;
2372 case R_DI:
2373 rm = 5;
2374 break;
2375 case R_BP:
2376 rm = 6;
2377 break;
2378 case R_BX:
2379 rm = 7;
2380 break;
2381 }
2382 if (rm == -1) /* can't happen, in theory */
2383 return NULL; /* so panic if it does */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002384
H. Peter Anvine2c80182005-01-15 22:15:51 +00002385 if (o == 0 && seg == NO_SEG && !forw_ref && rm != 6 &&
2386 !(input->eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS)))
2387 mod = 0;
2388 else if (input->eaflags & EAF_BYTEOFFS ||
2389 (o >= -128 && o <= 127 && seg == NO_SEG
2390 && !forw_ref
2391 && !(input->eaflags & EAF_WORDOFFS)))
2392 mod = 1;
2393 else
2394 mod = 2;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002395
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002396 output->sib_present = false; /* no SIB - it's 16-bit */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002397 output->bytes = mod; /* bytes of offset needed */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002398 output->modrm = (mod << 6) | ((rfield & 7) << 3) | rm;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002399 }
2400 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002401 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002402
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002403 output->size = 1 + output->sib_present + output->bytes;
2404 return output;
2405}
2406
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002407static void add_asp(insn *ins, int addrbits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002408{
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002409 int j, valid;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002410 int defdisp;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002411
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002412 valid = (addrbits == 64) ? 64|32 : 32|16;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002413
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002414 switch (ins->prefixes[PPS_ASIZE]) {
2415 case P_A16:
2416 valid &= 16;
2417 break;
2418 case P_A32:
2419 valid &= 32;
2420 break;
2421 case P_A64:
2422 valid &= 64;
2423 break;
2424 case P_ASP:
2425 valid &= (addrbits == 32) ? 16 : 32;
2426 break;
2427 default:
2428 break;
2429 }
2430
2431 for (j = 0; j < ins->operands; j++) {
2432 if (!(MEMORY & ~ins->oprs[j].type)) {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002433 int32_t i, b;
H. Peter Anvin70653092007-10-19 14:42:29 -07002434
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002435 /* Verify as Register */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002436 if (ins->oprs[j].indexreg < EXPR_REG_START
2437 || ins->oprs[j].indexreg >= REG_ENUM_LIMIT)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002438 i = 0;
2439 else
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002440 i = reg_flags[ins->oprs[j].indexreg];
H. Peter Anvin70653092007-10-19 14:42:29 -07002441
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002442 /* Verify as Register */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002443 if (ins->oprs[j].basereg < EXPR_REG_START
2444 || ins->oprs[j].basereg >= REG_ENUM_LIMIT)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002445 b = 0;
2446 else
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002447 b = reg_flags[ins->oprs[j].basereg];
H. Peter Anvin70653092007-10-19 14:42:29 -07002448
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002449 if (ins->oprs[j].scale == 0)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002450 i = 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002451
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002452 if (!i && !b) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002453 int ds = ins->oprs[j].disp_size;
2454 if ((addrbits != 64 && ds > 8) ||
2455 (addrbits == 64 && ds == 16))
2456 valid &= ds;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002457 } else {
2458 if (!(REG16 & ~b))
2459 valid &= 16;
2460 if (!(REG32 & ~b))
2461 valid &= 32;
2462 if (!(REG64 & ~b))
2463 valid &= 64;
H. Peter Anvin70653092007-10-19 14:42:29 -07002464
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002465 if (!(REG16 & ~i))
2466 valid &= 16;
2467 if (!(REG32 & ~i))
2468 valid &= 32;
2469 if (!(REG64 & ~i))
2470 valid &= 64;
2471 }
2472 }
2473 }
2474
2475 if (valid & addrbits) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002476 ins->addr_size = addrbits;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002477 } else if (valid & ((addrbits == 32) ? 16 : 32)) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002478 /* Add an address size prefix */
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002479 enum prefixes pref = (addrbits == 32) ? P_A16 : P_A32;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002480 ins->prefixes[PPS_ASIZE] = pref;
2481 ins->addr_size = (addrbits == 32) ? 16 : 32;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002482 } else {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002483 /* Impossible... */
2484 errfunc(ERR_NONFATAL, "impossible combination of address sizes");
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002485 ins->addr_size = addrbits; /* Error recovery */
2486 }
2487
2488 defdisp = ins->addr_size == 16 ? 16 : 32;
2489
2490 for (j = 0; j < ins->operands; j++) {
2491 if (!(MEM_OFFS & ~ins->oprs[j].type) &&
2492 (ins->oprs[j].disp_size ? ins->oprs[j].disp_size : defdisp)
2493 != ins->addr_size) {
2494 /* mem_offs sizes must match the address size; if not,
2495 strip the MEM_OFFS bit and match only EA instructions */
2496 ins->oprs[j].type &= ~(MEM_OFFS & ~MEMORY);
2497 }
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002498 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002499}