blob: 4d56a650361eaa2ca28c817004bb5ff5eb8d480a [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;
Keith Kaniose83b3182007-04-16 14:31:54 +00001604 if (ea_data.rip && (ins->oprs[(c >> 3) & 7].segment == 0xFFFFFFFF))
1605 ea_data.rip = 0; /* Make distinction between Symbols and Immediates */
Keith Kaniosb7a89542007-04-12 02:40:54 +00001606 out(offset, segment, &data, /* RIP = Relative, not Absolute */
1607 (ea_data.rip ? OUT_REL4ADR : OUT_ADDRESS) + ea_data.bytes,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001608 ins->oprs[(c >> 3) & 7].segment,
1609 ins->oprs[(c >> 3) & 7].wrt);
1610 s += ea_data.bytes;
1611 break;
1612 }
1613 offset += s;
1614 } else
1615 errfunc(ERR_PANIC, "internal instruction table corrupt"
1616 ": instruction code 0x%02X given", c);
1617 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001618}
1619
H. Peter Anvin0ec60e62007-07-07 01:59:52 +00001620static int32_t regflag(const operand * o)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001621{
1622 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1623 errfunc(ERR_PANIC, "invalid operand passed to regflag()");
1624 }
1625 return reg_flags[o->basereg];
1626}
1627
H. Peter Anvin5b0e3ec2007-07-07 02:01:08 +00001628static int32_t regval(const operand * o)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001629{
H. Peter Anvine2c80182005-01-15 22:15:51 +00001630 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1631 errfunc(ERR_PANIC, "invalid operand passed to regval()");
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001632 }
H. Peter Anvin232badb2002-06-06 02:41:20 +00001633 return regvals[o->basereg];
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001634}
1635
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001636static int op_rexflags(const operand * o, int mask)
1637{
1638 int32_t flags;
1639 int val;
1640
1641 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1642 errfunc(ERR_PANIC, "invalid operand passed to op_rexflags()");
1643 }
1644
1645 flags = reg_flags[o->basereg];
1646 val = regvals[o->basereg];
1647
1648 return rexflags(val, flags, mask);
1649}
1650
1651static int rexflags(int val, int32_t flags, int mask)
1652{
1653 int rex = 0;
1654
1655 if (val >= 8)
1656 rex |= REX_B|REX_X|REX_R;
1657 if (flags & BITS64)
1658 rex |= REX_W;
1659 if (!(REG_HIGH & ~flags)) /* AH, CH, DH, BH */
1660 rex |= REX_H;
1661 else if (!(REG8 & ~flags) && val >= 4) /* SPL, BPL, SIL, DIL */
1662 rex |= REX_P;
1663
1664 return rex & mask;
1665}
1666
H. Peter Anvin3360d792007-09-11 04:16:57 +00001667static int matches(const struct itemplate *itemp, insn * instruction, int bits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001668{
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001669 int i, size[MAX_OPERANDS], asize, oprs, ret;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001670
1671 ret = 100;
1672
1673 /*
1674 * Check the opcode
1675 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001676 if (itemp->opcode != instruction->opcode)
1677 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001678
1679 /*
1680 * Count the operands
1681 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001682 if (itemp->operands != instruction->operands)
1683 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001684
1685 /*
1686 * Check that no spurious colons or TOs are present
1687 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001688 for (i = 0; i < itemp->operands; i++)
1689 if (instruction->oprs[i].type & ~itemp->opd[i] & (COLON | TO))
1690 return 0;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001691
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001692 /*
1693 * Check that the operand flags all match up
1694 */
H. Peter Anvin16b0a332007-09-12 20:27:41 -07001695 for (i = 0; i < itemp->operands; i++) {
H. Peter Anvincf5180a2007-09-17 17:25:27 -07001696 if (itemp->opd[i] & SAME_AS) {
1697 int j = itemp->opd[i] & ~SAME_AS;
1698 if (instruction->oprs[i].type != instruction->oprs[j].type ||
1699 instruction->oprs[i].basereg != instruction->oprs[j].basereg)
1700 return 0;
H. Peter Anvin457afd42007-09-25 15:41:19 -07001701 } else if (itemp->opd[i] & ~instruction->oprs[i].type ||
H. Peter Anvine2c80182005-01-15 22:15:51 +00001702 ((itemp->opd[i] & SIZE_MASK) &&
1703 ((itemp->opd[i] ^ instruction->oprs[i].type) & SIZE_MASK))) {
H. Peter Anvin5a640e12007-05-29 23:57:12 +00001704 if ((itemp->opd[i] & ~instruction->oprs[i].type & ~SIZE_MASK) ||
H. Peter Anvine2c80182005-01-15 22:15:51 +00001705 (instruction->oprs[i].type & SIZE_MASK))
1706 return 0;
1707 else
H. Peter Anvine2c80182005-01-15 22:15:51 +00001708 return 1;
1709 }
H. Peter Anvin16b0a332007-09-12 20:27:41 -07001710 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001711
1712 /*
1713 * Check operand sizes
1714 */
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001715 if (itemp->flags & IF_ARMASK) {
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001716 memset(size, 0, sizeof size);
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001717
H. Peter Anvine2c80182005-01-15 22:15:51 +00001718 switch (itemp->flags & IF_ARMASK) {
1719 case IF_AR0:
1720 i = 0;
1721 break;
1722 case IF_AR1:
1723 i = 1;
1724 break;
1725 case IF_AR2:
1726 i = 2;
1727 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001728 case IF_AR3:
1729 i = 3;
1730 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001731 default:
1732 break; /* Shouldn't happen */
1733 }
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001734 switch (itemp->flags & IF_SMASK) {
1735 case IF_SB:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001736 size[i] = BITS8;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001737 break;
1738 case IF_SW:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001739 size[i] = BITS16;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001740 break;
1741 case IF_SD:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001742 size[i] = BITS32;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001743 break;
1744 case IF_SQ:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001745 size[i] = BITS64;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001746 break;
H. Peter Anvin41c9f6f2007-09-18 13:01:32 -07001747 case IF_SO:
1748 size[i] = BITS128;
1749 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001750 default:
1751 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001752 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001753 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001754 asize = 0;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001755 switch (itemp->flags & IF_SMASK) {
1756 case IF_SB:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001757 asize = BITS8;
1758 oprs = itemp->operands;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001759 break;
1760 case IF_SW:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001761 asize = BITS16;
1762 oprs = itemp->operands;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001763 break;
1764 case IF_SD:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001765 asize = BITS32;
1766 oprs = itemp->operands;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001767 break;
1768 case IF_SQ:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001769 asize = BITS64;
1770 oprs = itemp->operands;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001771 break;
H. Peter Anvin41c9f6f2007-09-18 13:01:32 -07001772 case IF_SO:
1773 asize = BITS128;
1774 oprs = itemp->operands;
1775 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001776 default:
1777 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001778 }
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001779 for (i = 0; i < MAX_OPERANDS; i++)
1780 size[i] = asize;
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001781 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00001782
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001783 if (itemp->flags & (IF_SM | IF_SM2)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001784 oprs = (itemp->flags & IF_SM2 ? 2 : itemp->operands);
1785 asize = 0;
1786 for (i = 0; i < oprs; i++) {
1787 if ((asize = itemp->opd[i] & SIZE_MASK) != 0) {
1788 int j;
1789 for (j = 0; j < oprs; j++)
1790 size[j] = asize;
1791 break;
1792 }
1793 }
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001794 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001795 oprs = itemp->operands;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001796 }
1797
Keith Kaniosb7a89542007-04-12 02:40:54 +00001798 for (i = 0; i < itemp->operands; i++) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001799 if (!(itemp->opd[i] & SIZE_MASK) &&
1800 (instruction->oprs[i].type & SIZE_MASK & ~size[i]))
H. Peter Anvine2c80182005-01-15 22:15:51 +00001801 return 2;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001802 }
1803
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001804 /*
1805 * Check template is okay at the set cpu level
1806 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00001807 if (((itemp->flags & IF_PLEVEL) > cpu))
H. Peter Anvine2c80182005-01-15 22:15:51 +00001808 return 3;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001809
1810 /*
1811 * Check if instruction is available in long mode
1812 */
1813 if ((itemp->flags & IF_NOLONG) && (bits == 64))
1814 return 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001815
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001816 /*
1817 * Check if special handling needed for Jumps
1818 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00001819 if ((uint8_t)(itemp->code[0]) >= 0370)
H. Peter Anvine2c80182005-01-15 22:15:51 +00001820 return 99;
1821
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001822 return ret;
1823}
1824
H. Peter Anvine2c80182005-01-15 22:15:51 +00001825static ea *process_ea(operand * input, ea * output, int addrbits,
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001826 int rfield, int32_t rflags, int forw_ref)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001827{
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00001828 output->rip = FALSE;
1829
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001830 /* REX flags for the rfield operand */
1831 output->rex |= rexflags(rfield, rflags, REX_R|REX_P|REX_W|REX_H);
1832
Keith Kaniosb7a89542007-04-12 02:40:54 +00001833 if (!(REGISTER & ~input->type)) { /* register direct */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001834 int i;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001835 int32_t f;
1836
1837 if (input->basereg < EXPR_REG_START /* Verify as Register */
Keith Kaniosb7a89542007-04-12 02:40:54 +00001838 || input->basereg >= REG_ENUM_LIMIT)
H. Peter Anvine2c80182005-01-15 22:15:51 +00001839 return NULL;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001840 f = regflag(input);
Keith Kaniosb7a89542007-04-12 02:40:54 +00001841 i = regvals[input->basereg];
Keith Kaniosb7a89542007-04-12 02:40:54 +00001842
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001843 if (REG_EA & ~f)
1844 return NULL; /* Invalid EA register */
1845
1846 output->rex |= op_rexflags(input, REX_B|REX_P|REX_W|REX_H);
1847
Keith Kaniosb7a89542007-04-12 02:40:54 +00001848 output->sib_present = FALSE; /* no SIB necessary */
1849 output->bytes = 0; /* no offset necessary either */
1850 output->modrm = 0xC0 | ((rfield & 7) << 3) | (i & 7);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001851 } else { /* it's a memory reference */
1852 if (input->basereg == -1
1853 && (input->indexreg == -1 || input->scale == 0)) {
1854 /* it's a pure offset */
1855 if (input->addr_size)
1856 addrbits = input->addr_size;
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00001857
1858 if (globalbits == 64 && (~input->type & IP_REL)) {
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00001859 int scale, index, base;
1860 output->sib_present = TRUE;
1861 scale = 0;
1862 index = 4;
1863 base = 5;
1864 output->sib = (scale << 6) | (index << 3) | base;
1865 output->bytes = 4;
1866 output->modrm = 4 | ((rfield & 7) << 3);
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00001867 output->rip = FALSE;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00001868 } else {
1869 output->sib_present = FALSE;
1870 output->bytes = (addrbits != 16 ? 4 : 2);
1871 output->modrm = (addrbits != 16 ? 5 : 6) | ((rfield & 7) << 3);
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00001872 output->rip = globalbits == 64;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00001873 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001874 } else { /* it's an indirection */
1875 int i = input->indexreg, b = input->basereg, s = input->scale;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001876 int32_t o = input->offset, seg = input->segment;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001877 int hb = input->hintbase, ht = input->hinttype;
1878 int t;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001879 int it, bt;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001880 int32_t ix, bx; /* register flags */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001881
H. Peter Anvine2c80182005-01-15 22:15:51 +00001882 if (s == 0)
1883 i = -1; /* make this easy, at least */
Keith Kaniosb7a89542007-04-12 02:40:54 +00001884
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001885 if (i >= EXPR_REG_START && i < REG_ENUM_LIMIT) {
Keith Kaniosb7a89542007-04-12 02:40:54 +00001886 it = regvals[i];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001887 ix = reg_flags[i];
1888 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00001889 it = -1;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001890 ix = 0;
1891 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00001892
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001893 if (b != -1 && b >= EXPR_REG_START && b < REG_ENUM_LIMIT) {
Keith Kaniosb7a89542007-04-12 02:40:54 +00001894 bt = regvals[b];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001895 bx = reg_flags[b];
1896 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00001897 bt = -1;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001898 bx = 0;
1899 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00001900
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001901 /* check for a 32/64-bit memory reference... */
1902 if ((ix|bx) & (BITS32|BITS64)) {
Keith Kaniosb7a89542007-04-12 02:40:54 +00001903 /* it must be a 32/64-bit memory reference. Firstly we have
1904 * to check that all registers involved are type E/Rxx. */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001905 int32_t sok = BITS32|BITS64;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001906
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001907 if (it != -1) {
1908 if (!(REG64 & ~ix) || !(REG32 & ~ix))
1909 sok &= ix;
1910 else
1911 return NULL;
1912 }
1913
1914 if (bt != -1) {
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00001915 if (REG_GPR & ~bx)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001916 return NULL; /* Invalid register */
H. Peter Anvina57e8d42007-05-30 03:44:02 +00001917 if (~sok & bx & SIZE_MASK)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001918 return NULL; /* Invalid size */
1919 sok &= ~bx;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001920 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00001921
H. Peter Anvine2c80182005-01-15 22:15:51 +00001922 /* While we're here, ensure the user didn't specify WORD. */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001923 if (input->addr_size == 16 ||
1924 (input->addr_size == 32 && !(sok & BITS32)) ||
1925 (input->addr_size == 64 && !(sok & BITS64)))
H. Peter Anvine2c80182005-01-15 22:15:51 +00001926 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001927
Keith Kaniosb7a89542007-04-12 02:40:54 +00001928 /* now reorganize base/index */
1929 if (s == 1 && bt != it && bt != -1 && it != -1 &&
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001930 ((hb == b && ht == EAH_NOTBASE)
1931 || (hb == i && ht == EAH_MAKEBASE))) {
1932 /* swap if hints say so */
1933 t = bt, bt = it, it = t;
1934 t = bx, bx = ix, ix = t;
1935 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00001936 if (bt == it) /* convert EAX+2*EAX to 3*EAX */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001937 bt = -1, bx = 0, s++;
1938 if (bt == -1 && s == 1 && !(hb == it && ht == EAH_NOTBASE)) {
1939 /* make single reg base, unless hint */
1940 bt = it, bx = ix, it = -1, ix = 0;
1941 }
H. Peter Anvinf5843c62007-09-10 18:59:26 +00001942 if (((s == 2 && it != REG_NUM_ESP
H. Peter Anvine2c80182005-01-15 22:15:51 +00001943 && !(input->eaflags & EAF_TIMESTWO)) || s == 3
Keith Kaniosb7a89542007-04-12 02:40:54 +00001944 || s == 5 || s == 9) && bt == -1)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001945 bt = it, bx = ix, s--; /* convert 3*EAX to EAX+2*EAX */
Keith Kanios48af1772007-08-17 07:37:52 +00001946 if (it == -1 && (bt & 7) != REG_NUM_ESP
H. Peter Anvine2c80182005-01-15 22:15:51 +00001947 && (input->eaflags & EAF_TIMESTWO))
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001948 it = bt, ix = bx, bt = -1, bx = 0, s = 1;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001949 /* convert [NOSPLIT EAX] to sib format with 0x0 displacement */
Keith Kanios48af1772007-08-17 07:37:52 +00001950 if (s == 1 && it == REG_NUM_ESP) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001951 /* swap ESP into base if scale is 1 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00001952 t = it, it = bt, bt = t;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001953 t = ix, ix = bx, bx = t;
1954 }
Keith Kanios48af1772007-08-17 07:37:52 +00001955 if (it == REG_NUM_ESP
Keith Kaniosb7a89542007-04-12 02:40:54 +00001956 || (s != 1 && s != 2 && s != 4 && s != 8 && it != -1))
H. Peter Anvine2c80182005-01-15 22:15:51 +00001957 return NULL; /* wrong, for various reasons */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001958
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001959 output->rex |= rexflags(it, ix, REX_X);
1960 output->rex |= rexflags(bt, bx, REX_B);
Keith Kaniosb7a89542007-04-12 02:40:54 +00001961
Keith Kanios48af1772007-08-17 07:37:52 +00001962 if (it == -1 && (bt & 7) != REG_NUM_ESP) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001963 /* no SIB needed */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001964 int mod, rm;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001965
1966 if (bt == -1) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001967 rm = 5;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001968 mod = 0;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001969 } else {
1970 rm = (bt & 7);
Keith Kanios48af1772007-08-17 07:37:52 +00001971 if (rm != REG_NUM_EBP && o == 0 &&
Keith Kaniosb7a89542007-04-12 02:40:54 +00001972 seg == NO_SEG && !forw_ref &&
1973 !(input->eaflags &
1974 (EAF_BYTEOFFS | EAF_WORDOFFS)))
1975 mod = 0;
1976 else if (input->eaflags & EAF_BYTEOFFS ||
1977 (o >= -128 && o <= 127 && seg == NO_SEG
1978 && !forw_ref
1979 && !(input->eaflags & EAF_WORDOFFS)))
1980 mod = 1;
1981 else
1982 mod = 2;
1983 }
H. Peter Anvinea838272002-04-30 20:51:53 +00001984
H. Peter Anvine2c80182005-01-15 22:15:51 +00001985 output->sib_present = FALSE;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001986 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
1987 output->modrm = (mod << 6) | ((rfield & 7) << 3) | rm;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001988 } else {
1989 /* we need a SIB */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001990 int mod, scale, index, base;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001991
1992 if (it == -1)
1993 index = 4, s = 1;
1994 else
1995 index = (it & 7);
1996
H. Peter Anvine2c80182005-01-15 22:15:51 +00001997 switch (s) {
1998 case 1:
1999 scale = 0;
2000 break;
2001 case 2:
2002 scale = 1;
2003 break;
2004 case 4:
2005 scale = 2;
2006 break;
2007 case 8:
2008 scale = 3;
2009 break;
2010 default: /* then what the smeg is it? */
2011 return NULL; /* panic */
2012 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00002013
2014 if (bt == -1) {
2015 base = 5;
2016 mod = 0;
2017 } else {
2018 base = (bt & 7);
Keith Kanios48af1772007-08-17 07:37:52 +00002019 if (base != REG_NUM_EBP && o == 0 &&
H. Peter Anvine2c80182005-01-15 22:15:51 +00002020 seg == NO_SEG && !forw_ref &&
2021 !(input->eaflags &
Keith Kaniosb7a89542007-04-12 02:40:54 +00002022 (EAF_BYTEOFFS | EAF_WORDOFFS)))
2023 mod = 0;
2024 else if (input->eaflags & EAF_BYTEOFFS ||
2025 (o >= -128 && o <= 127 && seg == NO_SEG
2026 && !forw_ref
2027 && !(input->eaflags & EAF_WORDOFFS)))
2028 mod = 1;
2029 else
2030 mod = 2;
2031 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002032
H. Peter Anvine2c80182005-01-15 22:15:51 +00002033 output->sib_present = TRUE;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002034 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2035 output->modrm = (mod << 6) | ((rfield & 7) << 3) | 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002036 output->sib = (scale << 6) | (index << 3) | base;
2037 }
2038 } else { /* it's 16-bit */
2039 int mod, rm;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002040
2041 /* check for 64-bit long mode */
2042 if (addrbits == 64)
2043 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002044
H. Peter Anvine2c80182005-01-15 22:15:51 +00002045 /* check all registers are BX, BP, SI or DI */
2046 if ((b != -1 && b != R_BP && b != R_BX && b != R_SI
2047 && b != R_DI) || (i != -1 && i != R_BP && i != R_BX
2048 && i != R_SI && i != R_DI))
2049 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002050
Keith Kaniosb7a89542007-04-12 02:40:54 +00002051 /* ensure the user didn't specify DWORD/QWORD */
2052 if (input->addr_size == 32 || input->addr_size == 64)
H. Peter Anvine2c80182005-01-15 22:15:51 +00002053 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002054
H. Peter Anvine2c80182005-01-15 22:15:51 +00002055 if (s != 1 && i != -1)
2056 return NULL; /* no can do, in 16-bit EA */
2057 if (b == -1 && i != -1) {
2058 int tmp = b;
2059 b = i;
2060 i = tmp;
2061 } /* swap */
2062 if ((b == R_SI || b == R_DI) && i != -1) {
2063 int tmp = b;
2064 b = i;
2065 i = tmp;
2066 }
2067 /* have BX/BP as base, SI/DI index */
2068 if (b == i)
2069 return NULL; /* shouldn't ever happen, in theory */
2070 if (i != -1 && b != -1 &&
2071 (i == R_BP || i == R_BX || b == R_SI || b == R_DI))
2072 return NULL; /* invalid combinations */
2073 if (b == -1) /* pure offset: handled above */
2074 return NULL; /* so if it gets to here, panic! */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002075
H. Peter Anvine2c80182005-01-15 22:15:51 +00002076 rm = -1;
2077 if (i != -1)
2078 switch (i * 256 + b) {
2079 case R_SI * 256 + R_BX:
2080 rm = 0;
2081 break;
2082 case R_DI * 256 + R_BX:
2083 rm = 1;
2084 break;
2085 case R_SI * 256 + R_BP:
2086 rm = 2;
2087 break;
2088 case R_DI * 256 + R_BP:
2089 rm = 3;
2090 break;
2091 } else
2092 switch (b) {
2093 case R_SI:
2094 rm = 4;
2095 break;
2096 case R_DI:
2097 rm = 5;
2098 break;
2099 case R_BP:
2100 rm = 6;
2101 break;
2102 case R_BX:
2103 rm = 7;
2104 break;
2105 }
2106 if (rm == -1) /* can't happen, in theory */
2107 return NULL; /* so panic if it does */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002108
H. Peter Anvine2c80182005-01-15 22:15:51 +00002109 if (o == 0 && seg == NO_SEG && !forw_ref && rm != 6 &&
2110 !(input->eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS)))
2111 mod = 0;
2112 else if (input->eaflags & EAF_BYTEOFFS ||
2113 (o >= -128 && o <= 127 && seg == NO_SEG
2114 && !forw_ref
2115 && !(input->eaflags & EAF_WORDOFFS)))
2116 mod = 1;
2117 else
2118 mod = 2;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002119
H. Peter Anvine2c80182005-01-15 22:15:51 +00002120 output->sib_present = FALSE; /* no SIB - it's 16-bit */
2121 output->bytes = mod; /* bytes of offset needed */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002122 output->modrm = (mod << 6) | ((rfield & 7) << 3) | rm;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002123 }
2124 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002125 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00002126
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002127 output->size = 1 + output->sib_present + output->bytes;
2128 return output;
2129}
2130
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002131static void add_asp(insn *instruction, int addrbits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002132{
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002133 int j, valid;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002134
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002135 valid = (addrbits == 64) ? 64|32 : 32|16;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002136
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002137 for (j = 0; j < instruction->operands; j++) {
2138 if (!(MEMORY & ~instruction->oprs[j].type)) {
2139 int32_t i, b;
2140
2141 /* Verify as Register */
2142 if (instruction->oprs[j].indexreg < EXPR_REG_START
2143 || instruction->oprs[j].indexreg >= REG_ENUM_LIMIT)
2144 i = 0;
2145 else
2146 i = reg_flags[instruction->oprs[j].indexreg];
2147
2148 /* Verify as Register */
2149 if (instruction->oprs[j].basereg < EXPR_REG_START
2150 || instruction->oprs[j].basereg >= REG_ENUM_LIMIT)
2151 b = 0;
2152 else
2153 b = reg_flags[instruction->oprs[j].basereg];
2154
2155 if (instruction->oprs[j].scale == 0)
2156 i = 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002157
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002158 if (!i && !b) {
2159 if (instruction->oprs[j].addr_size)
2160 valid &= instruction->oprs[j].addr_size;
2161 } else {
2162 if (!(REG16 & ~b))
2163 valid &= 16;
2164 if (!(REG32 & ~b))
2165 valid &= 32;
2166 if (!(REG64 & ~b))
2167 valid &= 64;
2168
2169 if (!(REG16 & ~i))
2170 valid &= 16;
2171 if (!(REG32 & ~i))
2172 valid &= 32;
2173 if (!(REG64 & ~i))
2174 valid &= 64;
2175 }
2176 }
2177 }
2178
2179 if (valid & addrbits) {
2180 /* Don't do anything */
2181 } else if (valid & ((addrbits == 32) ? 16 : 32)) {
2182 /* Add an instruction size prefix */
2183 enum prefixes pref = (addrbits == 32) ? P_A16 : P_A32;
2184 for (j = 0; j < instruction->nprefix; j++) {
2185 if (instruction->prefixes[j] == pref)
2186 return; /* Already there */
2187 }
2188 instruction->prefixes[j] = pref;
2189 instruction->nprefix++;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002190 } else {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002191 /* Impossible... */
2192 errfunc(ERR_NONFATAL, "impossible combination of address sizes");
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002193 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002194}