blob: 6adaec6abd19c92b645682f88a8a8285a345fd9d [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
5 * redistributable under the licence given in the file "Licence"
6 * 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 Anvinb061d592007-04-16 02:02:06 +000025 * depending on assembly mode or the address-size override
26 * on the operand.
H. Peter Anvin7eb4a382007-09-17 15:49:30 -070027 * \50..\53 - a byte relative operand, from operand 0..3
28 * \54..\57 - a qword immediate operand, from operand 0..3
29 * \60..\63 - a word relative operand, from operand 0..3
30 * \64..\67 - select between \6[0-3] and \7[0-3] depending on 16/32 bit
H. Peter Anvin17799b42002-05-21 03:31:21 +000031 * assembly mode or the operand-size override on the operand
H. Peter Anvin7eb4a382007-09-17 15:49:30 -070032 * \70..\73 - a long relative operand, from operand 0..3
33 * \74..\77 - a word constant, from the _segment_ part of operand 0..3
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000034 * \1ab - a ModRM, calculated on EA in operand a, with the spare
35 * field the register value of operand b.
H. Peter Anvin7eb4a382007-09-17 15:49:30 -070036 * \140..\143 - an immediate word or signed byte for operand 0..3
37 * \144..\147 - or 2 (s-field) into next opcode byte if operand 0..3
H. Peter Anvinaf535c12002-04-30 20:59:21 +000038 * is a signed byte rather than a word.
H. Peter Anvin7eb4a382007-09-17 15:49:30 -070039 * \150..\153 - an immediate dword or signed byte for operand 0..3
40 * \154..\157 - or 2 (s-field) into next opcode byte if operand 0..3
H. Peter Anvinaf535c12002-04-30 20:59:21 +000041 * is a signed byte rather than a dword.
H. Peter Anvin401c07e2007-09-17 16:55:04 -070042 * \160..\163 - this instruction uses DREX rather than REX, with the
43 * OC0 field set to 0, and the dest field taken from
44 * operand 0..3.
45 * \164..\167 - this instruction uses DREX rather than REX, with the
46 * OC0 field set to 1, and the dest field taken from
47 * operand 0..3.
H. Peter Anvin7eb4a382007-09-17 15:49:30 -070048 * \170 - encodes the literal byte 0. (Some compilers don't take
49 * kindly to a zero byte in the _middle_ of a compile time
50 * string constant, so I had to put this hack in.)
H. Peter Anvin401c07e2007-09-17 16:55:04 -070051 * \171 - placement of DREX suffix in the absence of an EA
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 Anvinea6e34d2002-04-30 20:51:32 +000054 * \310 - indicates fixed 16-bit address size, i.e. optional 0x67.
55 * \311 - indicates fixed 32-bit address size, i.e. optional 0x67.
Keith Kanios48af1772007-08-17 07:37:52 +000056 * \312 - (disassembler only) marker on LOOP, LOOPxx instructions.
H. Peter Anvince2b3972007-05-30 22:21:11 +000057 * \313 - indicates fixed 64-bit address size, 0x67 invalid.
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000058 * \320 - indicates fixed 16-bit operand size, i.e. optional 0x66.
59 * \321 - indicates fixed 32-bit operand size, i.e. optional 0x66.
60 * \322 - indicates that this instruction is only valid when the
61 * operand size is the default (instruction to disassembler,
62 * generates no code in the assembler)
H. Peter Anvince2b3972007-05-30 22:21:11 +000063 * \323 - indicates fixed 64-bit operand size, REX on extensions only.
Keith Kaniosb7a89542007-04-12 02:40:54 +000064 * \324 - indicates 64-bit operand size requiring REX prefix.
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000065 * \330 - a literal byte follows in the code stream, to be added
66 * to the condition code value of the instruction.
Keith Kanios48af1772007-08-17 07:37:52 +000067 * \331 - instruction not valid with REP prefix. Hint for
H. Peter Anvinef7468f2002-04-30 20:57:59 +000068 * disassembler only; for SSE instructions.
H. Peter Anvincb9b6902007-09-12 21:58:51 -070069 * \332 - REP prefix (0xF2 byte) used as opcode extension.
70 * \333 - REP prefix (0xF3 byte) used as opcode extension.
Keith Kanios48af1772007-08-17 07:37:52 +000071 * \334 - LOCK prefix used instead of REX.R
H. Peter Anvincb9b6902007-09-12 21:58:51 -070072 * \335 - disassemble a rep (0xF3 byte) prefix as repe not rep.
Keith Kaniosb7a89542007-04-12 02:40:54 +000073 * \340 - reserve <operand 0> bytes of uninitialized storage.
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000074 * Operand 0 had better be a segmentless constant.
H. Peter Anvin62cb6062007-09-11 22:44:03 +000075 * \364 - operand-size prefix (0x66) not permitted
76 * \365 - address-size prefix (0x67) not permitted
77 * \366 - operand-size prefix (0x66) used as opcode extension
78 * \367 - address-size prefix (0x67) used as opcode extension
H. Peter Anvin788e6c12002-04-30 21:02:01 +000079 * \370,\371,\372 - match only if operand 0 meets byte jump criteria.
80 * 370 is used for Jcc, 371 is used for JMP.
H. Peter Anvinaf535c12002-04-30 20:59:21 +000081 * \373 - assemble 0x03 if bits==16, 0x05 if bits==32;
82 * used for conditional jump over longer jump
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000083 */
84
85#include <stdio.h>
86#include <string.h>
Keith Kaniosb7a89542007-04-12 02:40:54 +000087#include <inttypes.h>
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000088
89#include "nasm.h"
H. Peter Anvin6768eb72002-04-30 20:52:26 +000090#include "nasmlib.h"
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000091#include "assemble.h"
92#include "insns.h"
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +000093#include "preproc.h"
H. Peter Anvin3df97a72007-05-30 03:25:21 +000094#include "regflags.c"
Keith Kaniosb7a89542007-04-12 02:40:54 +000095#include "regvals.c"
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000096
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000097typedef struct {
Keith Kaniosb7a89542007-04-12 02:40:54 +000098 int sib_present; /* is a SIB byte necessary? */
99 int bytes; /* # of bytes of offset needed */
100 int size; /* lazy - this is sib+bytes+1 */
101 uint8_t modrm, sib, rex, rip; /* the bytes themselves */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000102} ea;
103
Keith Kaniosb7a89542007-04-12 02:40:54 +0000104static uint32_t cpu; /* cpu level received from nasm.c */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000105static efunc errfunc;
106static struct ofmt *outfmt;
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000107static ListGen *list;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000108
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000109static int32_t calcsize(int32_t, int32_t, int, insn *, const char *);
110static void gencode(int32_t, int32_t, int, insn *, const char *, int32_t);
H. Peter Anvin3360d792007-09-11 04:16:57 +0000111static int matches(const struct itemplate *, insn *, int bits);
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000112static int32_t regflag(const operand *);
113static int32_t regval(const operand *);
114static int rexflags(int, int32_t, int);
115static int op_rexflags(const operand *, int);
H. Peter Anvin5b0e3ec2007-07-07 02:01:08 +0000116static ea *process_ea(operand *, ea *, int, int, int32_t, int);
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700117static void add_asp(insn *, int);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000118
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700119static int has_prefix(insn * ins, enum prefixes prefix)
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000120{
121 int j;
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000122 for (j = 0; j < ins->nprefix; j++) {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700123 if (ins->prefixes[j] == prefix)
124 return 1;
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000125 }
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700126 return 0;
127}
128
129static void assert_no_prefix(insn * ins, enum prefixes prefix)
130{
131 if (has_prefix(ins, prefix))
132 errfunc(ERR_NONFATAL, "invalid %s prefix", prefix_name(prefix));
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000133}
134
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000135/*
136 * This routine wrappers the real output format's output routine,
137 * in order to pass a copy of the data off to the listing file
138 * generator at the same time.
139 */
Keith Kaniosb7a89542007-04-12 02:40:54 +0000140static void out(int32_t offset, int32_t segto, const void *data,
141 uint32_t type, int32_t segment, int32_t wrt)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000142{
Keith Kaniosb7a89542007-04-12 02:40:54 +0000143 static int32_t lineno = 0; /* static!!! */
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000144 static char *lnfname = NULL;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000145
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000146 if ((type & OUT_TYPMASK) == OUT_ADDRESS) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000147 if (segment != NO_SEG || wrt != NO_SEG) {
148 /*
149 * This address is relocated. We must write it as
150 * OUT_ADDRESS, so there's no work to be done here.
151 */
152 list->output(offset, data, type);
153 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000154 uint8_t p[8], *q = p;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000155 /*
156 * This is a non-relocated address, and we're going to
157 * convert it into RAWDATA format.
158 */
159 if ((type & OUT_SIZMASK) == 4) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000160 WRITELONG(q, *(int32_t *)data);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000161 list->output(offset, p, OUT_RAWDATA + 4);
Keith Kaniosb7a89542007-04-12 02:40:54 +0000162 } else if ((type & OUT_SIZMASK) == 8) {
163 WRITEDLONG(q, *(int64_t *)data);
164 list->output(offset, p, OUT_RAWDATA + 8);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000165 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000166 WRITESHORT(q, *(int32_t *)data);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000167 list->output(offset, p, OUT_RAWDATA + 2);
168 }
169 }
170 } else if ((type & OUT_TYPMASK) == OUT_RAWDATA) {
171 list->output(offset, data, type);
172 } else if ((type & OUT_TYPMASK) == OUT_RESERVE) {
173 list->output(offset, NULL, type);
174 } else if ((type & OUT_TYPMASK) == OUT_REL2ADR ||
175 (type & OUT_TYPMASK) == OUT_REL4ADR) {
176 list->output(offset, data, type);
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000177 }
178
Frank Kotlerabebb082003-09-06 04:45:37 +0000179 /*
180 * this call to src_get determines when we call the
181 * debug-format-specific "linenum" function
182 * it updates lineno and lnfname to the current values
183 * returning 0 if "same as last time", -2 if lnfname
184 * changed, and the amount by which lineno changed,
185 * if it did. thus, these variables must be static
186 */
187
H. Peter Anvine2c80182005-01-15 22:15:51 +0000188 if (src_get(&lineno, &lnfname)) {
189 outfmt->current_dfmt->linenum(lnfname, lineno, segto);
H. Peter Anvince616072002-04-30 21:02:23 +0000190 }
H. Peter Anvineba20a72002-04-30 20:53:55 +0000191
H. Peter Anvine2c80182005-01-15 22:15:51 +0000192 outfmt->output(segto, data, type, segment, wrt);
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000193}
194
Keith Kaniosb7a89542007-04-12 02:40:54 +0000195static int jmp_match(int32_t segment, int32_t offset, int bits,
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000196 insn * ins, const char *code)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000197{
Keith Kaniosb7a89542007-04-12 02:40:54 +0000198 int32_t isize;
199 uint8_t c = code[0];
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000200
H. Peter Anvine2c80182005-01-15 22:15:51 +0000201 if (c != 0370 && c != 0371)
202 return 0;
H. Peter Anvin788e6c12002-04-30 21:02:01 +0000203 if (ins->oprs[0].opflags & OPFLAG_FORWARD) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000204 if ((optimizing < 0 || (ins->oprs[0].type & STRICT))
205 && c == 0370)
206 return 1;
207 else
208 return (pass0 == 0); /* match a forward reference */
H. Peter Anvin788e6c12002-04-30 21:02:01 +0000209 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000210 isize = calcsize(segment, offset, bits, ins, code);
211 if (ins->oprs[0].segment != segment)
212 return 0;
213 isize = ins->oprs[0].offset - offset - isize; /* isize is now the delta */
214 if (isize >= -128L && isize <= 127L)
215 return 1; /* it is byte size */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000216
217 return 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000218}
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000219
Keith Kaniosb7a89542007-04-12 02:40:54 +0000220int32_t assemble(int32_t segment, int32_t offset, int bits, uint32_t cp,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000221 insn * instruction, struct ofmt *output, efunc error,
222 ListGen * listgen)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000223{
H. Peter Anvin3360d792007-09-11 04:16:57 +0000224 const struct itemplate *temp;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000225 int j;
226 int size_prob;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000227 int32_t insn_end;
228 int32_t itimes;
229 int32_t start = offset;
230 int32_t wsize = 0; /* size for DB etc. */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000231
H. Peter Anvine2c80182005-01-15 22:15:51 +0000232 errfunc = error; /* to pass to other functions */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000233 cpu = cp;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000234 outfmt = output; /* likewise */
235 list = listgen; /* and again */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000236
H. Peter Anvine2c80182005-01-15 22:15:51 +0000237 switch (instruction->opcode) {
238 case -1:
239 return 0;
240 case I_DB:
241 wsize = 1;
242 break;
243 case I_DW:
244 wsize = 2;
245 break;
246 case I_DD:
247 wsize = 4;
248 break;
249 case I_DQ:
250 wsize = 8;
251 break;
252 case I_DT:
253 wsize = 10;
254 break;
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700255 case I_DO:
256 wsize = 16;
257 break;
H. Peter Anvin16b0a332007-09-12 20:27:41 -0700258 default:
259 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000260 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000261
H. Peter Anvineba20a72002-04-30 20:53:55 +0000262 if (wsize) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000263 extop *e;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000264 int32_t t = instruction->times;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000265 if (t < 0)
266 errfunc(ERR_PANIC,
267 "instruction->times < 0 (%ld) in assemble()", t);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000268
H. Peter Anvine2c80182005-01-15 22:15:51 +0000269 while (t--) { /* repeat TIMES times */
270 for (e = instruction->eops; e; e = e->next) {
271 if (e->type == EOT_DB_NUMBER) {
272 if (wsize == 1) {
273 if (e->segment != NO_SEG)
274 errfunc(ERR_NONFATAL,
275 "one-byte relocation attempted");
276 else {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000277 uint8_t out_byte = e->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000278 out(offset, segment, &out_byte,
279 OUT_RAWDATA + 1, NO_SEG, NO_SEG);
280 }
Keith Kanios61ff53c2007-04-14 18:54:52 +0000281 } else if (wsize > 8) {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700282 errfunc(ERR_NONFATAL, "integer supplied to a DT or DO"
Keith Kanios61ff53c2007-04-14 18:54:52 +0000283 " instruction");
H. Peter Anvine2c80182005-01-15 22:15:51 +0000284 } else
285 out(offset, segment, &e->offset,
286 OUT_ADDRESS + wsize, e->segment, e->wrt);
287 offset += wsize;
288 } else if (e->type == EOT_DB_STRING) {
289 int align;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000290
H. Peter Anvine2c80182005-01-15 22:15:51 +0000291 out(offset, segment, e->stringval,
292 OUT_RAWDATA + e->stringlen, NO_SEG, NO_SEG);
293 align = e->stringlen % wsize;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000294
H. Peter Anvine2c80182005-01-15 22:15:51 +0000295 if (align) {
296 align = wsize - align;
297 out(offset, segment, "\0\0\0\0\0\0\0\0",
298 OUT_RAWDATA + align, NO_SEG, NO_SEG);
299 }
300 offset += e->stringlen + align;
301 }
302 }
303 if (t > 0 && t == instruction->times - 1) {
304 /*
305 * Dummy call to list->output to give the offset to the
306 * listing module.
307 */
308 list->output(offset, NULL, OUT_RAWDATA);
309 list->uplevel(LIST_TIMES);
310 }
311 }
312 if (instruction->times > 1)
313 list->downlevel(LIST_TIMES);
314 return offset - start;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000315 }
316
H. Peter Anvine2c80182005-01-15 22:15:51 +0000317 if (instruction->opcode == I_INCBIN) {
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000318 static char fname[FILENAME_MAX];
H. Peter Anvine2c80182005-01-15 22:15:51 +0000319 FILE *fp;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000320 int32_t len;
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000321 char *prefix = "", *combine;
322 char **pPrevPath = NULL;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000323
H. Peter Anvine2c80182005-01-15 22:15:51 +0000324 len = FILENAME_MAX - 1;
325 if (len > instruction->eops->stringlen)
326 len = instruction->eops->stringlen;
327 strncpy(fname, instruction->eops->stringval, len);
328 fname[len] = '\0';
H. Peter Anvineba20a72002-04-30 20:53:55 +0000329
Keith Kaniosb7a89542007-04-12 02:40:54 +0000330 while (1) { /* added by alexfru: 'incbin' uses include paths */
H. Peter Anvine2c80182005-01-15 22:15:51 +0000331 combine = nasm_malloc(strlen(prefix) + len + 1);
332 strcpy(combine, prefix);
333 strcat(combine, fname);
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000334
H. Peter Anvine2c80182005-01-15 22:15:51 +0000335 if ((fp = fopen(combine, "rb")) != NULL) {
336 nasm_free(combine);
337 break;
338 }
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000339
H. Peter Anvine2c80182005-01-15 22:15:51 +0000340 nasm_free(combine);
341 pPrevPath = pp_get_include_path_ptr(pPrevPath);
342 if (pPrevPath == NULL)
343 break;
344 prefix = *pPrevPath;
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000345 }
346
347 if (fp == NULL)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000348 error(ERR_NONFATAL, "`incbin': unable to open file `%s'",
349 fname);
350 else if (fseek(fp, 0L, SEEK_END) < 0)
351 error(ERR_NONFATAL, "`incbin': unable to seek on file `%s'",
352 fname);
353 else {
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000354 static char buf[2048];
Keith Kaniosb7a89542007-04-12 02:40:54 +0000355 int32_t t = instruction->times;
356 int32_t base = 0;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000357
H. Peter Anvine2c80182005-01-15 22:15:51 +0000358 len = ftell(fp);
359 if (instruction->eops->next) {
360 base = instruction->eops->next->offset;
361 len -= base;
362 if (instruction->eops->next->next &&
363 len > instruction->eops->next->next->offset)
364 len = instruction->eops->next->next->offset;
365 }
366 /*
367 * Dummy call to list->output to give the offset to the
368 * listing module.
369 */
370 list->output(offset, NULL, OUT_RAWDATA);
371 list->uplevel(LIST_INCBIN);
372 while (t--) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000373 int32_t l;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000374
H. Peter Anvine2c80182005-01-15 22:15:51 +0000375 fseek(fp, base, SEEK_SET);
376 l = len;
377 while (l > 0) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000378 int32_t m =
H. Peter Anvine2c80182005-01-15 22:15:51 +0000379 fread(buf, 1, (l > sizeof(buf) ? sizeof(buf) : l),
380 fp);
381 if (!m) {
382 /*
383 * This shouldn't happen unless the file
384 * actually changes while we are reading
385 * it.
386 */
387 error(ERR_NONFATAL,
388 "`incbin': unexpected EOF while"
389 " reading file `%s'", fname);
390 t = 0; /* Try to exit cleanly */
391 break;
392 }
393 out(offset, segment, buf, OUT_RAWDATA + m,
394 NO_SEG, NO_SEG);
395 l -= m;
396 }
397 }
398 list->downlevel(LIST_INCBIN);
399 if (instruction->times > 1) {
400 /*
401 * Dummy call to list->output to give the offset to the
402 * listing module.
403 */
404 list->output(offset, NULL, OUT_RAWDATA);
405 list->uplevel(LIST_TIMES);
406 list->downlevel(LIST_TIMES);
407 }
408 fclose(fp);
409 return instruction->times * len;
410 }
411 return 0; /* if we're here, there's an error */
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000412 }
413
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700414 /* Check to see if we need an address-size prefix */
415 add_asp(instruction, bits);
416
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000417 size_prob = FALSE;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000418
419 for (temp = nasm_instructions[instruction->opcode]; temp->opcode != -1; temp++){
420 int m = matches(temp, instruction, bits);
421
H. Peter Anvine2c80182005-01-15 22:15:51 +0000422 if (m == 99)
423 m += jmp_match(segment, offset, bits, instruction, temp->code);
H. Peter Anvineba20a72002-04-30 20:53:55 +0000424
H. Peter Anvine2c80182005-01-15 22:15:51 +0000425 if (m == 100) { /* matches! */
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000426 const char *codes = temp->code;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000427 int32_t insn_size = calcsize(segment, offset, bits,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000428 instruction, codes);
429 itimes = instruction->times;
430 if (insn_size < 0) /* shouldn't be, on pass two */
431 error(ERR_PANIC, "errors made it through from pass one");
432 else
433 while (itimes--) {
434 for (j = 0; j < instruction->nprefix; j++) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000435 uint8_t c = 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000436 switch (instruction->prefixes[j]) {
437 case P_LOCK:
438 c = 0xF0;
439 break;
440 case P_REPNE:
441 case P_REPNZ:
442 c = 0xF2;
443 break;
444 case P_REPE:
445 case P_REPZ:
446 case P_REP:
447 c = 0xF3;
448 break;
449 case R_CS:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000450 if (bits == 64) {
451 error(ERR_WARNING,
452 "cs segment base ignored in 64-bit mode");
453 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000454 c = 0x2E;
455 break;
456 case R_DS:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000457 if (bits == 64) {
458 error(ERR_WARNING,
459 "ds segment base ignored in 64-bit mode");
460 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000461 c = 0x3E;
462 break;
463 case R_ES:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000464 if (bits == 64) {
465 error(ERR_WARNING,
466 "es segment base ignored in 64-bit mode");
467 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000468 c = 0x26;
469 break;
470 case R_FS:
471 c = 0x64;
472 break;
473 case R_GS:
474 c = 0x65;
475 break;
476 case R_SS:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000477 if (bits == 64) {
478 error(ERR_WARNING,
479 "ss segment base ignored in 64-bit mode");
480 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000481 c = 0x36;
482 break;
483 case R_SEGR6:
484 case R_SEGR7:
485 error(ERR_NONFATAL,
486 "segr6 and segr7 cannot be used as prefixes");
487 break;
488 case P_A16:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000489 if (bits == 64) {
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000490 error(ERR_NONFATAL,
491 "16-bit addressing is not supported "
492 "in 64-bit mode");
Keith Kaniosb7a89542007-04-12 02:40:54 +0000493 break;
494 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000495 if (bits != 16)
496 c = 0x67;
497 break;
498 case P_A32:
499 if (bits != 32)
500 c = 0x67;
501 break;
502 case P_O16:
503 if (bits != 16)
504 c = 0x66;
505 break;
506 case P_O32:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000507 if (bits == 16)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000508 c = 0x66;
509 break;
510 default:
511 error(ERR_PANIC, "invalid instruction prefix");
512 }
513 if (c != 0) {
514 out(offset, segment, &c, OUT_RAWDATA + 1,
515 NO_SEG, NO_SEG);
516 offset++;
517 }
Keith Kaniosb7a89542007-04-12 02:40:54 +0000518 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000519 insn_end = offset + insn_size;
520 gencode(segment, offset, bits, instruction, codes,
521 insn_end);
522 offset += insn_size;
523 if (itimes > 0 && itimes == instruction->times - 1) {
524 /*
525 * Dummy call to list->output to give the offset to the
526 * listing module.
527 */
528 list->output(offset, NULL, OUT_RAWDATA);
529 list->uplevel(LIST_TIMES);
530 }
531 }
532 if (instruction->times > 1)
533 list->downlevel(LIST_TIMES);
534 return offset - start;
535 } else if (m > 0 && m > size_prob) {
536 size_prob = m;
537 }
Keith Kaniosb7a89542007-04-12 02:40:54 +0000538// temp++;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000539 }
H. Peter Anvineba20a72002-04-30 20:53:55 +0000540
H. Peter Anvine2c80182005-01-15 22:15:51 +0000541 if (temp->opcode == -1) { /* didn't match any instruction */
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000542 switch (size_prob) {
543 case 1:
544 error(ERR_NONFATAL, "operation size not specified");
545 break;
546 case 2:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000547 error(ERR_NONFATAL, "mismatch in operand sizes");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000548 break;
549 case 3:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000550 error(ERR_NONFATAL, "no instruction for this cpu level");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000551 break;
552 case 4:
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000553 error(ERR_NONFATAL, "instruction not supported in 64-bit mode");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000554 break;
555 default:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000556 error(ERR_NONFATAL,
557 "invalid combination of opcode and operands");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000558 break;
559 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000560 }
561 return 0;
562}
563
Keith Kaniosb7a89542007-04-12 02:40:54 +0000564int32_t insn_size(int32_t segment, int32_t offset, int bits, uint32_t cp,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000565 insn * instruction, efunc error)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000566{
H. Peter Anvin3360d792007-09-11 04:16:57 +0000567 const struct itemplate *temp;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000568
H. Peter Anvine2c80182005-01-15 22:15:51 +0000569 errfunc = error; /* to pass to other functions */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000570 cpu = cp;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000571
572 if (instruction->opcode == -1)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000573 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000574
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700575 if (instruction->opcode == I_DB || instruction->opcode == I_DW ||
576 instruction->opcode == I_DD || instruction->opcode == I_DQ ||
577 instruction->opcode == I_DT || instruction->opcode == I_DO) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000578 extop *e;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000579 int32_t isize, osize, wsize = 0; /* placate gcc */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000580
H. Peter Anvine2c80182005-01-15 22:15:51 +0000581 isize = 0;
582 switch (instruction->opcode) {
583 case I_DB:
584 wsize = 1;
585 break;
586 case I_DW:
587 wsize = 2;
588 break;
589 case I_DD:
590 wsize = 4;
591 break;
592 case I_DQ:
593 wsize = 8;
594 break;
595 case I_DT:
596 wsize = 10;
597 break;
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700598 case I_DO:
599 wsize = 16;
600 break;
H. Peter Anvin16b0a332007-09-12 20:27:41 -0700601 default:
602 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000603 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000604
H. Peter Anvine2c80182005-01-15 22:15:51 +0000605 for (e = instruction->eops; e; e = e->next) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000606 int32_t align;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000607
H. Peter Anvine2c80182005-01-15 22:15:51 +0000608 osize = 0;
609 if (e->type == EOT_DB_NUMBER)
610 osize = 1;
611 else if (e->type == EOT_DB_STRING)
612 osize = e->stringlen;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000613
H. Peter Anvine2c80182005-01-15 22:15:51 +0000614 align = (-osize) % wsize;
615 if (align < 0)
616 align += wsize;
617 isize += osize + align;
618 }
619 return isize * instruction->times;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000620 }
621
H. Peter Anvine2c80182005-01-15 22:15:51 +0000622 if (instruction->opcode == I_INCBIN) {
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000623 char fname[FILENAME_MAX];
H. Peter Anvine2c80182005-01-15 22:15:51 +0000624 FILE *fp;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000625 int32_t len;
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000626 char *prefix = "", *combine;
627 char **pPrevPath = NULL;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000628
H. Peter Anvine2c80182005-01-15 22:15:51 +0000629 len = FILENAME_MAX - 1;
630 if (len > instruction->eops->stringlen)
631 len = instruction->eops->stringlen;
632 strncpy(fname, instruction->eops->stringval, len);
633 fname[len] = '\0';
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000634
H. Peter Anvine2c80182005-01-15 22:15:51 +0000635 while (1) { /* added by alexfru: 'incbin' uses include paths */
636 combine = nasm_malloc(strlen(prefix) + len + 1);
637 strcpy(combine, prefix);
638 strcat(combine, fname);
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000639
H. Peter Anvine2c80182005-01-15 22:15:51 +0000640 if ((fp = fopen(combine, "rb")) != NULL) {
641 nasm_free(combine);
642 break;
643 }
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000644
H. Peter Anvine2c80182005-01-15 22:15:51 +0000645 nasm_free(combine);
646 pPrevPath = pp_get_include_path_ptr(pPrevPath);
647 if (pPrevPath == NULL)
648 break;
649 prefix = *pPrevPath;
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000650 }
651
652 if (fp == NULL)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000653 error(ERR_NONFATAL, "`incbin': unable to open file `%s'",
654 fname);
655 else if (fseek(fp, 0L, SEEK_END) < 0)
656 error(ERR_NONFATAL, "`incbin': unable to seek on file `%s'",
657 fname);
658 else {
659 len = ftell(fp);
660 fclose(fp);
661 if (instruction->eops->next) {
662 len -= instruction->eops->next->offset;
663 if (instruction->eops->next->next &&
664 len > instruction->eops->next->next->offset) {
665 len = instruction->eops->next->next->offset;
666 }
667 }
668 return instruction->times * len;
669 }
670 return 0; /* if we're here, there's an error */
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000671 }
672
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700673 /* Check to see if we need an address-size prefix */
674 add_asp(instruction, bits);
675
Keith Kaniosb7a89542007-04-12 02:40:54 +0000676 for (temp = nasm_instructions[instruction->opcode]; temp->opcode != -1; temp++) {
677 int m = matches(temp, instruction, bits);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000678 if (m == 99)
679 m += jmp_match(segment, offset, bits, instruction, temp->code);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000680
H. Peter Anvine2c80182005-01-15 22:15:51 +0000681 if (m == 100) {
682 /* we've matched an instruction. */
Keith Kaniosb7a89542007-04-12 02:40:54 +0000683 int32_t isize;
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000684 const char *codes = temp->code;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000685 int j;
686
687 isize = calcsize(segment, offset, bits, instruction, codes);
688 if (isize < 0)
689 return -1;
690 for (j = 0; j < instruction->nprefix; j++) {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700691 switch (instruction->prefixes[j]) {
692 case P_A16:
693 if (bits != 16)
694 isize++;
695 break;
696 case P_A32:
697 if (bits != 32)
698 isize++;
699 break;
700 case P_O16:
701 if (bits != 16)
702 isize++;
703 break;
704 case P_O32:
705 if (bits == 16)
706 isize++;
707 break;
708 default:
709 isize++;
710 break;
711 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000712 }
713 return isize * instruction->times;
714 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000715 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000716 return -1; /* didn't match any instruction */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000717}
718
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000719/* check that opn[op] is a signed byte of size 16 or 32,
720 and return the signed value*/
H. Peter Anvine2c80182005-01-15 22:15:51 +0000721static int is_sbyte(insn * ins, int op, int size)
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000722{
Keith Kaniosb7a89542007-04-12 02:40:54 +0000723 int32_t v;
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000724 int ret;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000725
726 ret = !(ins->forw_ref && ins->oprs[op].opflags) && /* dead in the water on forward reference or External */
727 optimizing >= 0 &&
728 !(ins->oprs[op].type & STRICT) &&
729 ins->oprs[op].wrt == NO_SEG && ins->oprs[op].segment == NO_SEG;
H. Peter Anvin734b1882002-04-30 21:01:08 +0000730
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000731 v = ins->oprs[op].offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000732 if (size == 16)
Keith Kaniosb7a89542007-04-12 02:40:54 +0000733 v = (int16_t)v; /* sign extend if 16 bits */
H. Peter Anvine2c80182005-01-15 22:15:51 +0000734
735 return ret && v >= -128L && v <= 127L;
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000736}
737
Keith Kaniosb7a89542007-04-12 02:40:54 +0000738static int32_t calcsize(int32_t segment, int32_t offset, int bits,
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000739 insn * ins, const char *codes)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000740{
Keith Kaniosb7a89542007-04-12 02:40:54 +0000741 int32_t length = 0;
742 uint8_t c;
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000743 int rex_mask = ~0;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +0000744 ins->rex = 0; /* Ensure REX is reset */
H. Peter Anvineba20a72002-04-30 20:53:55 +0000745
H. Peter Anvine2c80182005-01-15 22:15:51 +0000746 (void)segment; /* Don't warn that this parameter is unused */
747 (void)offset; /* Don't warn that this parameter is unused */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000748
H. Peter Anvine2c80182005-01-15 22:15:51 +0000749 while (*codes)
750 switch (c = *codes++) {
751 case 01:
752 case 02:
753 case 03:
754 codes += c, length += c;
755 break;
756 case 04:
757 case 05:
758 case 06:
759 case 07:
760 length++;
761 break;
762 case 010:
763 case 011:
764 case 012:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700765 case 013:
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000766 ins->rex |=
767 op_rexflags(&ins->oprs[c - 010], REX_B|REX_H|REX_P|REX_W);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000768 codes++, length++;
769 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000770 case 014:
771 case 015:
772 case 016:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700773 case 017:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000774 length++;
775 break;
776 case 020:
777 case 021:
778 case 022:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700779 case 023:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000780 length++;
781 break;
782 case 024:
783 case 025:
784 case 026:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700785 case 027:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000786 length++;
787 break;
788 case 030:
789 case 031:
790 case 032:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700791 case 033:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000792 length += 2;
793 break;
794 case 034:
795 case 035:
796 case 036:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700797 case 037:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000798 if (ins->oprs[c - 034].type & (BITS16 | BITS32 | BITS64))
H. Peter Anvine2c80182005-01-15 22:15:51 +0000799 length += (ins->oprs[c - 034].type & BITS16) ? 2 : 4;
800 else
801 length += (bits == 16) ? 2 : 4;
802 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000803 case 040:
804 case 041:
805 case 042:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700806 case 043:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000807 length += 4;
808 break;
809 case 044:
810 case 045:
811 case 046:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700812 case 047:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000813 length += ((ins->oprs[c - 044].addr_size ?
Keith Kaniosb7a89542007-04-12 02:40:54 +0000814 ins->oprs[c - 044].addr_size : bits) >> 3);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000815 break;
816 case 050:
817 case 051:
818 case 052:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700819 case 053:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000820 length++;
821 break;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000822 case 054:
823 case 055:
824 case 056:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700825 case 057:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000826 length += 8; /* MOV reg64/imm */
827 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000828 case 060:
829 case 061:
830 case 062:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700831 case 063:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000832 length += 2;
833 break;
834 case 064:
835 case 065:
836 case 066:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700837 case 067:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000838 if (ins->oprs[c - 064].type & (BITS16 | BITS32 | BITS64))
H. Peter Anvine2c80182005-01-15 22:15:51 +0000839 length += (ins->oprs[c - 064].type & BITS16) ? 2 : 4;
840 else
841 length += (bits == 16) ? 2 : 4;
842 break;
843 case 070:
844 case 071:
845 case 072:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700846 case 073:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000847 length += 4;
848 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700849 case 074:
850 case 075:
851 case 076:
852 case 077:
853 length += 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000854 break;
855 case 0140:
856 case 0141:
857 case 0142:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700858 case 0143:
859 length += is_sbyte(ins, c - 0140, 16) ? 1 : 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000860 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000861 case 0144:
862 case 0145:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700863 case 0146:
864 case 0147:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000865 codes += 2;
866 length++;
867 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700868 case 0150:
869 case 0151:
870 case 0152:
871 case 0153:
872 length += is_sbyte(ins, c - 0150, 32) ? 1 : 4;
873 break;
874 case 0154:
875 case 0155:
876 case 0156:
877 case 0157:
878 codes += 2;
879 length++;
880 break;
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700881 case 0160:
882 case 0161:
883 case 0162:
884 case 0163:
885 length++;
886 ins->rex |= REX_D;
H. Peter Anvincf5180a2007-09-17 17:25:27 -0700887 ins->drexdst = regval(&ins->oprs[c & 3]);
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700888 break;
889 case 0164:
890 case 0165:
891 case 0166:
892 case 0167:
893 length++;
894 ins->rex |= REX_D|REX_OC;
H. Peter Anvincf5180a2007-09-17 17:25:27 -0700895 ins->drexdst = regval(&ins->oprs[c & 3]);
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700896 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700897 case 0170:
898 length++;
899 break;
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700900 case 0171:
901 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000902 case 0300:
903 case 0301:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000904 case 0302:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700905 case 0303:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000906 break;
907 case 0310:
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700908 if (bits == 64)
909 return -1;
910 length += (bits != 16) && !has_prefix(ins,P_A16);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000911 break;
912 case 0311:
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700913 length += (bits != 32) && !has_prefix(ins,P_A32);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000914 break;
915 case 0312:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000916 break;
917 case 0313:
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700918 if (bits != 64 || has_prefix(ins,P_A16) || has_prefix(ins,P_A32))
919 return -1;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000920 break;
921 case 0320:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000922 length += (bits != 16);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000923 break;
924 case 0321:
925 length += (bits == 16);
926 break;
927 case 0322:
928 break;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000929 case 0323:
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000930 rex_mask &= ~REX_W;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000931 break;
932 case 0324:
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000933 ins->rex |= REX_W;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +0000934 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000935 case 0330:
936 codes++, length++;
937 break;
938 case 0331:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000939 break;
H. Peter Anvincb9b6902007-09-12 21:58:51 -0700940 case 0332:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000941 case 0333:
942 length++;
943 break;
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000944 case 0334:
945 assert_no_prefix(ins, P_LOCK);
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000946 ins->rex |= REX_L;
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000947 break;
H. Peter Anvincb9b6902007-09-12 21:58:51 -0700948 case 0335:
949 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000950 case 0340:
951 case 0341:
952 case 0342:
953 if (ins->oprs[0].segment != NO_SEG)
954 errfunc(ERR_NONFATAL, "attempt to reserve non-constant"
955 " quantity of BSS space");
956 else
957 length += ins->oprs[0].offset << (c - 0340);
958 break;
H. Peter Anvin62cb6062007-09-11 22:44:03 +0000959 case 0364:
960 case 0365:
961 break;
Keith Kanios48af1772007-08-17 07:37:52 +0000962 case 0366:
H. Peter Anvin62cb6062007-09-11 22:44:03 +0000963 case 0367:
964 length++;
965 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000966 case 0370:
967 case 0371:
968 case 0372:
969 break;
970 case 0373:
971 length++;
972 break;
973 default: /* can't do it by 'case' statements */
974 if (c >= 0100 && c <= 0277) { /* it's an EA */
975 ea ea_data;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000976 int rfield;
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000977 int32_t rflags;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000978 ea_data.rex = 0; /* Ensure ea.REX is initially 0 */
979
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000980 if (c <= 0177) {
981 /* pick rfield from operand b */
982 rflags = regflag(&ins->oprs[c & 7]);
983 rfield = regvals[ins->oprs[c & 7].basereg];
984 } else {
985 rflags = 0;
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000986 rfield = c & 7;
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000987 }
Keith Kaniosb7a89542007-04-12 02:40:54 +0000988
H. Peter Anvine2c80182005-01-15 22:15:51 +0000989 if (!process_ea
Keith Kaniosb7a89542007-04-12 02:40:54 +0000990 (&ins->oprs[(c >> 3) & 7], &ea_data, bits,
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000991 rfield, rflags, ins->forw_ref)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000992 errfunc(ERR_NONFATAL, "invalid effective address");
993 return -1;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000994 } else {
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000995 ins->rex |= ea_data.rex;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000996 length += ea_data.size;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000997 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000998 } else
999 errfunc(ERR_PANIC, "internal instruction table corrupt"
1000 ": instruction code 0x%02X given", c);
1001 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001002
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001003 ins->rex &= rex_mask;
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001004
1005 if (ins->rex & REX_D) {
1006 if (ins->rex & REX_H) {
1007 errfunc(ERR_NONFATAL, "cannot use high register in drex instruction");
1008 return -1;
1009 }
H. Peter Anvincf5180a2007-09-17 17:25:27 -07001010 if (bits != 64 && ((ins->rex & (REX_W|REX_X|REX_B)) ||
1011 ins->drexdst > 7)) {
1012 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1013 return -1;
1014 }
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001015 length++;
1016 } else if (ins->rex & REX_REAL) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001017 if (ins->rex & REX_H) {
1018 errfunc(ERR_NONFATAL, "cannot use high register in rex instruction");
1019 return -1;
1020 } else if (bits == 64 ||
1021 ((ins->rex & REX_L) &&
1022 !(ins->rex & (REX_P|REX_W|REX_X|REX_B)) &&
1023 cpu >= IF_X86_64)) {
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001024 length++;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001025 } else {
H. Peter Anvincf5180a2007-09-17 17:25:27 -07001026 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1027 return -1;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001028 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00001029 }
1030
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001031 return length;
1032}
Keith Kaniosb7a89542007-04-12 02:40:54 +00001033
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001034#define EMIT_REX() \
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001035 if (!(ins->rex & REX_D) && (ins->rex & REX_REAL) && (bits == 64)) { \
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001036 ins->rex = (ins->rex & REX_REAL)|REX_P; \
1037 out(offset, segment, &ins->rex, OUT_RAWDATA+1, NO_SEG, NO_SEG); \
1038 ins->rex = 0; \
1039 offset += 1; \
1040 }
1041
Keith Kaniosb7a89542007-04-12 02:40:54 +00001042static void gencode(int32_t segment, int32_t offset, int bits,
Keith Kaniosa6dfa782007-04-13 16:47:53 +00001043 insn * ins, const char *codes, int32_t insn_end)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001044{
Keith Kaniosa6dfa782007-04-13 16:47:53 +00001045 static char condval[] = { /* conditional opcodes */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001046 0x7, 0x3, 0x2, 0x6, 0x2, 0x4, 0xF, 0xD, 0xC, 0xE, 0x6, 0x2,
1047 0x3, 0x7, 0x3, 0x5, 0xE, 0xC, 0xD, 0xF, 0x1, 0xB, 0x9, 0x5,
1048 0x0, 0xA, 0xA, 0xB, 0x8, 0x4
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001049 };
Keith Kaniosb7a89542007-04-12 02:40:54 +00001050 uint8_t c;
1051 uint8_t bytes[4];
1052 int32_t size;
1053 int64_t data;
1054
H. Peter Anvineba20a72002-04-30 20:53:55 +00001055 while (*codes)
H. Peter Anvine2c80182005-01-15 22:15:51 +00001056 switch (c = *codes++) {
1057 case 01:
1058 case 02:
1059 case 03:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001060 EMIT_REX();
H. Peter Anvine2c80182005-01-15 22:15:51 +00001061 out(offset, segment, codes, OUT_RAWDATA + c, NO_SEG, NO_SEG);
1062 codes += c;
1063 offset += c;
1064 break;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001065
H. Peter Anvine2c80182005-01-15 22:15:51 +00001066 case 04:
1067 case 06:
1068 switch (ins->oprs[0].basereg) {
1069 case R_CS:
1070 bytes[0] = 0x0E + (c == 0x04 ? 1 : 0);
1071 break;
1072 case R_DS:
1073 bytes[0] = 0x1E + (c == 0x04 ? 1 : 0);
1074 break;
1075 case R_ES:
1076 bytes[0] = 0x06 + (c == 0x04 ? 1 : 0);
1077 break;
1078 case R_SS:
1079 bytes[0] = 0x16 + (c == 0x04 ? 1 : 0);
1080 break;
1081 default:
1082 errfunc(ERR_PANIC,
1083 "bizarre 8086 segment register received");
1084 }
1085 out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG, NO_SEG);
1086 offset++;
1087 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001088
H. Peter Anvine2c80182005-01-15 22:15:51 +00001089 case 05:
1090 case 07:
1091 switch (ins->oprs[0].basereg) {
1092 case R_FS:
1093 bytes[0] = 0xA0 + (c == 0x05 ? 1 : 0);
1094 break;
1095 case R_GS:
1096 bytes[0] = 0xA8 + (c == 0x05 ? 1 : 0);
1097 break;
1098 default:
1099 errfunc(ERR_PANIC,
1100 "bizarre 386 segment register received");
1101 }
1102 out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG, NO_SEG);
1103 offset++;
1104 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001105
H. Peter Anvine2c80182005-01-15 22:15:51 +00001106 case 010:
1107 case 011:
1108 case 012:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001109 case 013:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001110 EMIT_REX();
Keith Kaniosb7a89542007-04-12 02:40:54 +00001111 bytes[0] = *codes++ + ((regval(&ins->oprs[c - 010])) & 7);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001112 out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG, NO_SEG);
1113 offset += 1;
1114 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001115
H. Peter Anvine2c80182005-01-15 22:15:51 +00001116 case 014:
1117 case 015:
1118 case 016:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001119 case 017:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001120 if (ins->oprs[c - 014].offset < -128
1121 || ins->oprs[c - 014].offset > 127) {
1122 errfunc(ERR_WARNING, "signed byte value exceeds bounds");
1123 }
H. Peter Anvineba20a72002-04-30 20:53:55 +00001124
H. Peter Anvine2c80182005-01-15 22:15:51 +00001125 if (ins->oprs[c - 014].segment != NO_SEG) {
1126 data = ins->oprs[c - 014].offset;
1127 out(offset, segment, &data, OUT_ADDRESS + 1,
1128 ins->oprs[c - 014].segment, ins->oprs[c - 014].wrt);
1129 } else {
1130 bytes[0] = ins->oprs[c - 014].offset;
1131 out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG,
1132 NO_SEG);
1133 }
1134 offset += 1;
1135 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001136
H. Peter Anvine2c80182005-01-15 22:15:51 +00001137 case 020:
1138 case 021:
1139 case 022:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001140 case 023:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001141 if (ins->oprs[c - 020].offset < -256
1142 || ins->oprs[c - 020].offset > 255) {
1143 errfunc(ERR_WARNING, "byte value exceeds bounds");
1144 }
1145 if (ins->oprs[c - 020].segment != NO_SEG) {
1146 data = ins->oprs[c - 020].offset;
1147 out(offset, segment, &data, OUT_ADDRESS + 1,
1148 ins->oprs[c - 020].segment, ins->oprs[c - 020].wrt);
1149 } else {
1150 bytes[0] = ins->oprs[c - 020].offset;
1151 out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG,
1152 NO_SEG);
1153 }
1154 offset += 1;
1155 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001156
H. Peter Anvine2c80182005-01-15 22:15:51 +00001157 case 024:
1158 case 025:
1159 case 026:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001160 case 027:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001161 if (ins->oprs[c - 024].offset < 0
1162 || ins->oprs[c - 024].offset > 255)
1163 errfunc(ERR_WARNING, "unsigned byte value exceeds bounds");
1164 if (ins->oprs[c - 024].segment != NO_SEG) {
1165 data = ins->oprs[c - 024].offset;
1166 out(offset, segment, &data, OUT_ADDRESS + 1,
1167 ins->oprs[c - 024].segment, ins->oprs[c - 024].wrt);
1168 } else {
1169 bytes[0] = ins->oprs[c - 024].offset;
1170 out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG,
1171 NO_SEG);
1172 }
1173 offset += 1;
1174 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001175
H. Peter Anvine2c80182005-01-15 22:15:51 +00001176 case 030:
1177 case 031:
1178 case 032:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001179 case 033:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001180 if (ins->oprs[c - 030].segment == NO_SEG &&
1181 ins->oprs[c - 030].wrt == NO_SEG &&
1182 (ins->oprs[c - 030].offset < -65536L ||
1183 ins->oprs[c - 030].offset > 65535L)) {
1184 errfunc(ERR_WARNING, "word value exceeds bounds");
1185 }
1186 data = ins->oprs[c - 030].offset;
1187 out(offset, segment, &data, OUT_ADDRESS + 2,
1188 ins->oprs[c - 030].segment, ins->oprs[c - 030].wrt);
1189 offset += 2;
1190 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001191
H. Peter Anvine2c80182005-01-15 22:15:51 +00001192 case 034:
1193 case 035:
1194 case 036:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001195 case 037:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001196 if (ins->oprs[c - 034].type & (BITS16 | BITS32))
1197 size = (ins->oprs[c - 034].type & BITS16) ? 2 : 4;
1198 else
1199 size = (bits == 16) ? 2 : 4;
1200 data = ins->oprs[c - 034].offset;
1201 if (size == 2 && (data < -65536L || data > 65535L))
1202 errfunc(ERR_WARNING, "word value exceeds bounds");
1203 out(offset, segment, &data, OUT_ADDRESS + size,
1204 ins->oprs[c - 034].segment, ins->oprs[c - 034].wrt);
1205 offset += size;
1206 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001207
H. Peter Anvine2c80182005-01-15 22:15:51 +00001208 case 040:
1209 case 041:
1210 case 042:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001211 case 043:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001212 data = ins->oprs[c - 040].offset;
1213 out(offset, segment, &data, OUT_ADDRESS + 4,
1214 ins->oprs[c - 040].segment, ins->oprs[c - 040].wrt);
1215 offset += 4;
1216 break;
H. Peter Anvin3ba46772002-05-27 23:19:35 +00001217
H. Peter Anvine2c80182005-01-15 22:15:51 +00001218 case 044:
1219 case 045:
1220 case 046:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001221 case 047:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001222 data = ins->oprs[c - 044].offset;
1223 size = ((ins->oprs[c - 044].addr_size ?
Keith Kaniosb7a89542007-04-12 02:40:54 +00001224 ins->oprs[c - 044].addr_size : bits) >> 3);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001225 if (size == 2 && (data < -65536L || data > 65535L))
1226 errfunc(ERR_WARNING, "word value exceeds bounds");
1227 out(offset, segment, &data, OUT_ADDRESS + size,
1228 ins->oprs[c - 044].segment, ins->oprs[c - 044].wrt);
1229 offset += size;
1230 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001231
H. Peter Anvine2c80182005-01-15 22:15:51 +00001232 case 050:
1233 case 051:
1234 case 052:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001235 case 053:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001236 if (ins->oprs[c - 050].segment != segment)
1237 errfunc(ERR_NONFATAL,
1238 "short relative jump outside segment");
1239 data = ins->oprs[c - 050].offset - insn_end;
1240 if (data > 127 || data < -128)
1241 errfunc(ERR_NONFATAL, "short jump is out of range");
1242 bytes[0] = data;
1243 out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG, NO_SEG);
1244 offset += 1;
1245 break;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001246
1247 case 054:
1248 case 055:
1249 case 056:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001250 case 057:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001251 data = (int64_t)ins->oprs[c - 054].offset;
1252 out(offset, segment, &data, OUT_ADDRESS + 8,
1253 ins->oprs[c - 054].segment, ins->oprs[c - 054].wrt);
1254 offset += 8;
1255 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001256
H. Peter Anvine2c80182005-01-15 22:15:51 +00001257 case 060:
1258 case 061:
1259 case 062:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001260 case 063:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001261 if (ins->oprs[c - 060].segment != segment) {
1262 data = ins->oprs[c - 060].offset;
1263 out(offset, segment, &data,
1264 OUT_REL2ADR + insn_end - offset,
1265 ins->oprs[c - 060].segment, ins->oprs[c - 060].wrt);
1266 } else {
1267 data = ins->oprs[c - 060].offset - insn_end;
1268 out(offset, segment, &data,
1269 OUT_ADDRESS + 2, NO_SEG, NO_SEG);
1270 }
1271 offset += 2;
1272 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001273
H. Peter Anvine2c80182005-01-15 22:15:51 +00001274 case 064:
1275 case 065:
1276 case 066:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001277 case 067:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001278 if (ins->oprs[c - 064].type & (BITS16 | BITS32 | BITS64))
H. Peter Anvine2c80182005-01-15 22:15:51 +00001279 size = (ins->oprs[c - 064].type & BITS16) ? 2 : 4;
1280 else
1281 size = (bits == 16) ? 2 : 4;
1282 if (ins->oprs[c - 064].segment != segment) {
Keith Kaniosb7a89542007-04-12 02:40:54 +00001283 int32_t reltype = (size == 2 ? OUT_REL2ADR : OUT_REL4ADR);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001284 data = ins->oprs[c - 064].offset;
1285 out(offset, segment, &data, reltype + insn_end - offset,
1286 ins->oprs[c - 064].segment, ins->oprs[c - 064].wrt);
1287 } else {
1288 data = ins->oprs[c - 064].offset - insn_end;
1289 out(offset, segment, &data,
1290 OUT_ADDRESS + size, NO_SEG, NO_SEG);
1291 }
1292 offset += size;
1293 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001294
H. Peter Anvine2c80182005-01-15 22:15:51 +00001295 case 070:
1296 case 071:
1297 case 072:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001298 case 073:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001299 if (ins->oprs[c - 070].segment != segment) {
1300 data = ins->oprs[c - 070].offset;
1301 out(offset, segment, &data,
1302 OUT_REL4ADR + insn_end - offset,
1303 ins->oprs[c - 070].segment, ins->oprs[c - 070].wrt);
1304 } else {
1305 data = ins->oprs[c - 070].offset - insn_end;
1306 out(offset, segment, &data,
1307 OUT_ADDRESS + 4, NO_SEG, NO_SEG);
1308 }
1309 offset += 4;
1310 break;
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001311
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001312 case 074:
1313 case 075:
1314 case 076:
1315 case 077:
1316 if (ins->oprs[c - 074].segment == NO_SEG)
1317 errfunc(ERR_NONFATAL, "value referenced by FAR is not"
1318 " relocatable");
1319 data = 0L;
1320 out(offset, segment, &data, OUT_ADDRESS + 2,
1321 outfmt->segbase(1 + ins->oprs[c - 074].segment),
1322 ins->oprs[c - 074].wrt);
1323 offset += 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001324 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001325
H. Peter Anvine2c80182005-01-15 22:15:51 +00001326 case 0140:
1327 case 0141:
1328 case 0142:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001329 case 0143:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001330 data = ins->oprs[c - 0140].offset;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001331 if (is_sbyte(ins, c - 0140, 16)) {
1332 bytes[0] = data;
1333 out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG,
1334 NO_SEG);
1335 offset++;
1336 } else {
1337 if (ins->oprs[c - 0140].segment == NO_SEG &&
1338 ins->oprs[c - 0140].wrt == NO_SEG &&
1339 (data < -65536L || data > 65535L)) {
1340 errfunc(ERR_WARNING, "word value exceeds bounds");
1341 }
1342 out(offset, segment, &data, OUT_ADDRESS + 2,
H. Peter Anvin8f94f982007-09-17 16:31:33 -07001343 ins->oprs[c - 0140].segment, ins->oprs[c - 0140].wrt);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001344 offset += 2;
1345 }
1346 break;
1347
1348 case 0144:
1349 case 0145:
1350 case 0146:
1351 case 0147:
1352 EMIT_REX();
1353 codes++;
1354 bytes[0] = *codes++;
1355 if (is_sbyte(ins, c - 0144, 16))
1356 bytes[0] |= 2; /* s-bit */
1357 out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG, NO_SEG);
1358 offset++;
1359 break;
1360
1361 case 0150:
1362 case 0151:
1363 case 0152:
1364 case 0153:
1365 data = ins->oprs[c - 0150].offset;
1366 if (is_sbyte(ins, c - 0150, 32)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001367 bytes[0] = data;
1368 out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG,
1369 NO_SEG);
1370 offset++;
1371 } else {
1372 out(offset, segment, &data, OUT_ADDRESS + 4,
H. Peter Anvin8f94f982007-09-17 16:31:33 -07001373 ins->oprs[c - 0150].segment, ins->oprs[c - 0150].wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001374 offset += 4;
1375 }
1376 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001377
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001378 case 0154:
1379 case 0155:
1380 case 0156:
1381 case 0157:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001382 EMIT_REX();
H. Peter Anvine2c80182005-01-15 22:15:51 +00001383 codes++;
1384 bytes[0] = *codes++;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001385 if (is_sbyte(ins, c - 0154, 32))
H. Peter Anvine2c80182005-01-15 22:15:51 +00001386 bytes[0] |= 2; /* s-bit */
1387 out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG, NO_SEG);
1388 offset++;
1389 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001390
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001391 case 0160:
1392 case 0161:
1393 case 0162:
1394 case 0163:
1395 case 0164:
1396 case 0165:
1397 case 0166:
1398 case 0167:
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001399 break;
1400
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001401 case 0170:
1402 bytes[0] = 0;
1403 out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG, NO_SEG);
1404 offset += 1;
1405 break;
1406
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001407 case 0171:
1408 bytes[0] =
1409 (ins->drexdst << 4) |
1410 (ins->rex & REX_OC ? 0x08 : 0) |
1411 (ins->rex & (REX_R|REX_X|REX_B));
1412 ins->rex = 0;
1413 out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG, NO_SEG);
1414 offset++;
1415 break;
1416
H. Peter Anvine2c80182005-01-15 22:15:51 +00001417 case 0300:
1418 case 0301:
1419 case 0302:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001420 case 0303:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001421 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001422
H. Peter Anvine2c80182005-01-15 22:15:51 +00001423 case 0310:
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07001424 if (bits == 32 && !has_prefix(ins,P_A16)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001425 *bytes = 0x67;
1426 out(offset, segment, bytes,
1427 OUT_RAWDATA + 1, NO_SEG, NO_SEG);
1428 offset += 1;
1429 } else
1430 offset += 0;
1431 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001432
H. Peter Anvine2c80182005-01-15 22:15:51 +00001433 case 0311:
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07001434 if (bits != 32 && !has_prefix(ins,P_A32)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001435 *bytes = 0x67;
1436 out(offset, segment, bytes,
1437 OUT_RAWDATA + 1, NO_SEG, NO_SEG);
1438 offset += 1;
1439 } else
1440 offset += 0;
1441 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001442
H. Peter Anvine2c80182005-01-15 22:15:51 +00001443 case 0312:
1444 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001445
Keith Kaniosb7a89542007-04-12 02:40:54 +00001446 case 0313:
1447 ins->rex = 0;
1448 break;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07001449
H. Peter Anvine2c80182005-01-15 22:15:51 +00001450 case 0320:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001451 if (bits != 16) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001452 *bytes = 0x66;
1453 out(offset, segment, bytes,
1454 OUT_RAWDATA + 1, NO_SEG, NO_SEG);
1455 offset += 1;
1456 } else
1457 offset += 0;
1458 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001459
H. Peter Anvine2c80182005-01-15 22:15:51 +00001460 case 0321:
1461 if (bits == 16) {
1462 *bytes = 0x66;
1463 out(offset, segment, bytes,
1464 OUT_RAWDATA + 1, NO_SEG, NO_SEG);
1465 offset += 1;
1466 } else
1467 offset += 0;
1468 break;
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001469
H. Peter Anvine2c80182005-01-15 22:15:51 +00001470 case 0322:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001471 case 0323:
1472 break;
1473
1474 case 0324:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001475 ins->rex |= REX_W;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001476 break;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001477
H. Peter Anvine2c80182005-01-15 22:15:51 +00001478 case 0330:
1479 *bytes = *codes++ ^ condval[ins->condition];
1480 out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG, NO_SEG);
1481 offset += 1;
1482 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001483
H. Peter Anvine2c80182005-01-15 22:15:51 +00001484 case 0331:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001485 break;
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001486
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001487 case 0332:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001488 case 0333:
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001489 *bytes = c - 0332 + 0xF2;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001490 out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG, NO_SEG);
1491 offset += 1;
1492 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001493
Keith Kanios48af1772007-08-17 07:37:52 +00001494 case 0334:
1495 if (ins->rex & REX_R) {
1496 *bytes = 0xF0;
1497 out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG, NO_SEG);
1498 offset += 1;
1499 }
1500 ins->rex &= ~(REX_L|REX_R);
1501 break;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001502
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001503 case 0335:
1504 break;
1505
H. Peter Anvine2c80182005-01-15 22:15:51 +00001506 case 0340:
1507 case 0341:
1508 case 0342:
1509 if (ins->oprs[0].segment != NO_SEG)
1510 errfunc(ERR_PANIC, "non-constant BSS size in pass two");
1511 else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00001512 int32_t size = ins->oprs[0].offset << (c - 0340);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001513 if (size > 0)
1514 out(offset, segment, NULL,
1515 OUT_RESERVE + size, NO_SEG, NO_SEG);
1516 offset += size;
1517 }
1518 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001519
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001520 case 0364:
1521 case 0365:
1522 break;
1523
Keith Kanios48af1772007-08-17 07:37:52 +00001524 case 0366:
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001525 case 0367:
1526 *bytes = c - 0366 + 0x66;
Keith Kanios48af1772007-08-17 07:37:52 +00001527 out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG, NO_SEG);
1528 offset += 1;
1529 break;
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001530
H. Peter Anvine2c80182005-01-15 22:15:51 +00001531 case 0370:
1532 case 0371:
1533 case 0372:
1534 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001535
H. Peter Anvine2c80182005-01-15 22:15:51 +00001536 case 0373:
1537 *bytes = bits == 16 ? 3 : 5;
1538 out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG, NO_SEG);
1539 offset += 1;
1540 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001541
H. Peter Anvine2c80182005-01-15 22:15:51 +00001542 default: /* can't do it by 'case' statements */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001543 if (c >= 0100 && c <= 0277) { /* it's an EA */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001544 ea ea_data;
1545 int rfield;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001546 int32_t rflags;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001547 uint8_t *p;
1548 int32_t s;
1549
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001550 if (c <= 0177) {
1551 /* pick rfield from operand b */
1552 rflags = regflag(&ins->oprs[c & 7]);
1553 rfield = regvals[ins->oprs[c & 7].basereg];
1554 } else {
1555 /* rfield is constant */
1556 rflags = 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001557 rfield = c & 7;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001558 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001559
1560 if (!process_ea
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001561 (&ins->oprs[(c >> 3) & 7], &ea_data, bits,
1562 rfield, rflags, ins->forw_ref)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001563 errfunc(ERR_NONFATAL, "invalid effective address");
1564 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00001565
H. Peter Anvine2c80182005-01-15 22:15:51 +00001566 p = bytes;
1567 *p++ = ea_data.modrm;
1568 if (ea_data.sib_present)
1569 *p++ = ea_data.sib;
1570
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001571 /* DREX suffixes come between the SIB and the displacement */
1572 if (ins->rex & REX_D) {
1573 *p++ =
1574 (ins->drexdst << 4) |
1575 (ins->rex & REX_OC ? 0x08 : 0) |
1576 (ins->rex & (REX_R|REX_X|REX_B));
1577 ins->rex = 0;
1578 }
1579
H. Peter Anvine2c80182005-01-15 22:15:51 +00001580 s = p - bytes;
1581 out(offset, segment, bytes, OUT_RAWDATA + s,
1582 NO_SEG, NO_SEG);
1583
1584 switch (ea_data.bytes) {
1585 case 0:
1586 break;
1587 case 1:
1588 if (ins->oprs[(c >> 3) & 7].segment != NO_SEG) {
1589 data = ins->oprs[(c >> 3) & 7].offset;
1590 out(offset, segment, &data, OUT_ADDRESS + 1,
1591 ins->oprs[(c >> 3) & 7].segment,
1592 ins->oprs[(c >> 3) & 7].wrt);
1593 } else {
1594 *bytes = ins->oprs[(c >> 3) & 7].offset;
1595 out(offset, segment, bytes, OUT_RAWDATA + 1,
1596 NO_SEG, NO_SEG);
1597 }
1598 s++;
1599 break;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001600 case 8:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001601 case 2:
1602 case 4:
1603 data = ins->oprs[(c >> 3) & 7].offset;
H. Peter Anvind0b0d282007-09-28 17:17:20 -07001604 out(offset, segment, &data,
1605 (ea_data.rip ? OUT_REL4ADR : OUT_ADDRESS)
1606 + ea_data.bytes,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001607 ins->oprs[(c >> 3) & 7].segment,
1608 ins->oprs[(c >> 3) & 7].wrt);
1609 s += ea_data.bytes;
1610 break;
1611 }
1612 offset += s;
1613 } else
1614 errfunc(ERR_PANIC, "internal instruction table corrupt"
1615 ": instruction code 0x%02X given", c);
1616 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001617}
1618
H. Peter Anvin0ec60e62007-07-07 01:59:52 +00001619static int32_t regflag(const operand * o)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001620{
1621 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1622 errfunc(ERR_PANIC, "invalid operand passed to regflag()");
1623 }
1624 return reg_flags[o->basereg];
1625}
1626
H. Peter Anvin5b0e3ec2007-07-07 02:01:08 +00001627static int32_t regval(const operand * o)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001628{
H. Peter Anvine2c80182005-01-15 22:15:51 +00001629 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1630 errfunc(ERR_PANIC, "invalid operand passed to regval()");
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001631 }
H. Peter Anvin232badb2002-06-06 02:41:20 +00001632 return regvals[o->basereg];
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001633}
1634
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001635static int op_rexflags(const operand * o, int mask)
1636{
1637 int32_t flags;
1638 int val;
1639
1640 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1641 errfunc(ERR_PANIC, "invalid operand passed to op_rexflags()");
1642 }
1643
1644 flags = reg_flags[o->basereg];
1645 val = regvals[o->basereg];
1646
1647 return rexflags(val, flags, mask);
1648}
1649
1650static int rexflags(int val, int32_t flags, int mask)
1651{
1652 int rex = 0;
1653
1654 if (val >= 8)
1655 rex |= REX_B|REX_X|REX_R;
1656 if (flags & BITS64)
1657 rex |= REX_W;
1658 if (!(REG_HIGH & ~flags)) /* AH, CH, DH, BH */
1659 rex |= REX_H;
1660 else if (!(REG8 & ~flags) && val >= 4) /* SPL, BPL, SIL, DIL */
1661 rex |= REX_P;
1662
1663 return rex & mask;
1664}
1665
H. Peter Anvin3360d792007-09-11 04:16:57 +00001666static int matches(const struct itemplate *itemp, insn * instruction, int bits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001667{
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001668 int i, size[MAX_OPERANDS], asize, oprs, ret;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001669
1670 ret = 100;
1671
1672 /*
1673 * Check the opcode
1674 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001675 if (itemp->opcode != instruction->opcode)
1676 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001677
1678 /*
1679 * Count the operands
1680 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001681 if (itemp->operands != instruction->operands)
1682 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001683
1684 /*
1685 * Check that no spurious colons or TOs are present
1686 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001687 for (i = 0; i < itemp->operands; i++)
1688 if (instruction->oprs[i].type & ~itemp->opd[i] & (COLON | TO))
1689 return 0;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001690
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001691 /*
1692 * Check that the operand flags all match up
1693 */
H. Peter Anvin16b0a332007-09-12 20:27:41 -07001694 for (i = 0; i < itemp->operands; i++) {
H. Peter Anvincf5180a2007-09-17 17:25:27 -07001695 if (itemp->opd[i] & SAME_AS) {
1696 int j = itemp->opd[i] & ~SAME_AS;
1697 if (instruction->oprs[i].type != instruction->oprs[j].type ||
1698 instruction->oprs[i].basereg != instruction->oprs[j].basereg)
1699 return 0;
H. Peter Anvin457afd42007-09-25 15:41:19 -07001700 } else if (itemp->opd[i] & ~instruction->oprs[i].type ||
H. Peter Anvine2c80182005-01-15 22:15:51 +00001701 ((itemp->opd[i] & SIZE_MASK) &&
1702 ((itemp->opd[i] ^ instruction->oprs[i].type) & SIZE_MASK))) {
H. Peter Anvin5a640e12007-05-29 23:57:12 +00001703 if ((itemp->opd[i] & ~instruction->oprs[i].type & ~SIZE_MASK) ||
H. Peter Anvine2c80182005-01-15 22:15:51 +00001704 (instruction->oprs[i].type & SIZE_MASK))
1705 return 0;
1706 else
H. Peter Anvine2c80182005-01-15 22:15:51 +00001707 return 1;
1708 }
H. Peter Anvin16b0a332007-09-12 20:27:41 -07001709 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001710
1711 /*
1712 * Check operand sizes
1713 */
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001714 if (itemp->flags & IF_ARMASK) {
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001715 memset(size, 0, sizeof size);
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001716
H. Peter Anvine2c80182005-01-15 22:15:51 +00001717 switch (itemp->flags & IF_ARMASK) {
1718 case IF_AR0:
1719 i = 0;
1720 break;
1721 case IF_AR1:
1722 i = 1;
1723 break;
1724 case IF_AR2:
1725 i = 2;
1726 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001727 case IF_AR3:
1728 i = 3;
1729 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001730 default:
1731 break; /* Shouldn't happen */
1732 }
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001733 switch (itemp->flags & IF_SMASK) {
1734 case IF_SB:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001735 size[i] = BITS8;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001736 break;
1737 case IF_SW:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001738 size[i] = BITS16;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001739 break;
1740 case IF_SD:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001741 size[i] = BITS32;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001742 break;
1743 case IF_SQ:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001744 size[i] = BITS64;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001745 break;
H. Peter Anvin41c9f6f2007-09-18 13:01:32 -07001746 case IF_SO:
1747 size[i] = BITS128;
1748 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001749 default:
1750 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001751 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001752 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001753 asize = 0;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001754 switch (itemp->flags & IF_SMASK) {
1755 case IF_SB:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001756 asize = BITS8;
1757 oprs = itemp->operands;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001758 break;
1759 case IF_SW:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001760 asize = BITS16;
1761 oprs = itemp->operands;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001762 break;
1763 case IF_SD:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001764 asize = BITS32;
1765 oprs = itemp->operands;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001766 break;
1767 case IF_SQ:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001768 asize = BITS64;
1769 oprs = itemp->operands;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001770 break;
H. Peter Anvin41c9f6f2007-09-18 13:01:32 -07001771 case IF_SO:
1772 asize = BITS128;
1773 oprs = itemp->operands;
1774 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001775 default:
1776 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001777 }
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001778 for (i = 0; i < MAX_OPERANDS; i++)
1779 size[i] = asize;
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001780 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00001781
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001782 if (itemp->flags & (IF_SM | IF_SM2)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001783 oprs = (itemp->flags & IF_SM2 ? 2 : itemp->operands);
1784 asize = 0;
1785 for (i = 0; i < oprs; i++) {
1786 if ((asize = itemp->opd[i] & SIZE_MASK) != 0) {
1787 int j;
1788 for (j = 0; j < oprs; j++)
1789 size[j] = asize;
1790 break;
1791 }
1792 }
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001793 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001794 oprs = itemp->operands;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001795 }
1796
Keith Kaniosb7a89542007-04-12 02:40:54 +00001797 for (i = 0; i < itemp->operands; i++) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001798 if (!(itemp->opd[i] & SIZE_MASK) &&
1799 (instruction->oprs[i].type & SIZE_MASK & ~size[i]))
H. Peter Anvine2c80182005-01-15 22:15:51 +00001800 return 2;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001801 }
1802
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001803 /*
1804 * Check template is okay at the set cpu level
1805 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00001806 if (((itemp->flags & IF_PLEVEL) > cpu))
H. Peter Anvine2c80182005-01-15 22:15:51 +00001807 return 3;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001808
1809 /*
1810 * Check if instruction is available in long mode
1811 */
1812 if ((itemp->flags & IF_NOLONG) && (bits == 64))
1813 return 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001814
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001815 /*
1816 * Check if special handling needed for Jumps
1817 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00001818 if ((uint8_t)(itemp->code[0]) >= 0370)
H. Peter Anvine2c80182005-01-15 22:15:51 +00001819 return 99;
1820
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001821 return ret;
1822}
1823
H. Peter Anvine2c80182005-01-15 22:15:51 +00001824static ea *process_ea(operand * input, ea * output, int addrbits,
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001825 int rfield, int32_t rflags, int forw_ref)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001826{
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00001827 output->rip = FALSE;
1828
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001829 /* REX flags for the rfield operand */
1830 output->rex |= rexflags(rfield, rflags, REX_R|REX_P|REX_W|REX_H);
1831
Keith Kaniosb7a89542007-04-12 02:40:54 +00001832 if (!(REGISTER & ~input->type)) { /* register direct */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001833 int i;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001834 int32_t f;
1835
1836 if (input->basereg < EXPR_REG_START /* Verify as Register */
Keith Kaniosb7a89542007-04-12 02:40:54 +00001837 || input->basereg >= REG_ENUM_LIMIT)
H. Peter Anvine2c80182005-01-15 22:15:51 +00001838 return NULL;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001839 f = regflag(input);
Keith Kaniosb7a89542007-04-12 02:40:54 +00001840 i = regvals[input->basereg];
Keith Kaniosb7a89542007-04-12 02:40:54 +00001841
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001842 if (REG_EA & ~f)
1843 return NULL; /* Invalid EA register */
1844
1845 output->rex |= op_rexflags(input, REX_B|REX_P|REX_W|REX_H);
1846
Keith Kaniosb7a89542007-04-12 02:40:54 +00001847 output->sib_present = FALSE; /* no SIB necessary */
1848 output->bytes = 0; /* no offset necessary either */
1849 output->modrm = 0xC0 | ((rfield & 7) << 3) | (i & 7);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001850 } else { /* it's a memory reference */
1851 if (input->basereg == -1
1852 && (input->indexreg == -1 || input->scale == 0)) {
1853 /* it's a pure offset */
1854 if (input->addr_size)
1855 addrbits = input->addr_size;
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00001856
1857 if (globalbits == 64 && (~input->type & IP_REL)) {
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00001858 int scale, index, base;
1859 output->sib_present = TRUE;
1860 scale = 0;
1861 index = 4;
1862 base = 5;
1863 output->sib = (scale << 6) | (index << 3) | base;
1864 output->bytes = 4;
1865 output->modrm = 4 | ((rfield & 7) << 3);
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00001866 output->rip = FALSE;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00001867 } else {
1868 output->sib_present = FALSE;
1869 output->bytes = (addrbits != 16 ? 4 : 2);
1870 output->modrm = (addrbits != 16 ? 5 : 6) | ((rfield & 7) << 3);
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00001871 output->rip = globalbits == 64;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00001872 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001873 } else { /* it's an indirection */
1874 int i = input->indexreg, b = input->basereg, s = input->scale;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001875 int32_t o = input->offset, seg = input->segment;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001876 int hb = input->hintbase, ht = input->hinttype;
1877 int t;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001878 int it, bt;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001879 int32_t ix, bx; /* register flags */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001880
H. Peter Anvine2c80182005-01-15 22:15:51 +00001881 if (s == 0)
1882 i = -1; /* make this easy, at least */
Keith Kaniosb7a89542007-04-12 02:40:54 +00001883
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001884 if (i >= EXPR_REG_START && i < REG_ENUM_LIMIT) {
Keith Kaniosb7a89542007-04-12 02:40:54 +00001885 it = regvals[i];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001886 ix = reg_flags[i];
1887 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00001888 it = -1;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001889 ix = 0;
1890 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00001891
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001892 if (b != -1 && b >= EXPR_REG_START && b < REG_ENUM_LIMIT) {
Keith Kaniosb7a89542007-04-12 02:40:54 +00001893 bt = regvals[b];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001894 bx = reg_flags[b];
1895 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00001896 bt = -1;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001897 bx = 0;
1898 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00001899
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001900 /* check for a 32/64-bit memory reference... */
1901 if ((ix|bx) & (BITS32|BITS64)) {
Keith Kaniosb7a89542007-04-12 02:40:54 +00001902 /* it must be a 32/64-bit memory reference. Firstly we have
1903 * to check that all registers involved are type E/Rxx. */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001904 int32_t sok = BITS32|BITS64;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001905
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001906 if (it != -1) {
1907 if (!(REG64 & ~ix) || !(REG32 & ~ix))
1908 sok &= ix;
1909 else
1910 return NULL;
1911 }
1912
1913 if (bt != -1) {
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00001914 if (REG_GPR & ~bx)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001915 return NULL; /* Invalid register */
H. Peter Anvina57e8d42007-05-30 03:44:02 +00001916 if (~sok & bx & SIZE_MASK)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001917 return NULL; /* Invalid size */
1918 sok &= ~bx;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001919 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00001920
H. Peter Anvine2c80182005-01-15 22:15:51 +00001921 /* While we're here, ensure the user didn't specify WORD. */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001922 if (input->addr_size == 16 ||
1923 (input->addr_size == 32 && !(sok & BITS32)) ||
1924 (input->addr_size == 64 && !(sok & BITS64)))
H. Peter Anvine2c80182005-01-15 22:15:51 +00001925 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001926
Keith Kaniosb7a89542007-04-12 02:40:54 +00001927 /* now reorganize base/index */
1928 if (s == 1 && bt != it && bt != -1 && it != -1 &&
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001929 ((hb == b && ht == EAH_NOTBASE)
1930 || (hb == i && ht == EAH_MAKEBASE))) {
1931 /* swap if hints say so */
1932 t = bt, bt = it, it = t;
1933 t = bx, bx = ix, ix = t;
1934 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00001935 if (bt == it) /* convert EAX+2*EAX to 3*EAX */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001936 bt = -1, bx = 0, s++;
1937 if (bt == -1 && s == 1 && !(hb == it && ht == EAH_NOTBASE)) {
1938 /* make single reg base, unless hint */
1939 bt = it, bx = ix, it = -1, ix = 0;
1940 }
H. Peter Anvinf5843c62007-09-10 18:59:26 +00001941 if (((s == 2 && it != REG_NUM_ESP
H. Peter Anvine2c80182005-01-15 22:15:51 +00001942 && !(input->eaflags & EAF_TIMESTWO)) || s == 3
Keith Kaniosb7a89542007-04-12 02:40:54 +00001943 || s == 5 || s == 9) && bt == -1)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001944 bt = it, bx = ix, s--; /* convert 3*EAX to EAX+2*EAX */
Keith Kanios48af1772007-08-17 07:37:52 +00001945 if (it == -1 && (bt & 7) != REG_NUM_ESP
H. Peter Anvine2c80182005-01-15 22:15:51 +00001946 && (input->eaflags & EAF_TIMESTWO))
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001947 it = bt, ix = bx, bt = -1, bx = 0, s = 1;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001948 /* convert [NOSPLIT EAX] to sib format with 0x0 displacement */
Keith Kanios48af1772007-08-17 07:37:52 +00001949 if (s == 1 && it == REG_NUM_ESP) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001950 /* swap ESP into base if scale is 1 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00001951 t = it, it = bt, bt = t;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001952 t = ix, ix = bx, bx = t;
1953 }
Keith Kanios48af1772007-08-17 07:37:52 +00001954 if (it == REG_NUM_ESP
Keith Kaniosb7a89542007-04-12 02:40:54 +00001955 || (s != 1 && s != 2 && s != 4 && s != 8 && it != -1))
H. Peter Anvine2c80182005-01-15 22:15:51 +00001956 return NULL; /* wrong, for various reasons */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001957
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001958 output->rex |= rexflags(it, ix, REX_X);
1959 output->rex |= rexflags(bt, bx, REX_B);
Keith Kaniosb7a89542007-04-12 02:40:54 +00001960
Keith Kanios48af1772007-08-17 07:37:52 +00001961 if (it == -1 && (bt & 7) != REG_NUM_ESP) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001962 /* no SIB needed */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001963 int mod, rm;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001964
1965 if (bt == -1) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001966 rm = 5;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001967 mod = 0;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001968 } else {
1969 rm = (bt & 7);
Keith Kanios48af1772007-08-17 07:37:52 +00001970 if (rm != REG_NUM_EBP && o == 0 &&
Keith Kaniosb7a89542007-04-12 02:40:54 +00001971 seg == NO_SEG && !forw_ref &&
1972 !(input->eaflags &
1973 (EAF_BYTEOFFS | EAF_WORDOFFS)))
1974 mod = 0;
1975 else if (input->eaflags & EAF_BYTEOFFS ||
1976 (o >= -128 && o <= 127 && seg == NO_SEG
1977 && !forw_ref
1978 && !(input->eaflags & EAF_WORDOFFS)))
1979 mod = 1;
1980 else
1981 mod = 2;
1982 }
H. Peter Anvinea838272002-04-30 20:51:53 +00001983
H. Peter Anvine2c80182005-01-15 22:15:51 +00001984 output->sib_present = FALSE;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001985 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
1986 output->modrm = (mod << 6) | ((rfield & 7) << 3) | rm;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001987 } else {
1988 /* we need a SIB */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001989 int mod, scale, index, base;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001990
1991 if (it == -1)
1992 index = 4, s = 1;
1993 else
1994 index = (it & 7);
1995
H. Peter Anvine2c80182005-01-15 22:15:51 +00001996 switch (s) {
1997 case 1:
1998 scale = 0;
1999 break;
2000 case 2:
2001 scale = 1;
2002 break;
2003 case 4:
2004 scale = 2;
2005 break;
2006 case 8:
2007 scale = 3;
2008 break;
2009 default: /* then what the smeg is it? */
2010 return NULL; /* panic */
2011 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00002012
2013 if (bt == -1) {
2014 base = 5;
2015 mod = 0;
2016 } else {
2017 base = (bt & 7);
Keith Kanios48af1772007-08-17 07:37:52 +00002018 if (base != REG_NUM_EBP && o == 0 &&
H. Peter Anvine2c80182005-01-15 22:15:51 +00002019 seg == NO_SEG && !forw_ref &&
2020 !(input->eaflags &
Keith Kaniosb7a89542007-04-12 02:40:54 +00002021 (EAF_BYTEOFFS | EAF_WORDOFFS)))
2022 mod = 0;
2023 else if (input->eaflags & EAF_BYTEOFFS ||
2024 (o >= -128 && o <= 127 && seg == NO_SEG
2025 && !forw_ref
2026 && !(input->eaflags & EAF_WORDOFFS)))
2027 mod = 1;
2028 else
2029 mod = 2;
2030 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002031
H. Peter Anvine2c80182005-01-15 22:15:51 +00002032 output->sib_present = TRUE;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002033 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2034 output->modrm = (mod << 6) | ((rfield & 7) << 3) | 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002035 output->sib = (scale << 6) | (index << 3) | base;
2036 }
2037 } else { /* it's 16-bit */
2038 int mod, rm;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002039
2040 /* check for 64-bit long mode */
2041 if (addrbits == 64)
2042 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002043
H. Peter Anvine2c80182005-01-15 22:15:51 +00002044 /* check all registers are BX, BP, SI or DI */
2045 if ((b != -1 && b != R_BP && b != R_BX && b != R_SI
2046 && b != R_DI) || (i != -1 && i != R_BP && i != R_BX
2047 && i != R_SI && i != R_DI))
2048 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002049
Keith Kaniosb7a89542007-04-12 02:40:54 +00002050 /* ensure the user didn't specify DWORD/QWORD */
2051 if (input->addr_size == 32 || input->addr_size == 64)
H. Peter Anvine2c80182005-01-15 22:15:51 +00002052 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002053
H. Peter Anvine2c80182005-01-15 22:15:51 +00002054 if (s != 1 && i != -1)
2055 return NULL; /* no can do, in 16-bit EA */
2056 if (b == -1 && i != -1) {
2057 int tmp = b;
2058 b = i;
2059 i = tmp;
2060 } /* swap */
2061 if ((b == R_SI || b == R_DI) && i != -1) {
2062 int tmp = b;
2063 b = i;
2064 i = tmp;
2065 }
2066 /* have BX/BP as base, SI/DI index */
2067 if (b == i)
2068 return NULL; /* shouldn't ever happen, in theory */
2069 if (i != -1 && b != -1 &&
2070 (i == R_BP || i == R_BX || b == R_SI || b == R_DI))
2071 return NULL; /* invalid combinations */
2072 if (b == -1) /* pure offset: handled above */
2073 return NULL; /* so if it gets to here, panic! */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002074
H. Peter Anvine2c80182005-01-15 22:15:51 +00002075 rm = -1;
2076 if (i != -1)
2077 switch (i * 256 + b) {
2078 case R_SI * 256 + R_BX:
2079 rm = 0;
2080 break;
2081 case R_DI * 256 + R_BX:
2082 rm = 1;
2083 break;
2084 case R_SI * 256 + R_BP:
2085 rm = 2;
2086 break;
2087 case R_DI * 256 + R_BP:
2088 rm = 3;
2089 break;
2090 } else
2091 switch (b) {
2092 case R_SI:
2093 rm = 4;
2094 break;
2095 case R_DI:
2096 rm = 5;
2097 break;
2098 case R_BP:
2099 rm = 6;
2100 break;
2101 case R_BX:
2102 rm = 7;
2103 break;
2104 }
2105 if (rm == -1) /* can't happen, in theory */
2106 return NULL; /* so panic if it does */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002107
H. Peter Anvine2c80182005-01-15 22:15:51 +00002108 if (o == 0 && seg == NO_SEG && !forw_ref && rm != 6 &&
2109 !(input->eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS)))
2110 mod = 0;
2111 else if (input->eaflags & EAF_BYTEOFFS ||
2112 (o >= -128 && o <= 127 && seg == NO_SEG
2113 && !forw_ref
2114 && !(input->eaflags & EAF_WORDOFFS)))
2115 mod = 1;
2116 else
2117 mod = 2;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002118
H. Peter Anvine2c80182005-01-15 22:15:51 +00002119 output->sib_present = FALSE; /* no SIB - it's 16-bit */
2120 output->bytes = mod; /* bytes of offset needed */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002121 output->modrm = (mod << 6) | ((rfield & 7) << 3) | rm;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002122 }
2123 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002124 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00002125
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002126 output->size = 1 + output->sib_present + output->bytes;
2127 return output;
2128}
2129
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002130static void add_asp(insn *instruction, int addrbits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002131{
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002132 int j, valid;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002133
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002134 valid = (addrbits == 64) ? 64|32 : 32|16;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002135
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002136 for (j = 0; j < instruction->operands; j++) {
2137 if (!(MEMORY & ~instruction->oprs[j].type)) {
2138 int32_t i, b;
2139
2140 /* Verify as Register */
2141 if (instruction->oprs[j].indexreg < EXPR_REG_START
2142 || instruction->oprs[j].indexreg >= REG_ENUM_LIMIT)
2143 i = 0;
2144 else
2145 i = reg_flags[instruction->oprs[j].indexreg];
2146
2147 /* Verify as Register */
2148 if (instruction->oprs[j].basereg < EXPR_REG_START
2149 || instruction->oprs[j].basereg >= REG_ENUM_LIMIT)
2150 b = 0;
2151 else
2152 b = reg_flags[instruction->oprs[j].basereg];
2153
2154 if (instruction->oprs[j].scale == 0)
2155 i = 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002156
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002157 if (!i && !b) {
2158 if (instruction->oprs[j].addr_size)
2159 valid &= instruction->oprs[j].addr_size;
2160 } else {
2161 if (!(REG16 & ~b))
2162 valid &= 16;
2163 if (!(REG32 & ~b))
2164 valid &= 32;
2165 if (!(REG64 & ~b))
2166 valid &= 64;
2167
2168 if (!(REG16 & ~i))
2169 valid &= 16;
2170 if (!(REG32 & ~i))
2171 valid &= 32;
2172 if (!(REG64 & ~i))
2173 valid &= 64;
2174 }
2175 }
2176 }
2177
2178 if (valid & addrbits) {
2179 /* Don't do anything */
2180 } else if (valid & ((addrbits == 32) ? 16 : 32)) {
2181 /* Add an instruction size prefix */
2182 enum prefixes pref = (addrbits == 32) ? P_A16 : P_A32;
2183 for (j = 0; j < instruction->nprefix; j++) {
2184 if (instruction->prefixes[j] == pref)
2185 return; /* Already there */
2186 }
2187 instruction->prefixes[j] = pref;
2188 instruction->nprefix++;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002189 } else {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002190 /* Impossible... */
2191 errfunc(ERR_NONFATAL, "impossible combination of address sizes");
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002192 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002193}