blob: 2fd9f973c306ef364f0cfd8d51d9f323ec0ad5ab [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
H. Peter Anvinfe501952007-10-02 21:53:51 -070085#include "compiler.h"
86
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000087#include <stdio.h>
88#include <string.h>
Keith Kaniosb7a89542007-04-12 02:40:54 +000089#include <inttypes.h>
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000090
91#include "nasm.h"
H. Peter Anvin6768eb72002-04-30 20:52:26 +000092#include "nasmlib.h"
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000093#include "assemble.h"
94#include "insns.h"
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +000095#include "preproc.h"
H. Peter Anvin3df97a72007-05-30 03:25:21 +000096#include "regflags.c"
Keith Kaniosb7a89542007-04-12 02:40:54 +000097#include "regvals.c"
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000098
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000099typedef struct {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000100 int sib_present; /* is a SIB byte necessary? */
101 int bytes; /* # of bytes of offset needed */
102 int size; /* lazy - this is sib+bytes+1 */
103 uint8_t modrm, sib, rex, rip; /* the bytes themselves */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000104} ea;
105
Keith Kaniosb7a89542007-04-12 02:40:54 +0000106static uint32_t cpu; /* cpu level received from nasm.c */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000107static efunc errfunc;
108static struct ofmt *outfmt;
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000109static ListGen *list;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000110
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000111static int32_t calcsize(int32_t, int32_t, int, insn *, const char *);
112static void gencode(int32_t, int32_t, int, insn *, const char *, int32_t);
H. Peter Anvin3360d792007-09-11 04:16:57 +0000113static int matches(const struct itemplate *, insn *, int bits);
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000114static int32_t regflag(const operand *);
115static int32_t regval(const operand *);
116static int rexflags(int, int32_t, int);
117static int op_rexflags(const operand *, int);
H. Peter Anvin5b0e3ec2007-07-07 02:01:08 +0000118static ea *process_ea(operand *, ea *, int, int, int32_t, int);
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700119static void add_asp(insn *, int);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000120
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700121static int has_prefix(insn * ins, enum prefixes prefix)
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000122{
123 int j;
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000124 for (j = 0; j < ins->nprefix; j++) {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700125 if (ins->prefixes[j] == prefix)
126 return 1;
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000127 }
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700128 return 0;
129}
130
131static void assert_no_prefix(insn * ins, enum prefixes prefix)
132{
133 if (has_prefix(ins, prefix))
134 errfunc(ERR_NONFATAL, "invalid %s prefix", prefix_name(prefix));
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000135}
136
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000137/*
138 * This routine wrappers the real output format's output routine,
139 * in order to pass a copy of the data off to the listing file
140 * generator at the same time.
141 */
Keith Kaniosb7a89542007-04-12 02:40:54 +0000142static void out(int32_t offset, int32_t segto, const void *data,
143 uint32_t type, int32_t segment, int32_t wrt)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000144{
Keith Kaniosb7a89542007-04-12 02:40:54 +0000145 static int32_t lineno = 0; /* static!!! */
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000146 static char *lnfname = NULL;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000147
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000148 if ((type & OUT_TYPMASK) == OUT_ADDRESS) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000149 if (segment != NO_SEG || wrt != NO_SEG) {
150 /*
151 * This address is relocated. We must write it as
152 * OUT_ADDRESS, so there's no work to be done here.
153 */
154 list->output(offset, data, type);
155 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000156 uint8_t p[8], *q = p;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000157 /*
158 * This is a non-relocated address, and we're going to
159 * convert it into RAWDATA format.
160 */
161 if ((type & OUT_SIZMASK) == 4) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000162 WRITELONG(q, *(int32_t *)data);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000163 list->output(offset, p, OUT_RAWDATA + 4);
Keith Kaniosb7a89542007-04-12 02:40:54 +0000164 } else if ((type & OUT_SIZMASK) == 8) {
165 WRITEDLONG(q, *(int64_t *)data);
166 list->output(offset, p, OUT_RAWDATA + 8);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000167 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000168 WRITESHORT(q, *(int32_t *)data);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000169 list->output(offset, p, OUT_RAWDATA + 2);
170 }
171 }
172 } else if ((type & OUT_TYPMASK) == OUT_RAWDATA) {
173 list->output(offset, data, type);
174 } else if ((type & OUT_TYPMASK) == OUT_RESERVE) {
175 list->output(offset, NULL, type);
176 } else if ((type & OUT_TYPMASK) == OUT_REL2ADR ||
177 (type & OUT_TYPMASK) == OUT_REL4ADR) {
178 list->output(offset, data, type);
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000179 }
180
Frank Kotlerabebb082003-09-06 04:45:37 +0000181 /*
182 * this call to src_get determines when we call the
183 * debug-format-specific "linenum" function
184 * it updates lineno and lnfname to the current values
185 * returning 0 if "same as last time", -2 if lnfname
186 * changed, and the amount by which lineno changed,
187 * if it did. thus, these variables must be static
188 */
189
H. Peter Anvine2c80182005-01-15 22:15:51 +0000190 if (src_get(&lineno, &lnfname)) {
191 outfmt->current_dfmt->linenum(lnfname, lineno, segto);
H. Peter Anvince616072002-04-30 21:02:23 +0000192 }
H. Peter Anvineba20a72002-04-30 20:53:55 +0000193
H. Peter Anvine2c80182005-01-15 22:15:51 +0000194 outfmt->output(segto, data, type, segment, wrt);
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000195}
196
Keith Kaniosb7a89542007-04-12 02:40:54 +0000197static int jmp_match(int32_t segment, int32_t offset, int bits,
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000198 insn * ins, const char *code)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000199{
Keith Kaniosb7a89542007-04-12 02:40:54 +0000200 int32_t isize;
201 uint8_t c = code[0];
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000202
H. Peter Anvine2c80182005-01-15 22:15:51 +0000203 if (c != 0370 && c != 0371)
204 return 0;
H. Peter Anvin788e6c12002-04-30 21:02:01 +0000205 if (ins->oprs[0].opflags & OPFLAG_FORWARD) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000206 if ((optimizing < 0 || (ins->oprs[0].type & STRICT))
207 && c == 0370)
208 return 1;
209 else
210 return (pass0 == 0); /* match a forward reference */
H. Peter Anvin788e6c12002-04-30 21:02:01 +0000211 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000212 isize = calcsize(segment, offset, bits, ins, code);
213 if (ins->oprs[0].segment != segment)
214 return 0;
215 isize = ins->oprs[0].offset - offset - isize; /* isize is now the delta */
216 if (isize >= -128L && isize <= 127L)
217 return 1; /* it is byte size */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000218
219 return 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000220}
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000221
Keith Kaniosb7a89542007-04-12 02:40:54 +0000222int32_t assemble(int32_t segment, int32_t offset, int bits, uint32_t cp,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000223 insn * instruction, struct ofmt *output, efunc error,
224 ListGen * listgen)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000225{
H. Peter Anvin3360d792007-09-11 04:16:57 +0000226 const struct itemplate *temp;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000227 int j;
228 int size_prob;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000229 int32_t insn_end;
230 int32_t itimes;
231 int32_t start = offset;
232 int32_t wsize = 0; /* size for DB etc. */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000233
H. Peter Anvine2c80182005-01-15 22:15:51 +0000234 errfunc = error; /* to pass to other functions */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000235 cpu = cp;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000236 outfmt = output; /* likewise */
237 list = listgen; /* and again */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000238
H. Peter Anvine2c80182005-01-15 22:15:51 +0000239 switch (instruction->opcode) {
240 case -1:
241 return 0;
242 case I_DB:
243 wsize = 1;
244 break;
245 case I_DW:
246 wsize = 2;
247 break;
248 case I_DD:
249 wsize = 4;
250 break;
251 case I_DQ:
252 wsize = 8;
253 break;
254 case I_DT:
255 wsize = 10;
256 break;
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700257 case I_DO:
258 wsize = 16;
259 break;
H. Peter Anvin16b0a332007-09-12 20:27:41 -0700260 default:
261 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000262 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000263
H. Peter Anvineba20a72002-04-30 20:53:55 +0000264 if (wsize) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000265 extop *e;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000266 int32_t t = instruction->times;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000267 if (t < 0)
268 errfunc(ERR_PANIC,
269 "instruction->times < 0 (%ld) in assemble()", t);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000270
H. Peter Anvine2c80182005-01-15 22:15:51 +0000271 while (t--) { /* repeat TIMES times */
272 for (e = instruction->eops; e; e = e->next) {
273 if (e->type == EOT_DB_NUMBER) {
274 if (wsize == 1) {
275 if (e->segment != NO_SEG)
276 errfunc(ERR_NONFATAL,
277 "one-byte relocation attempted");
278 else {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000279 uint8_t out_byte = e->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000280 out(offset, segment, &out_byte,
281 OUT_RAWDATA + 1, NO_SEG, NO_SEG);
282 }
Keith Kanios61ff53c2007-04-14 18:54:52 +0000283 } else if (wsize > 8) {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700284 errfunc(ERR_NONFATAL, "integer supplied to a DT or DO"
Keith Kanios61ff53c2007-04-14 18:54:52 +0000285 " instruction");
H. Peter Anvine2c80182005-01-15 22:15:51 +0000286 } else
287 out(offset, segment, &e->offset,
288 OUT_ADDRESS + wsize, e->segment, e->wrt);
289 offset += wsize;
290 } else if (e->type == EOT_DB_STRING) {
291 int align;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000292
H. Peter Anvine2c80182005-01-15 22:15:51 +0000293 out(offset, segment, e->stringval,
294 OUT_RAWDATA + e->stringlen, NO_SEG, NO_SEG);
295 align = e->stringlen % wsize;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000296
H. Peter Anvine2c80182005-01-15 22:15:51 +0000297 if (align) {
298 align = wsize - align;
299 out(offset, segment, "\0\0\0\0\0\0\0\0",
300 OUT_RAWDATA + align, NO_SEG, NO_SEG);
301 }
302 offset += e->stringlen + align;
303 }
304 }
305 if (t > 0 && t == instruction->times - 1) {
306 /*
307 * Dummy call to list->output to give the offset to the
308 * listing module.
309 */
310 list->output(offset, NULL, OUT_RAWDATA);
311 list->uplevel(LIST_TIMES);
312 }
313 }
314 if (instruction->times > 1)
315 list->downlevel(LIST_TIMES);
316 return offset - start;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000317 }
318
H. Peter Anvine2c80182005-01-15 22:15:51 +0000319 if (instruction->opcode == I_INCBIN) {
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000320 static char fname[FILENAME_MAX];
H. Peter Anvine2c80182005-01-15 22:15:51 +0000321 FILE *fp;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000322 int32_t len;
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000323 char *prefix = "", *combine;
324 char **pPrevPath = NULL;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000325
H. Peter Anvine2c80182005-01-15 22:15:51 +0000326 len = FILENAME_MAX - 1;
327 if (len > instruction->eops->stringlen)
328 len = instruction->eops->stringlen;
329 strncpy(fname, instruction->eops->stringval, len);
330 fname[len] = '\0';
H. Peter Anvineba20a72002-04-30 20:53:55 +0000331
Keith Kaniosb7a89542007-04-12 02:40:54 +0000332 while (1) { /* added by alexfru: 'incbin' uses include paths */
H. Peter Anvine2c80182005-01-15 22:15:51 +0000333 combine = nasm_malloc(strlen(prefix) + len + 1);
334 strcpy(combine, prefix);
335 strcat(combine, fname);
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000336
H. Peter Anvine2c80182005-01-15 22:15:51 +0000337 if ((fp = fopen(combine, "rb")) != NULL) {
338 nasm_free(combine);
339 break;
340 }
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000341
H. Peter Anvine2c80182005-01-15 22:15:51 +0000342 nasm_free(combine);
343 pPrevPath = pp_get_include_path_ptr(pPrevPath);
344 if (pPrevPath == NULL)
345 break;
346 prefix = *pPrevPath;
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000347 }
348
349 if (fp == NULL)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000350 error(ERR_NONFATAL, "`incbin': unable to open file `%s'",
351 fname);
352 else if (fseek(fp, 0L, SEEK_END) < 0)
353 error(ERR_NONFATAL, "`incbin': unable to seek on file `%s'",
354 fname);
355 else {
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000356 static char buf[2048];
Keith Kaniosb7a89542007-04-12 02:40:54 +0000357 int32_t t = instruction->times;
358 int32_t base = 0;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000359
H. Peter Anvine2c80182005-01-15 22:15:51 +0000360 len = ftell(fp);
361 if (instruction->eops->next) {
362 base = instruction->eops->next->offset;
363 len -= base;
364 if (instruction->eops->next->next &&
365 len > instruction->eops->next->next->offset)
366 len = instruction->eops->next->next->offset;
367 }
368 /*
369 * Dummy call to list->output to give the offset to the
370 * listing module.
371 */
372 list->output(offset, NULL, OUT_RAWDATA);
373 list->uplevel(LIST_INCBIN);
374 while (t--) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000375 int32_t l;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000376
H. Peter Anvine2c80182005-01-15 22:15:51 +0000377 fseek(fp, base, SEEK_SET);
378 l = len;
379 while (l > 0) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000380 int32_t m =
Charles Crayne192d5b52007-10-18 19:02:42 -0700381 fread(buf, 1, (l > (int32_t) sizeof(buf) ? (int32_t) sizeof(buf) : l),
H. Peter Anvine2c80182005-01-15 22:15:51 +0000382 fp);
383 if (!m) {
384 /*
385 * This shouldn't happen unless the file
386 * actually changes while we are reading
387 * it.
388 */
389 error(ERR_NONFATAL,
390 "`incbin': unexpected EOF while"
391 " reading file `%s'", fname);
392 t = 0; /* Try to exit cleanly */
393 break;
394 }
395 out(offset, segment, buf, OUT_RAWDATA + m,
396 NO_SEG, NO_SEG);
397 l -= m;
398 }
399 }
400 list->downlevel(LIST_INCBIN);
401 if (instruction->times > 1) {
402 /*
403 * Dummy call to list->output to give the offset to the
404 * listing module.
405 */
406 list->output(offset, NULL, OUT_RAWDATA);
407 list->uplevel(LIST_TIMES);
408 list->downlevel(LIST_TIMES);
409 }
410 fclose(fp);
411 return instruction->times * len;
412 }
413 return 0; /* if we're here, there's an error */
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000414 }
415
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700416 /* Check to see if we need an address-size prefix */
417 add_asp(instruction, bits);
418
H. Peter Anvin6867acc2007-10-10 14:58:45 -0700419 size_prob = false;
H. Peter Anvin70653092007-10-19 14:42:29 -0700420
421 for (temp = nasm_instructions[instruction->opcode]; temp->opcode != -1; temp++){
Keith Kaniosb7a89542007-04-12 02:40:54 +0000422 int m = matches(temp, instruction, bits);
H. Peter Anvin70653092007-10-19 14:42:29 -0700423
H. Peter Anvine2c80182005-01-15 22:15:51 +0000424 if (m == 99)
425 m += jmp_match(segment, offset, bits, instruction, temp->code);
H. Peter Anvineba20a72002-04-30 20:53:55 +0000426
H. Peter Anvine2c80182005-01-15 22:15:51 +0000427 if (m == 100) { /* matches! */
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000428 const char *codes = temp->code;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000429 int32_t insn_size = calcsize(segment, offset, bits,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000430 instruction, codes);
431 itimes = instruction->times;
432 if (insn_size < 0) /* shouldn't be, on pass two */
433 error(ERR_PANIC, "errors made it through from pass one");
434 else
435 while (itimes--) {
436 for (j = 0; j < instruction->nprefix; j++) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000437 uint8_t c = 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000438 switch (instruction->prefixes[j]) {
439 case P_LOCK:
440 c = 0xF0;
441 break;
442 case P_REPNE:
443 case P_REPNZ:
444 c = 0xF2;
445 break;
446 case P_REPE:
447 case P_REPZ:
448 case P_REP:
449 c = 0xF3;
450 break;
451 case R_CS:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000452 if (bits == 64) {
453 error(ERR_WARNING,
454 "cs segment base ignored in 64-bit mode");
455 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000456 c = 0x2E;
457 break;
458 case R_DS:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000459 if (bits == 64) {
460 error(ERR_WARNING,
461 "ds segment base ignored in 64-bit mode");
462 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000463 c = 0x3E;
464 break;
465 case R_ES:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000466 if (bits == 64) {
467 error(ERR_WARNING,
468 "es segment base ignored in 64-bit mode");
469 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000470 c = 0x26;
471 break;
472 case R_FS:
473 c = 0x64;
474 break;
475 case R_GS:
476 c = 0x65;
477 break;
478 case R_SS:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000479 if (bits == 64) {
480 error(ERR_WARNING,
481 "ss segment base ignored in 64-bit mode");
482 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000483 c = 0x36;
484 break;
485 case R_SEGR6:
486 case R_SEGR7:
487 error(ERR_NONFATAL,
488 "segr6 and segr7 cannot be used as prefixes");
489 break;
490 case P_A16:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000491 if (bits == 64) {
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000492 error(ERR_NONFATAL,
493 "16-bit addressing is not supported "
494 "in 64-bit mode");
Keith Kaniosb7a89542007-04-12 02:40:54 +0000495 break;
496 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000497 if (bits != 16)
498 c = 0x67;
499 break;
500 case P_A32:
501 if (bits != 32)
502 c = 0x67;
503 break;
504 case P_O16:
505 if (bits != 16)
506 c = 0x66;
507 break;
508 case P_O32:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000509 if (bits == 16)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000510 c = 0x66;
511 break;
512 default:
513 error(ERR_PANIC, "invalid instruction prefix");
514 }
515 if (c != 0) {
516 out(offset, segment, &c, OUT_RAWDATA + 1,
517 NO_SEG, NO_SEG);
518 offset++;
519 }
H. Peter Anvin70653092007-10-19 14:42:29 -0700520 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000521 insn_end = offset + insn_size;
522 gencode(segment, offset, bits, instruction, codes,
523 insn_end);
524 offset += insn_size;
525 if (itimes > 0 && itimes == instruction->times - 1) {
526 /*
527 * Dummy call to list->output to give the offset to the
528 * listing module.
529 */
530 list->output(offset, NULL, OUT_RAWDATA);
531 list->uplevel(LIST_TIMES);
532 }
533 }
534 if (instruction->times > 1)
535 list->downlevel(LIST_TIMES);
536 return offset - start;
537 } else if (m > 0 && m > size_prob) {
538 size_prob = m;
539 }
Keith Kaniosb7a89542007-04-12 02:40:54 +0000540// temp++;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000541 }
H. Peter Anvineba20a72002-04-30 20:53:55 +0000542
H. Peter Anvine2c80182005-01-15 22:15:51 +0000543 if (temp->opcode == -1) { /* didn't match any instruction */
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000544 switch (size_prob) {
545 case 1:
546 error(ERR_NONFATAL, "operation size not specified");
547 break;
548 case 2:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000549 error(ERR_NONFATAL, "mismatch in operand sizes");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000550 break;
551 case 3:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000552 error(ERR_NONFATAL, "no instruction for this cpu level");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000553 break;
554 case 4:
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000555 error(ERR_NONFATAL, "instruction not supported in 64-bit mode");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000556 break;
557 default:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000558 error(ERR_NONFATAL,
559 "invalid combination of opcode and operands");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000560 break;
561 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000562 }
563 return 0;
564}
565
Keith Kaniosb7a89542007-04-12 02:40:54 +0000566int32_t insn_size(int32_t segment, int32_t offset, int bits, uint32_t cp,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000567 insn * instruction, efunc error)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000568{
H. Peter Anvin3360d792007-09-11 04:16:57 +0000569 const struct itemplate *temp;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000570
H. Peter Anvine2c80182005-01-15 22:15:51 +0000571 errfunc = error; /* to pass to other functions */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000572 cpu = cp;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000573
574 if (instruction->opcode == -1)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000575 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000576
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700577 if (instruction->opcode == I_DB || instruction->opcode == I_DW ||
578 instruction->opcode == I_DD || instruction->opcode == I_DQ ||
579 instruction->opcode == I_DT || instruction->opcode == I_DO) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000580 extop *e;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000581 int32_t isize, osize, wsize = 0; /* placate gcc */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000582
H. Peter Anvine2c80182005-01-15 22:15:51 +0000583 isize = 0;
584 switch (instruction->opcode) {
585 case I_DB:
586 wsize = 1;
587 break;
588 case I_DW:
589 wsize = 2;
590 break;
591 case I_DD:
592 wsize = 4;
593 break;
594 case I_DQ:
595 wsize = 8;
596 break;
597 case I_DT:
598 wsize = 10;
599 break;
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700600 case I_DO:
601 wsize = 16;
602 break;
H. Peter Anvin16b0a332007-09-12 20:27:41 -0700603 default:
604 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000605 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000606
H. Peter Anvine2c80182005-01-15 22:15:51 +0000607 for (e = instruction->eops; e; e = e->next) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000608 int32_t align;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000609
H. Peter Anvine2c80182005-01-15 22:15:51 +0000610 osize = 0;
611 if (e->type == EOT_DB_NUMBER)
612 osize = 1;
613 else if (e->type == EOT_DB_STRING)
614 osize = e->stringlen;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000615
H. Peter Anvine2c80182005-01-15 22:15:51 +0000616 align = (-osize) % wsize;
617 if (align < 0)
618 align += wsize;
619 isize += osize + align;
620 }
621 return isize * instruction->times;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000622 }
623
H. Peter Anvine2c80182005-01-15 22:15:51 +0000624 if (instruction->opcode == I_INCBIN) {
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000625 char fname[FILENAME_MAX];
H. Peter Anvine2c80182005-01-15 22:15:51 +0000626 FILE *fp;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000627 int32_t len;
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000628 char *prefix = "", *combine;
629 char **pPrevPath = NULL;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000630
H. Peter Anvine2c80182005-01-15 22:15:51 +0000631 len = FILENAME_MAX - 1;
632 if (len > instruction->eops->stringlen)
633 len = instruction->eops->stringlen;
634 strncpy(fname, instruction->eops->stringval, len);
635 fname[len] = '\0';
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000636
H. Peter Anvine2c80182005-01-15 22:15:51 +0000637 while (1) { /* added by alexfru: 'incbin' uses include paths */
638 combine = nasm_malloc(strlen(prefix) + len + 1);
639 strcpy(combine, prefix);
640 strcat(combine, fname);
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000641
H. Peter Anvine2c80182005-01-15 22:15:51 +0000642 if ((fp = fopen(combine, "rb")) != NULL) {
643 nasm_free(combine);
644 break;
645 }
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000646
H. Peter Anvine2c80182005-01-15 22:15:51 +0000647 nasm_free(combine);
648 pPrevPath = pp_get_include_path_ptr(pPrevPath);
649 if (pPrevPath == NULL)
650 break;
651 prefix = *pPrevPath;
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000652 }
653
654 if (fp == NULL)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000655 error(ERR_NONFATAL, "`incbin': unable to open file `%s'",
656 fname);
657 else if (fseek(fp, 0L, SEEK_END) < 0)
658 error(ERR_NONFATAL, "`incbin': unable to seek on file `%s'",
659 fname);
660 else {
661 len = ftell(fp);
662 fclose(fp);
663 if (instruction->eops->next) {
664 len -= instruction->eops->next->offset;
665 if (instruction->eops->next->next &&
666 len > instruction->eops->next->next->offset) {
667 len = instruction->eops->next->next->offset;
668 }
669 }
670 return instruction->times * len;
671 }
672 return 0; /* if we're here, there's an error */
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000673 }
674
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700675 /* Check to see if we need an address-size prefix */
676 add_asp(instruction, bits);
677
Keith Kaniosb7a89542007-04-12 02:40:54 +0000678 for (temp = nasm_instructions[instruction->opcode]; temp->opcode != -1; temp++) {
679 int m = matches(temp, instruction, bits);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000680 if (m == 99)
681 m += jmp_match(segment, offset, bits, instruction, temp->code);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000682
H. Peter Anvine2c80182005-01-15 22:15:51 +0000683 if (m == 100) {
684 /* we've matched an instruction. */
Keith Kaniosb7a89542007-04-12 02:40:54 +0000685 int32_t isize;
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000686 const char *codes = temp->code;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000687 int j;
688
689 isize = calcsize(segment, offset, bits, instruction, codes);
690 if (isize < 0)
691 return -1;
692 for (j = 0; j < instruction->nprefix; j++) {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700693 switch (instruction->prefixes[j]) {
694 case P_A16:
695 if (bits != 16)
696 isize++;
697 break;
698 case P_A32:
699 if (bits != 32)
700 isize++;
701 break;
702 case P_O16:
703 if (bits != 16)
704 isize++;
705 break;
706 case P_O32:
707 if (bits == 16)
708 isize++;
709 break;
710 default:
711 isize++;
712 break;
713 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000714 }
715 return isize * instruction->times;
716 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000717 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000718 return -1; /* didn't match any instruction */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000719}
720
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000721/* check that opn[op] is a signed byte of size 16 or 32,
722 and return the signed value*/
H. Peter Anvine2c80182005-01-15 22:15:51 +0000723static int is_sbyte(insn * ins, int op, int size)
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000724{
Keith Kaniosb7a89542007-04-12 02:40:54 +0000725 int32_t v;
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000726 int ret;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000727
728 ret = !(ins->forw_ref && ins->oprs[op].opflags) && /* dead in the water on forward reference or External */
729 optimizing >= 0 &&
730 !(ins->oprs[op].type & STRICT) &&
731 ins->oprs[op].wrt == NO_SEG && ins->oprs[op].segment == NO_SEG;
H. Peter Anvin734b1882002-04-30 21:01:08 +0000732
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000733 v = ins->oprs[op].offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000734 if (size == 16)
Keith Kaniosb7a89542007-04-12 02:40:54 +0000735 v = (int16_t)v; /* sign extend if 16 bits */
H. Peter Anvine2c80182005-01-15 22:15:51 +0000736
737 return ret && v >= -128L && v <= 127L;
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000738}
739
Keith Kaniosb7a89542007-04-12 02:40:54 +0000740static int32_t calcsize(int32_t segment, int32_t offset, int bits,
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000741 insn * ins, const char *codes)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000742{
Keith Kaniosb7a89542007-04-12 02:40:54 +0000743 int32_t length = 0;
744 uint8_t c;
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000745 int rex_mask = ~0;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +0000746 ins->rex = 0; /* Ensure REX is reset */
H. Peter Anvineba20a72002-04-30 20:53:55 +0000747
H. Peter Anvine2c80182005-01-15 22:15:51 +0000748 (void)segment; /* Don't warn that this parameter is unused */
749 (void)offset; /* Don't warn that this parameter is unused */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000750
H. Peter Anvine2c80182005-01-15 22:15:51 +0000751 while (*codes)
752 switch (c = *codes++) {
753 case 01:
754 case 02:
755 case 03:
756 codes += c, length += c;
757 break;
758 case 04:
759 case 05:
760 case 06:
761 case 07:
762 length++;
763 break;
764 case 010:
765 case 011:
766 case 012:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700767 case 013:
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000768 ins->rex |=
769 op_rexflags(&ins->oprs[c - 010], REX_B|REX_H|REX_P|REX_W);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000770 codes++, length++;
771 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000772 case 014:
773 case 015:
774 case 016:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700775 case 017:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000776 length++;
777 break;
778 case 020:
779 case 021:
780 case 022:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700781 case 023:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000782 length++;
783 break;
784 case 024:
785 case 025:
786 case 026:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700787 case 027:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000788 length++;
789 break;
790 case 030:
791 case 031:
792 case 032:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700793 case 033:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000794 length += 2;
795 break;
796 case 034:
797 case 035:
798 case 036:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700799 case 037:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000800 if (ins->oprs[c - 034].type & (BITS16 | BITS32 | BITS64))
H. Peter Anvine2c80182005-01-15 22:15:51 +0000801 length += (ins->oprs[c - 034].type & BITS16) ? 2 : 4;
802 else
803 length += (bits == 16) ? 2 : 4;
804 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000805 case 040:
806 case 041:
807 case 042:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700808 case 043:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000809 length += 4;
810 break;
811 case 044:
812 case 045:
813 case 046:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700814 case 047:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000815 length += ((ins->oprs[c - 044].addr_size ?
Keith Kaniosb7a89542007-04-12 02:40:54 +0000816 ins->oprs[c - 044].addr_size : bits) >> 3);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000817 break;
818 case 050:
819 case 051:
820 case 052:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700821 case 053:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000822 length++;
823 break;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000824 case 054:
825 case 055:
826 case 056:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700827 case 057:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000828 length += 8; /* MOV reg64/imm */
829 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000830 case 060:
831 case 061:
832 case 062:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700833 case 063:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000834 length += 2;
835 break;
836 case 064:
837 case 065:
838 case 066:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700839 case 067:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000840 if (ins->oprs[c - 064].type & (BITS16 | BITS32 | BITS64))
H. Peter Anvine2c80182005-01-15 22:15:51 +0000841 length += (ins->oprs[c - 064].type & BITS16) ? 2 : 4;
842 else
843 length += (bits == 16) ? 2 : 4;
844 break;
845 case 070:
846 case 071:
847 case 072:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700848 case 073:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000849 length += 4;
850 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700851 case 074:
852 case 075:
853 case 076:
854 case 077:
855 length += 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000856 break;
857 case 0140:
858 case 0141:
859 case 0142:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700860 case 0143:
861 length += is_sbyte(ins, c - 0140, 16) ? 1 : 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000862 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000863 case 0144:
864 case 0145:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700865 case 0146:
866 case 0147:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000867 codes += 2;
868 length++;
869 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700870 case 0150:
871 case 0151:
872 case 0152:
873 case 0153:
874 length += is_sbyte(ins, c - 0150, 32) ? 1 : 4;
875 break;
876 case 0154:
877 case 0155:
878 case 0156:
879 case 0157:
880 codes += 2;
881 length++;
882 break;
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700883 case 0160:
884 case 0161:
885 case 0162:
886 case 0163:
887 length++;
888 ins->rex |= REX_D;
H. Peter Anvincf5180a2007-09-17 17:25:27 -0700889 ins->drexdst = regval(&ins->oprs[c & 3]);
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700890 break;
891 case 0164:
892 case 0165:
893 case 0166:
894 case 0167:
895 length++;
896 ins->rex |= REX_D|REX_OC;
H. Peter Anvincf5180a2007-09-17 17:25:27 -0700897 ins->drexdst = regval(&ins->oprs[c & 3]);
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700898 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700899 case 0170:
900 length++;
901 break;
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700902 case 0171:
903 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000904 case 0300:
905 case 0301:
H. Peter Anvin70653092007-10-19 14:42:29 -0700906 case 0302:
907 case 0303:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000908 break;
909 case 0310:
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700910 if (bits == 64)
911 return -1;
912 length += (bits != 16) && !has_prefix(ins,P_A16);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000913 break;
914 case 0311:
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700915 length += (bits != 32) && !has_prefix(ins,P_A32);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000916 break;
917 case 0312:
H. Peter Anvin70653092007-10-19 14:42:29 -0700918 break;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000919 case 0313:
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700920 if (bits != 64 || has_prefix(ins,P_A16) || has_prefix(ins,P_A32))
921 return -1;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000922 break;
923 case 0320:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000924 length += (bits != 16);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000925 break;
926 case 0321:
927 length += (bits == 16);
928 break;
929 case 0322:
930 break;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000931 case 0323:
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000932 rex_mask &= ~REX_W;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000933 break;
934 case 0324:
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000935 ins->rex |= REX_W;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +0000936 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000937 case 0330:
938 codes++, length++;
939 break;
940 case 0331:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000941 break;
H. Peter Anvincb9b6902007-09-12 21:58:51 -0700942 case 0332:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000943 case 0333:
944 length++;
945 break;
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000946 case 0334:
947 assert_no_prefix(ins, P_LOCK);
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000948 ins->rex |= REX_L;
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000949 break;
H. Peter Anvincb9b6902007-09-12 21:58:51 -0700950 case 0335:
951 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000952 case 0340:
953 case 0341:
954 case 0342:
955 if (ins->oprs[0].segment != NO_SEG)
956 errfunc(ERR_NONFATAL, "attempt to reserve non-constant"
957 " quantity of BSS space");
958 else
959 length += ins->oprs[0].offset << (c - 0340);
960 break;
H. Peter Anvin62cb6062007-09-11 22:44:03 +0000961 case 0364:
962 case 0365:
963 break;
Keith Kanios48af1772007-08-17 07:37:52 +0000964 case 0366:
H. Peter Anvin62cb6062007-09-11 22:44:03 +0000965 case 0367:
966 length++;
967 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000968 case 0370:
969 case 0371:
970 case 0372:
971 break;
972 case 0373:
973 length++;
974 break;
975 default: /* can't do it by 'case' statements */
976 if (c >= 0100 && c <= 0277) { /* it's an EA */
977 ea ea_data;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000978 int rfield;
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000979 int32_t rflags;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000980 ea_data.rex = 0; /* Ensure ea.REX is initially 0 */
H. Peter Anvin70653092007-10-19 14:42:29 -0700981
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000982 if (c <= 0177) {
983 /* pick rfield from operand b */
984 rflags = regflag(&ins->oprs[c & 7]);
985 rfield = regvals[ins->oprs[c & 7].basereg];
986 } else {
987 rflags = 0;
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000988 rfield = c & 7;
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000989 }
Keith Kaniosb7a89542007-04-12 02:40:54 +0000990
H. Peter Anvine2c80182005-01-15 22:15:51 +0000991 if (!process_ea
Keith Kaniosb7a89542007-04-12 02:40:54 +0000992 (&ins->oprs[(c >> 3) & 7], &ea_data, bits,
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000993 rfield, rflags, ins->forw_ref)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000994 errfunc(ERR_NONFATAL, "invalid effective address");
995 return -1;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000996 } else {
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000997 ins->rex |= ea_data.rex;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000998 length += ea_data.size;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000999 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001000 } else
1001 errfunc(ERR_PANIC, "internal instruction table corrupt"
1002 ": instruction code 0x%02X given", c);
1003 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001004
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001005 ins->rex &= rex_mask;
H. Peter Anvin70653092007-10-19 14:42:29 -07001006
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001007 if (ins->rex & REX_D) {
1008 if (ins->rex & REX_H) {
1009 errfunc(ERR_NONFATAL, "cannot use high register in drex instruction");
1010 return -1;
1011 }
H. Peter Anvincf5180a2007-09-17 17:25:27 -07001012 if (bits != 64 && ((ins->rex & (REX_W|REX_X|REX_B)) ||
1013 ins->drexdst > 7)) {
1014 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1015 return -1;
1016 }
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001017 length++;
1018 } else if (ins->rex & REX_REAL) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001019 if (ins->rex & REX_H) {
1020 errfunc(ERR_NONFATAL, "cannot use high register in rex instruction");
1021 return -1;
1022 } else if (bits == 64 ||
1023 ((ins->rex & REX_L) &&
1024 !(ins->rex & (REX_P|REX_W|REX_X|REX_B)) &&
1025 cpu >= IF_X86_64)) {
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001026 length++;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001027 } else {
H. Peter Anvincf5180a2007-09-17 17:25:27 -07001028 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1029 return -1;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001030 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00001031 }
1032
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001033 return length;
1034}
Keith Kaniosb7a89542007-04-12 02:40:54 +00001035
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001036#define EMIT_REX() \
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001037 if (!(ins->rex & REX_D) && (ins->rex & REX_REAL) && (bits == 64)) { \
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001038 ins->rex = (ins->rex & REX_REAL)|REX_P; \
1039 out(offset, segment, &ins->rex, OUT_RAWDATA+1, NO_SEG, NO_SEG); \
1040 ins->rex = 0; \
1041 offset += 1; \
1042 }
1043
Keith Kaniosb7a89542007-04-12 02:40:54 +00001044static void gencode(int32_t segment, int32_t offset, int bits,
Keith Kaniosa6dfa782007-04-13 16:47:53 +00001045 insn * ins, const char *codes, int32_t insn_end)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001046{
Keith Kaniosa6dfa782007-04-13 16:47:53 +00001047 static char condval[] = { /* conditional opcodes */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001048 0x7, 0x3, 0x2, 0x6, 0x2, 0x4, 0xF, 0xD, 0xC, 0xE, 0x6, 0x2,
1049 0x3, 0x7, 0x3, 0x5, 0xE, 0xC, 0xD, 0xF, 0x1, 0xB, 0x9, 0x5,
1050 0x0, 0xA, 0xA, 0xB, 0x8, 0x4
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001051 };
Keith Kaniosb7a89542007-04-12 02:40:54 +00001052 uint8_t c;
1053 uint8_t bytes[4];
1054 int32_t size;
1055 int64_t data;
H. Peter Anvin70653092007-10-19 14:42:29 -07001056
H. Peter Anvineba20a72002-04-30 20:53:55 +00001057 while (*codes)
H. Peter Anvine2c80182005-01-15 22:15:51 +00001058 switch (c = *codes++) {
1059 case 01:
1060 case 02:
1061 case 03:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001062 EMIT_REX();
H. Peter Anvine2c80182005-01-15 22:15:51 +00001063 out(offset, segment, codes, OUT_RAWDATA + c, NO_SEG, NO_SEG);
1064 codes += c;
1065 offset += c;
1066 break;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001067
H. Peter Anvine2c80182005-01-15 22:15:51 +00001068 case 04:
1069 case 06:
1070 switch (ins->oprs[0].basereg) {
1071 case R_CS:
1072 bytes[0] = 0x0E + (c == 0x04 ? 1 : 0);
1073 break;
1074 case R_DS:
1075 bytes[0] = 0x1E + (c == 0x04 ? 1 : 0);
1076 break;
1077 case R_ES:
1078 bytes[0] = 0x06 + (c == 0x04 ? 1 : 0);
1079 break;
1080 case R_SS:
1081 bytes[0] = 0x16 + (c == 0x04 ? 1 : 0);
1082 break;
1083 default:
1084 errfunc(ERR_PANIC,
1085 "bizarre 8086 segment register received");
1086 }
1087 out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG, NO_SEG);
1088 offset++;
1089 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001090
H. Peter Anvine2c80182005-01-15 22:15:51 +00001091 case 05:
1092 case 07:
1093 switch (ins->oprs[0].basereg) {
1094 case R_FS:
1095 bytes[0] = 0xA0 + (c == 0x05 ? 1 : 0);
1096 break;
1097 case R_GS:
1098 bytes[0] = 0xA8 + (c == 0x05 ? 1 : 0);
1099 break;
1100 default:
1101 errfunc(ERR_PANIC,
1102 "bizarre 386 segment register received");
1103 }
1104 out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG, NO_SEG);
1105 offset++;
1106 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001107
H. Peter Anvine2c80182005-01-15 22:15:51 +00001108 case 010:
1109 case 011:
1110 case 012:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001111 case 013:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001112 EMIT_REX();
Keith Kaniosb7a89542007-04-12 02:40:54 +00001113 bytes[0] = *codes++ + ((regval(&ins->oprs[c - 010])) & 7);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001114 out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG, NO_SEG);
1115 offset += 1;
1116 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001117
H. Peter Anvine2c80182005-01-15 22:15:51 +00001118 case 014:
1119 case 015:
1120 case 016:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001121 case 017:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001122 if (ins->oprs[c - 014].offset < -128
1123 || ins->oprs[c - 014].offset > 127) {
1124 errfunc(ERR_WARNING, "signed byte value exceeds bounds");
1125 }
H. Peter Anvineba20a72002-04-30 20:53:55 +00001126
H. Peter Anvine2c80182005-01-15 22:15:51 +00001127 if (ins->oprs[c - 014].segment != NO_SEG) {
1128 data = ins->oprs[c - 014].offset;
1129 out(offset, segment, &data, OUT_ADDRESS + 1,
1130 ins->oprs[c - 014].segment, ins->oprs[c - 014].wrt);
1131 } else {
1132 bytes[0] = ins->oprs[c - 014].offset;
1133 out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG,
1134 NO_SEG);
1135 }
1136 offset += 1;
1137 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001138
H. Peter Anvine2c80182005-01-15 22:15:51 +00001139 case 020:
1140 case 021:
1141 case 022:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001142 case 023:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001143 if (ins->oprs[c - 020].offset < -256
1144 || ins->oprs[c - 020].offset > 255) {
1145 errfunc(ERR_WARNING, "byte value exceeds bounds");
1146 }
1147 if (ins->oprs[c - 020].segment != NO_SEG) {
1148 data = ins->oprs[c - 020].offset;
1149 out(offset, segment, &data, OUT_ADDRESS + 1,
1150 ins->oprs[c - 020].segment, ins->oprs[c - 020].wrt);
1151 } else {
1152 bytes[0] = ins->oprs[c - 020].offset;
1153 out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG,
1154 NO_SEG);
1155 }
1156 offset += 1;
1157 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001158
H. Peter Anvine2c80182005-01-15 22:15:51 +00001159 case 024:
1160 case 025:
1161 case 026:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001162 case 027:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001163 if (ins->oprs[c - 024].offset < 0
1164 || ins->oprs[c - 024].offset > 255)
1165 errfunc(ERR_WARNING, "unsigned byte value exceeds bounds");
1166 if (ins->oprs[c - 024].segment != NO_SEG) {
1167 data = ins->oprs[c - 024].offset;
1168 out(offset, segment, &data, OUT_ADDRESS + 1,
1169 ins->oprs[c - 024].segment, ins->oprs[c - 024].wrt);
1170 } else {
1171 bytes[0] = ins->oprs[c - 024].offset;
1172 out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG,
1173 NO_SEG);
1174 }
1175 offset += 1;
1176 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001177
H. Peter Anvine2c80182005-01-15 22:15:51 +00001178 case 030:
1179 case 031:
1180 case 032:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001181 case 033:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001182 if (ins->oprs[c - 030].segment == NO_SEG &&
1183 ins->oprs[c - 030].wrt == NO_SEG &&
1184 (ins->oprs[c - 030].offset < -65536L ||
1185 ins->oprs[c - 030].offset > 65535L)) {
1186 errfunc(ERR_WARNING, "word value exceeds bounds");
1187 }
1188 data = ins->oprs[c - 030].offset;
1189 out(offset, segment, &data, OUT_ADDRESS + 2,
1190 ins->oprs[c - 030].segment, ins->oprs[c - 030].wrt);
1191 offset += 2;
1192 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001193
H. Peter Anvine2c80182005-01-15 22:15:51 +00001194 case 034:
1195 case 035:
1196 case 036:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001197 case 037:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001198 if (ins->oprs[c - 034].type & (BITS16 | BITS32))
1199 size = (ins->oprs[c - 034].type & BITS16) ? 2 : 4;
1200 else
1201 size = (bits == 16) ? 2 : 4;
1202 data = ins->oprs[c - 034].offset;
1203 if (size == 2 && (data < -65536L || data > 65535L))
1204 errfunc(ERR_WARNING, "word value exceeds bounds");
1205 out(offset, segment, &data, OUT_ADDRESS + size,
1206 ins->oprs[c - 034].segment, ins->oprs[c - 034].wrt);
1207 offset += size;
1208 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001209
H. Peter Anvine2c80182005-01-15 22:15:51 +00001210 case 040:
1211 case 041:
1212 case 042:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001213 case 043:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001214 data = ins->oprs[c - 040].offset;
1215 out(offset, segment, &data, OUT_ADDRESS + 4,
1216 ins->oprs[c - 040].segment, ins->oprs[c - 040].wrt);
1217 offset += 4;
1218 break;
H. Peter Anvin3ba46772002-05-27 23:19:35 +00001219
H. Peter Anvine2c80182005-01-15 22:15:51 +00001220 case 044:
1221 case 045:
1222 case 046:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001223 case 047:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001224 data = ins->oprs[c - 044].offset;
1225 size = ((ins->oprs[c - 044].addr_size ?
Keith Kaniosb7a89542007-04-12 02:40:54 +00001226 ins->oprs[c - 044].addr_size : bits) >> 3);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001227 if (size == 2 && (data < -65536L || data > 65535L))
1228 errfunc(ERR_WARNING, "word value exceeds bounds");
1229 out(offset, segment, &data, OUT_ADDRESS + size,
1230 ins->oprs[c - 044].segment, ins->oprs[c - 044].wrt);
1231 offset += size;
1232 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001233
H. Peter Anvine2c80182005-01-15 22:15:51 +00001234 case 050:
1235 case 051:
1236 case 052:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001237 case 053:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001238 if (ins->oprs[c - 050].segment != segment)
1239 errfunc(ERR_NONFATAL,
1240 "short relative jump outside segment");
1241 data = ins->oprs[c - 050].offset - insn_end;
1242 if (data > 127 || data < -128)
1243 errfunc(ERR_NONFATAL, "short jump is out of range");
1244 bytes[0] = data;
1245 out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG, NO_SEG);
1246 offset += 1;
1247 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001248
Keith Kaniosb7a89542007-04-12 02:40:54 +00001249 case 054:
1250 case 055:
1251 case 056:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001252 case 057:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001253 data = (int64_t)ins->oprs[c - 054].offset;
1254 out(offset, segment, &data, OUT_ADDRESS + 8,
1255 ins->oprs[c - 054].segment, ins->oprs[c - 054].wrt);
1256 offset += 8;
1257 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001258
H. Peter Anvine2c80182005-01-15 22:15:51 +00001259 case 060:
1260 case 061:
1261 case 062:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001262 case 063:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001263 if (ins->oprs[c - 060].segment != segment) {
1264 data = ins->oprs[c - 060].offset;
1265 out(offset, segment, &data,
1266 OUT_REL2ADR + insn_end - offset,
1267 ins->oprs[c - 060].segment, ins->oprs[c - 060].wrt);
1268 } else {
1269 data = ins->oprs[c - 060].offset - insn_end;
1270 out(offset, segment, &data,
1271 OUT_ADDRESS + 2, NO_SEG, NO_SEG);
1272 }
1273 offset += 2;
1274 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001275
H. Peter Anvine2c80182005-01-15 22:15:51 +00001276 case 064:
1277 case 065:
1278 case 066:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001279 case 067:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001280 if (ins->oprs[c - 064].type & (BITS16 | BITS32 | BITS64))
H. Peter Anvine2c80182005-01-15 22:15:51 +00001281 size = (ins->oprs[c - 064].type & BITS16) ? 2 : 4;
1282 else
1283 size = (bits == 16) ? 2 : 4;
1284 if (ins->oprs[c - 064].segment != segment) {
Keith Kaniosb7a89542007-04-12 02:40:54 +00001285 int32_t reltype = (size == 2 ? OUT_REL2ADR : OUT_REL4ADR);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001286 data = ins->oprs[c - 064].offset;
1287 out(offset, segment, &data, reltype + insn_end - offset,
1288 ins->oprs[c - 064].segment, ins->oprs[c - 064].wrt);
1289 } else {
1290 data = ins->oprs[c - 064].offset - insn_end;
1291 out(offset, segment, &data,
1292 OUT_ADDRESS + size, NO_SEG, NO_SEG);
1293 }
1294 offset += size;
1295 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001296
H. Peter Anvine2c80182005-01-15 22:15:51 +00001297 case 070:
1298 case 071:
1299 case 072:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001300 case 073:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001301 if (ins->oprs[c - 070].segment != segment) {
1302 data = ins->oprs[c - 070].offset;
1303 out(offset, segment, &data,
1304 OUT_REL4ADR + insn_end - offset,
1305 ins->oprs[c - 070].segment, ins->oprs[c - 070].wrt);
1306 } else {
1307 data = ins->oprs[c - 070].offset - insn_end;
1308 out(offset, segment, &data,
1309 OUT_ADDRESS + 4, NO_SEG, NO_SEG);
1310 }
1311 offset += 4;
1312 break;
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001313
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001314 case 074:
1315 case 075:
1316 case 076:
1317 case 077:
1318 if (ins->oprs[c - 074].segment == NO_SEG)
1319 errfunc(ERR_NONFATAL, "value referenced by FAR is not"
1320 " relocatable");
1321 data = 0L;
1322 out(offset, segment, &data, OUT_ADDRESS + 2,
1323 outfmt->segbase(1 + ins->oprs[c - 074].segment),
1324 ins->oprs[c - 074].wrt);
1325 offset += 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001326 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001327
H. Peter Anvine2c80182005-01-15 22:15:51 +00001328 case 0140:
1329 case 0141:
1330 case 0142:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001331 case 0143:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001332 data = ins->oprs[c - 0140].offset;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001333 if (is_sbyte(ins, c - 0140, 16)) {
1334 bytes[0] = data;
1335 out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG,
1336 NO_SEG);
1337 offset++;
1338 } else {
1339 if (ins->oprs[c - 0140].segment == NO_SEG &&
1340 ins->oprs[c - 0140].wrt == NO_SEG &&
1341 (data < -65536L || data > 65535L)) {
1342 errfunc(ERR_WARNING, "word value exceeds bounds");
1343 }
1344 out(offset, segment, &data, OUT_ADDRESS + 2,
H. Peter Anvin8f94f982007-09-17 16:31:33 -07001345 ins->oprs[c - 0140].segment, ins->oprs[c - 0140].wrt);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001346 offset += 2;
1347 }
1348 break;
1349
1350 case 0144:
1351 case 0145:
1352 case 0146:
1353 case 0147:
1354 EMIT_REX();
1355 codes++;
1356 bytes[0] = *codes++;
1357 if (is_sbyte(ins, c - 0144, 16))
1358 bytes[0] |= 2; /* s-bit */
1359 out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG, NO_SEG);
1360 offset++;
1361 break;
1362
1363 case 0150:
1364 case 0151:
1365 case 0152:
1366 case 0153:
1367 data = ins->oprs[c - 0150].offset;
1368 if (is_sbyte(ins, c - 0150, 32)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001369 bytes[0] = data;
1370 out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG,
1371 NO_SEG);
1372 offset++;
1373 } else {
1374 out(offset, segment, &data, OUT_ADDRESS + 4,
H. Peter Anvin8f94f982007-09-17 16:31:33 -07001375 ins->oprs[c - 0150].segment, ins->oprs[c - 0150].wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001376 offset += 4;
1377 }
1378 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001379
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001380 case 0154:
1381 case 0155:
1382 case 0156:
1383 case 0157:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001384 EMIT_REX();
H. Peter Anvine2c80182005-01-15 22:15:51 +00001385 codes++;
1386 bytes[0] = *codes++;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001387 if (is_sbyte(ins, c - 0154, 32))
H. Peter Anvine2c80182005-01-15 22:15:51 +00001388 bytes[0] |= 2; /* s-bit */
1389 out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG, NO_SEG);
1390 offset++;
1391 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001392
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001393 case 0160:
1394 case 0161:
1395 case 0162:
1396 case 0163:
1397 case 0164:
1398 case 0165:
1399 case 0166:
1400 case 0167:
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001401 break;
1402
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001403 case 0170:
H. Peter Anvinc189b442007-10-05 17:04:32 -07001404 EMIT_REX();
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001405 bytes[0] = 0;
1406 out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG, NO_SEG);
1407 offset += 1;
1408 break;
1409
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001410 case 0171:
1411 bytes[0] =
1412 (ins->drexdst << 4) |
1413 (ins->rex & REX_OC ? 0x08 : 0) |
1414 (ins->rex & (REX_R|REX_X|REX_B));
1415 ins->rex = 0;
1416 out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG, NO_SEG);
1417 offset++;
1418 break;
1419
H. Peter Anvine2c80182005-01-15 22:15:51 +00001420 case 0300:
1421 case 0301:
1422 case 0302:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001423 case 0303:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001424 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001425
H. Peter Anvine2c80182005-01-15 22:15:51 +00001426 case 0310:
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07001427 if (bits == 32 && !has_prefix(ins,P_A16)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001428 *bytes = 0x67;
1429 out(offset, segment, bytes,
1430 OUT_RAWDATA + 1, NO_SEG, NO_SEG);
1431 offset += 1;
1432 } else
1433 offset += 0;
1434 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001435
H. Peter Anvine2c80182005-01-15 22:15:51 +00001436 case 0311:
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07001437 if (bits != 32 && !has_prefix(ins,P_A32)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001438 *bytes = 0x67;
1439 out(offset, segment, bytes,
1440 OUT_RAWDATA + 1, NO_SEG, NO_SEG);
1441 offset += 1;
1442 } else
1443 offset += 0;
1444 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001445
H. Peter Anvine2c80182005-01-15 22:15:51 +00001446 case 0312:
1447 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001448
Keith Kaniosb7a89542007-04-12 02:40:54 +00001449 case 0313:
1450 ins->rex = 0;
1451 break;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07001452
H. Peter Anvine2c80182005-01-15 22:15:51 +00001453 case 0320:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001454 if (bits != 16) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001455 *bytes = 0x66;
1456 out(offset, segment, bytes,
1457 OUT_RAWDATA + 1, NO_SEG, NO_SEG);
1458 offset += 1;
1459 } else
1460 offset += 0;
1461 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001462
H. Peter Anvine2c80182005-01-15 22:15:51 +00001463 case 0321:
1464 if (bits == 16) {
1465 *bytes = 0x66;
1466 out(offset, segment, bytes,
1467 OUT_RAWDATA + 1, NO_SEG, NO_SEG);
1468 offset += 1;
1469 } else
1470 offset += 0;
1471 break;
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001472
H. Peter Anvine2c80182005-01-15 22:15:51 +00001473 case 0322:
H. Peter Anvin70653092007-10-19 14:42:29 -07001474 case 0323:
1475 break;
1476
Keith Kaniosb7a89542007-04-12 02:40:54 +00001477 case 0324:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001478 ins->rex |= REX_W;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001479 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001480
H. Peter Anvine2c80182005-01-15 22:15:51 +00001481 case 0330:
1482 *bytes = *codes++ ^ condval[ins->condition];
1483 out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG, NO_SEG);
1484 offset += 1;
1485 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001486
H. Peter Anvine2c80182005-01-15 22:15:51 +00001487 case 0331:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001488 break;
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001489
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001490 case 0332:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001491 case 0333:
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001492 *bytes = c - 0332 + 0xF2;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001493 out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG, NO_SEG);
1494 offset += 1;
1495 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001496
Keith Kanios48af1772007-08-17 07:37:52 +00001497 case 0334:
1498 if (ins->rex & REX_R) {
1499 *bytes = 0xF0;
1500 out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG, NO_SEG);
1501 offset += 1;
1502 }
1503 ins->rex &= ~(REX_L|REX_R);
1504 break;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001505
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001506 case 0335:
1507 break;
1508
H. Peter Anvine2c80182005-01-15 22:15:51 +00001509 case 0340:
1510 case 0341:
1511 case 0342:
1512 if (ins->oprs[0].segment != NO_SEG)
1513 errfunc(ERR_PANIC, "non-constant BSS size in pass two");
1514 else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00001515 int32_t size = ins->oprs[0].offset << (c - 0340);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001516 if (size > 0)
1517 out(offset, segment, NULL,
1518 OUT_RESERVE + size, NO_SEG, NO_SEG);
1519 offset += size;
1520 }
1521 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001522
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001523 case 0364:
1524 case 0365:
1525 break;
1526
Keith Kanios48af1772007-08-17 07:37:52 +00001527 case 0366:
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001528 case 0367:
1529 *bytes = c - 0366 + 0x66;
Keith Kanios48af1772007-08-17 07:37:52 +00001530 out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG, NO_SEG);
1531 offset += 1;
1532 break;
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001533
H. Peter Anvine2c80182005-01-15 22:15:51 +00001534 case 0370:
1535 case 0371:
1536 case 0372:
1537 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001538
H. Peter Anvine2c80182005-01-15 22:15:51 +00001539 case 0373:
1540 *bytes = bits == 16 ? 3 : 5;
1541 out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG, NO_SEG);
1542 offset += 1;
1543 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001544
H. Peter Anvine2c80182005-01-15 22:15:51 +00001545 default: /* can't do it by 'case' statements */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001546 if (c >= 0100 && c <= 0277) { /* it's an EA */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001547 ea ea_data;
1548 int rfield;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001549 int32_t rflags;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001550 uint8_t *p;
1551 int32_t s;
H. Peter Anvin70653092007-10-19 14:42:29 -07001552
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001553 if (c <= 0177) {
1554 /* pick rfield from operand b */
1555 rflags = regflag(&ins->oprs[c & 7]);
1556 rfield = regvals[ins->oprs[c & 7].basereg];
1557 } else {
1558 /* rfield is constant */
1559 rflags = 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001560 rfield = c & 7;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001561 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001562
1563 if (!process_ea
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001564 (&ins->oprs[(c >> 3) & 7], &ea_data, bits,
1565 rfield, rflags, ins->forw_ref)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001566 errfunc(ERR_NONFATAL, "invalid effective address");
1567 }
H. Peter Anvin70653092007-10-19 14:42:29 -07001568
H. Peter Anvine2c80182005-01-15 22:15:51 +00001569 p = bytes;
1570 *p++ = ea_data.modrm;
1571 if (ea_data.sib_present)
1572 *p++ = ea_data.sib;
1573
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001574 /* DREX suffixes come between the SIB and the displacement */
1575 if (ins->rex & REX_D) {
1576 *p++ =
1577 (ins->drexdst << 4) |
1578 (ins->rex & REX_OC ? 0x08 : 0) |
1579 (ins->rex & (REX_R|REX_X|REX_B));
1580 ins->rex = 0;
1581 }
1582
H. Peter Anvine2c80182005-01-15 22:15:51 +00001583 s = p - bytes;
1584 out(offset, segment, bytes, OUT_RAWDATA + s,
1585 NO_SEG, NO_SEG);
1586
1587 switch (ea_data.bytes) {
1588 case 0:
1589 break;
1590 case 1:
1591 if (ins->oprs[(c >> 3) & 7].segment != NO_SEG) {
1592 data = ins->oprs[(c >> 3) & 7].offset;
1593 out(offset, segment, &data, OUT_ADDRESS + 1,
1594 ins->oprs[(c >> 3) & 7].segment,
1595 ins->oprs[(c >> 3) & 7].wrt);
1596 } else {
1597 *bytes = ins->oprs[(c >> 3) & 7].offset;
1598 out(offset, segment, bytes, OUT_RAWDATA + 1,
1599 NO_SEG, NO_SEG);
1600 }
1601 s++;
1602 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001603 case 8:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001604 case 2:
1605 case 4:
1606 data = ins->oprs[(c >> 3) & 7].offset;
H. Peter Anvind0b0d282007-09-28 17:17:20 -07001607 out(offset, segment, &data,
1608 (ea_data.rip ? OUT_REL4ADR : OUT_ADDRESS)
1609 + ea_data.bytes,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001610 ins->oprs[(c >> 3) & 7].segment,
1611 ins->oprs[(c >> 3) & 7].wrt);
1612 s += ea_data.bytes;
1613 break;
1614 }
1615 offset += s;
1616 } else
1617 errfunc(ERR_PANIC, "internal instruction table corrupt"
1618 ": instruction code 0x%02X given", c);
1619 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001620}
1621
H. Peter Anvin0ec60e62007-07-07 01:59:52 +00001622static int32_t regflag(const operand * o)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001623{
1624 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1625 errfunc(ERR_PANIC, "invalid operand passed to regflag()");
1626 }
1627 return reg_flags[o->basereg];
1628}
1629
H. Peter Anvin5b0e3ec2007-07-07 02:01:08 +00001630static int32_t regval(const operand * o)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001631{
H. Peter Anvine2c80182005-01-15 22:15:51 +00001632 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1633 errfunc(ERR_PANIC, "invalid operand passed to regval()");
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001634 }
H. Peter Anvin232badb2002-06-06 02:41:20 +00001635 return regvals[o->basereg];
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001636}
1637
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001638static int op_rexflags(const operand * o, int mask)
1639{
1640 int32_t flags;
1641 int val;
1642
1643 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1644 errfunc(ERR_PANIC, "invalid operand passed to op_rexflags()");
1645 }
1646
1647 flags = reg_flags[o->basereg];
1648 val = regvals[o->basereg];
1649
1650 return rexflags(val, flags, mask);
1651}
1652
1653static int rexflags(int val, int32_t flags, int mask)
1654{
1655 int rex = 0;
1656
1657 if (val >= 8)
1658 rex |= REX_B|REX_X|REX_R;
1659 if (flags & BITS64)
1660 rex |= REX_W;
1661 if (!(REG_HIGH & ~flags)) /* AH, CH, DH, BH */
1662 rex |= REX_H;
1663 else if (!(REG8 & ~flags) && val >= 4) /* SPL, BPL, SIL, DIL */
1664 rex |= REX_P;
1665
1666 return rex & mask;
1667}
1668
H. Peter Anvin3360d792007-09-11 04:16:57 +00001669static int matches(const struct itemplate *itemp, insn * instruction, int bits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001670{
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001671 int i, size[MAX_OPERANDS], asize, oprs, ret;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001672
1673 ret = 100;
1674
1675 /*
1676 * Check the opcode
1677 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001678 if (itemp->opcode != instruction->opcode)
1679 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001680
1681 /*
1682 * Count the operands
1683 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001684 if (itemp->operands != instruction->operands)
1685 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001686
1687 /*
1688 * Check that no spurious colons or TOs are present
1689 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001690 for (i = 0; i < itemp->operands; i++)
1691 if (instruction->oprs[i].type & ~itemp->opd[i] & (COLON | TO))
1692 return 0;
H. Peter Anvin70653092007-10-19 14:42:29 -07001693
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001694 /*
1695 * Check that the operand flags all match up
1696 */
H. Peter Anvin16b0a332007-09-12 20:27:41 -07001697 for (i = 0; i < itemp->operands; i++) {
H. Peter Anvincf5180a2007-09-17 17:25:27 -07001698 if (itemp->opd[i] & SAME_AS) {
1699 int j = itemp->opd[i] & ~SAME_AS;
1700 if (instruction->oprs[i].type != instruction->oprs[j].type ||
1701 instruction->oprs[i].basereg != instruction->oprs[j].basereg)
1702 return 0;
H. Peter Anvin457afd42007-09-25 15:41:19 -07001703 } else if (itemp->opd[i] & ~instruction->oprs[i].type ||
H. Peter Anvine2c80182005-01-15 22:15:51 +00001704 ((itemp->opd[i] & SIZE_MASK) &&
1705 ((itemp->opd[i] ^ instruction->oprs[i].type) & SIZE_MASK))) {
H. Peter Anvin5a640e12007-05-29 23:57:12 +00001706 if ((itemp->opd[i] & ~instruction->oprs[i].type & ~SIZE_MASK) ||
H. Peter Anvine2c80182005-01-15 22:15:51 +00001707 (instruction->oprs[i].type & SIZE_MASK))
1708 return 0;
1709 else
H. Peter Anvine2c80182005-01-15 22:15:51 +00001710 return 1;
1711 }
H. Peter Anvin16b0a332007-09-12 20:27:41 -07001712 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001713
1714 /*
1715 * Check operand sizes
1716 */
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001717 if (itemp->flags & IF_ARMASK) {
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001718 memset(size, 0, sizeof size);
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001719
H. Peter Anvine2c80182005-01-15 22:15:51 +00001720 switch (itemp->flags & IF_ARMASK) {
1721 case IF_AR0:
1722 i = 0;
1723 break;
1724 case IF_AR1:
1725 i = 1;
1726 break;
1727 case IF_AR2:
1728 i = 2;
1729 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001730 case IF_AR3:
1731 i = 3;
1732 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001733 default:
1734 break; /* Shouldn't happen */
1735 }
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001736 switch (itemp->flags & IF_SMASK) {
1737 case IF_SB:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001738 size[i] = BITS8;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001739 break;
1740 case IF_SW:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001741 size[i] = BITS16;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001742 break;
1743 case IF_SD:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001744 size[i] = BITS32;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001745 break;
1746 case IF_SQ:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001747 size[i] = BITS64;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001748 break;
H. Peter Anvin41c9f6f2007-09-18 13:01:32 -07001749 case IF_SO:
1750 size[i] = BITS128;
1751 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001752 default:
1753 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001754 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001755 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001756 asize = 0;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001757 switch (itemp->flags & IF_SMASK) {
1758 case IF_SB:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001759 asize = BITS8;
1760 oprs = itemp->operands;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001761 break;
1762 case IF_SW:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001763 asize = BITS16;
1764 oprs = itemp->operands;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001765 break;
1766 case IF_SD:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001767 asize = BITS32;
1768 oprs = itemp->operands;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001769 break;
1770 case IF_SQ:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001771 asize = BITS64;
1772 oprs = itemp->operands;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001773 break;
H. Peter Anvin41c9f6f2007-09-18 13:01:32 -07001774 case IF_SO:
1775 asize = BITS128;
1776 oprs = itemp->operands;
1777 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001778 default:
1779 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001780 }
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001781 for (i = 0; i < MAX_OPERANDS; i++)
1782 size[i] = asize;
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001783 }
H. Peter Anvin70653092007-10-19 14:42:29 -07001784
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001785 if (itemp->flags & (IF_SM | IF_SM2)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001786 oprs = (itemp->flags & IF_SM2 ? 2 : itemp->operands);
1787 asize = 0;
1788 for (i = 0; i < oprs; i++) {
1789 if ((asize = itemp->opd[i] & SIZE_MASK) != 0) {
1790 int j;
1791 for (j = 0; j < oprs; j++)
1792 size[j] = asize;
1793 break;
1794 }
1795 }
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001796 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001797 oprs = itemp->operands;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001798 }
1799
Keith Kaniosb7a89542007-04-12 02:40:54 +00001800 for (i = 0; i < itemp->operands; i++) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001801 if (!(itemp->opd[i] & SIZE_MASK) &&
1802 (instruction->oprs[i].type & SIZE_MASK & ~size[i]))
H. Peter Anvine2c80182005-01-15 22:15:51 +00001803 return 2;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001804 }
1805
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001806 /*
1807 * Check template is okay at the set cpu level
1808 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00001809 if (((itemp->flags & IF_PLEVEL) > cpu))
H. Peter Anvine2c80182005-01-15 22:15:51 +00001810 return 3;
H. Peter Anvin70653092007-10-19 14:42:29 -07001811
Keith Kaniosb7a89542007-04-12 02:40:54 +00001812 /*
1813 * Check if instruction is available in long mode
1814 */
1815 if ((itemp->flags & IF_NOLONG) && (bits == 64))
1816 return 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001817
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001818 /*
1819 * Check if special handling needed for Jumps
1820 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00001821 if ((uint8_t)(itemp->code[0]) >= 0370)
H. Peter Anvine2c80182005-01-15 22:15:51 +00001822 return 99;
1823
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001824 return ret;
1825}
1826
H. Peter Anvine2c80182005-01-15 22:15:51 +00001827static ea *process_ea(operand * input, ea * output, int addrbits,
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001828 int rfield, int32_t rflags, int forw_ref)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001829{
H. Peter Anvin6867acc2007-10-10 14:58:45 -07001830 output->rip = false;
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00001831
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001832 /* REX flags for the rfield operand */
1833 output->rex |= rexflags(rfield, rflags, REX_R|REX_P|REX_W|REX_H);
1834
Keith Kaniosb7a89542007-04-12 02:40:54 +00001835 if (!(REGISTER & ~input->type)) { /* register direct */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001836 int i;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001837 int32_t f;
1838
1839 if (input->basereg < EXPR_REG_START /* Verify as Register */
Keith Kaniosb7a89542007-04-12 02:40:54 +00001840 || input->basereg >= REG_ENUM_LIMIT)
H. Peter Anvine2c80182005-01-15 22:15:51 +00001841 return NULL;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001842 f = regflag(input);
Keith Kaniosb7a89542007-04-12 02:40:54 +00001843 i = regvals[input->basereg];
Keith Kaniosb7a89542007-04-12 02:40:54 +00001844
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001845 if (REG_EA & ~f)
1846 return NULL; /* Invalid EA register */
H. Peter Anvin70653092007-10-19 14:42:29 -07001847
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001848 output->rex |= op_rexflags(input, REX_B|REX_P|REX_W|REX_H);
1849
H. Peter Anvin6867acc2007-10-10 14:58:45 -07001850 output->sib_present = false; /* no SIB necessary */
Keith Kaniosb7a89542007-04-12 02:40:54 +00001851 output->bytes = 0; /* no offset necessary either */
1852 output->modrm = 0xC0 | ((rfield & 7) << 3) | (i & 7);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001853 } else { /* it's a memory reference */
1854 if (input->basereg == -1
1855 && (input->indexreg == -1 || input->scale == 0)) {
1856 /* it's a pure offset */
1857 if (input->addr_size)
1858 addrbits = input->addr_size;
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00001859
1860 if (globalbits == 64 && (~input->type & IP_REL)) {
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00001861 int scale, index, base;
H. Peter Anvin6867acc2007-10-10 14:58:45 -07001862 output->sib_present = true;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00001863 scale = 0;
1864 index = 4;
1865 base = 5;
1866 output->sib = (scale << 6) | (index << 3) | base;
1867 output->bytes = 4;
1868 output->modrm = 4 | ((rfield & 7) << 3);
H. Peter Anvin6867acc2007-10-10 14:58:45 -07001869 output->rip = false;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00001870 } else {
H. Peter Anvin6867acc2007-10-10 14:58:45 -07001871 output->sib_present = false;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00001872 output->bytes = (addrbits != 16 ? 4 : 2);
1873 output->modrm = (addrbits != 16 ? 5 : 6) | ((rfield & 7) << 3);
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00001874 output->rip = globalbits == 64;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00001875 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001876 } else { /* it's an indirection */
1877 int i = input->indexreg, b = input->basereg, s = input->scale;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001878 int32_t o = input->offset, seg = input->segment;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001879 int hb = input->hintbase, ht = input->hinttype;
1880 int t;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001881 int it, bt;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001882 int32_t ix, bx; /* register flags */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001883
H. Peter Anvine2c80182005-01-15 22:15:51 +00001884 if (s == 0)
1885 i = -1; /* make this easy, at least */
H. Peter Anvin70653092007-10-19 14:42:29 -07001886
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001887 if (i >= EXPR_REG_START && i < REG_ENUM_LIMIT) {
Keith Kaniosb7a89542007-04-12 02:40:54 +00001888 it = regvals[i];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001889 ix = reg_flags[i];
1890 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00001891 it = -1;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001892 ix = 0;
1893 }
H. Peter Anvin70653092007-10-19 14:42:29 -07001894
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001895 if (b != -1 && b >= EXPR_REG_START && b < REG_ENUM_LIMIT) {
Keith Kaniosb7a89542007-04-12 02:40:54 +00001896 bt = regvals[b];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001897 bx = reg_flags[b];
1898 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00001899 bt = -1;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001900 bx = 0;
1901 }
H. Peter Anvin70653092007-10-19 14:42:29 -07001902
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001903 /* check for a 32/64-bit memory reference... */
1904 if ((ix|bx) & (BITS32|BITS64)) {
Keith Kaniosb7a89542007-04-12 02:40:54 +00001905 /* it must be a 32/64-bit memory reference. Firstly we have
1906 * to check that all registers involved are type E/Rxx. */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001907 int32_t sok = BITS32|BITS64;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001908
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001909 if (it != -1) {
1910 if (!(REG64 & ~ix) || !(REG32 & ~ix))
1911 sok &= ix;
1912 else
1913 return NULL;
1914 }
1915
1916 if (bt != -1) {
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00001917 if (REG_GPR & ~bx)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001918 return NULL; /* Invalid register */
H. Peter Anvina57e8d42007-05-30 03:44:02 +00001919 if (~sok & bx & SIZE_MASK)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001920 return NULL; /* Invalid size */
1921 sok &= ~bx;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001922 }
H. Peter Anvin70653092007-10-19 14:42:29 -07001923
H. Peter Anvine2c80182005-01-15 22:15:51 +00001924 /* While we're here, ensure the user didn't specify WORD. */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001925 if (input->addr_size == 16 ||
1926 (input->addr_size == 32 && !(sok & BITS32)) ||
1927 (input->addr_size == 64 && !(sok & BITS64)))
H. Peter Anvine2c80182005-01-15 22:15:51 +00001928 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001929
Keith Kaniosb7a89542007-04-12 02:40:54 +00001930 /* now reorganize base/index */
1931 if (s == 1 && bt != it && bt != -1 && it != -1 &&
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001932 ((hb == b && ht == EAH_NOTBASE)
1933 || (hb == i && ht == EAH_MAKEBASE))) {
1934 /* swap if hints say so */
1935 t = bt, bt = it, it = t;
1936 t = bx, bx = ix, ix = t;
1937 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00001938 if (bt == it) /* convert EAX+2*EAX to 3*EAX */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001939 bt = -1, bx = 0, s++;
1940 if (bt == -1 && s == 1 && !(hb == it && ht == EAH_NOTBASE)) {
1941 /* make single reg base, unless hint */
1942 bt = it, bx = ix, it = -1, ix = 0;
1943 }
H. Peter Anvinf5843c62007-09-10 18:59:26 +00001944 if (((s == 2 && it != REG_NUM_ESP
H. Peter Anvine2c80182005-01-15 22:15:51 +00001945 && !(input->eaflags & EAF_TIMESTWO)) || s == 3
Keith Kaniosb7a89542007-04-12 02:40:54 +00001946 || s == 5 || s == 9) && bt == -1)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001947 bt = it, bx = ix, s--; /* convert 3*EAX to EAX+2*EAX */
Keith Kanios48af1772007-08-17 07:37:52 +00001948 if (it == -1 && (bt & 7) != REG_NUM_ESP
H. Peter Anvine2c80182005-01-15 22:15:51 +00001949 && (input->eaflags & EAF_TIMESTWO))
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001950 it = bt, ix = bx, bt = -1, bx = 0, s = 1;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001951 /* convert [NOSPLIT EAX] to sib format with 0x0 displacement */
Keith Kanios48af1772007-08-17 07:37:52 +00001952 if (s == 1 && it == REG_NUM_ESP) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001953 /* swap ESP into base if scale is 1 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00001954 t = it, it = bt, bt = t;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001955 t = ix, ix = bx, bx = t;
1956 }
Keith Kanios48af1772007-08-17 07:37:52 +00001957 if (it == REG_NUM_ESP
Keith Kaniosb7a89542007-04-12 02:40:54 +00001958 || (s != 1 && s != 2 && s != 4 && s != 8 && it != -1))
H. Peter Anvine2c80182005-01-15 22:15:51 +00001959 return NULL; /* wrong, for various reasons */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001960
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001961 output->rex |= rexflags(it, ix, REX_X);
1962 output->rex |= rexflags(bt, bx, REX_B);
Keith Kaniosb7a89542007-04-12 02:40:54 +00001963
Keith Kanios48af1772007-08-17 07:37:52 +00001964 if (it == -1 && (bt & 7) != REG_NUM_ESP) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001965 /* no SIB needed */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001966 int mod, rm;
H. Peter Anvin70653092007-10-19 14:42:29 -07001967
Keith Kaniosb7a89542007-04-12 02:40:54 +00001968 if (bt == -1) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001969 rm = 5;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001970 mod = 0;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001971 } else {
1972 rm = (bt & 7);
Keith Kanios48af1772007-08-17 07:37:52 +00001973 if (rm != REG_NUM_EBP && o == 0 &&
Keith Kaniosb7a89542007-04-12 02:40:54 +00001974 seg == NO_SEG && !forw_ref &&
1975 !(input->eaflags &
1976 (EAF_BYTEOFFS | EAF_WORDOFFS)))
1977 mod = 0;
1978 else if (input->eaflags & EAF_BYTEOFFS ||
1979 (o >= -128 && o <= 127 && seg == NO_SEG
1980 && !forw_ref
1981 && !(input->eaflags & EAF_WORDOFFS)))
1982 mod = 1;
1983 else
1984 mod = 2;
1985 }
H. Peter Anvinea838272002-04-30 20:51:53 +00001986
H. Peter Anvin6867acc2007-10-10 14:58:45 -07001987 output->sib_present = false;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001988 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
1989 output->modrm = (mod << 6) | ((rfield & 7) << 3) | rm;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001990 } else {
1991 /* we need a SIB */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001992 int mod, scale, index, base;
H. Peter Anvin70653092007-10-19 14:42:29 -07001993
Keith Kaniosb7a89542007-04-12 02:40:54 +00001994 if (it == -1)
1995 index = 4, s = 1;
1996 else
1997 index = (it & 7);
H. Peter Anvin70653092007-10-19 14:42:29 -07001998
H. Peter Anvine2c80182005-01-15 22:15:51 +00001999 switch (s) {
2000 case 1:
2001 scale = 0;
2002 break;
2003 case 2:
2004 scale = 1;
2005 break;
2006 case 4:
2007 scale = 2;
2008 break;
2009 case 8:
2010 scale = 3;
2011 break;
2012 default: /* then what the smeg is it? */
2013 return NULL; /* panic */
2014 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002015
Keith Kaniosb7a89542007-04-12 02:40:54 +00002016 if (bt == -1) {
2017 base = 5;
2018 mod = 0;
2019 } else {
2020 base = (bt & 7);
Keith Kanios48af1772007-08-17 07:37:52 +00002021 if (base != REG_NUM_EBP && o == 0 &&
H. Peter Anvine2c80182005-01-15 22:15:51 +00002022 seg == NO_SEG && !forw_ref &&
2023 !(input->eaflags &
Keith Kaniosb7a89542007-04-12 02:40:54 +00002024 (EAF_BYTEOFFS | EAF_WORDOFFS)))
2025 mod = 0;
2026 else if (input->eaflags & EAF_BYTEOFFS ||
2027 (o >= -128 && o <= 127 && seg == NO_SEG
2028 && !forw_ref
2029 && !(input->eaflags & EAF_WORDOFFS)))
2030 mod = 1;
2031 else
2032 mod = 2;
2033 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002034
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002035 output->sib_present = true;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002036 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2037 output->modrm = (mod << 6) | ((rfield & 7) << 3) | 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002038 output->sib = (scale << 6) | (index << 3) | base;
2039 }
2040 } else { /* it's 16-bit */
2041 int mod, rm;
H. Peter Anvin70653092007-10-19 14:42:29 -07002042
Keith Kaniosb7a89542007-04-12 02:40:54 +00002043 /* check for 64-bit long mode */
2044 if (addrbits == 64)
2045 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002046
H. Peter Anvine2c80182005-01-15 22:15:51 +00002047 /* check all registers are BX, BP, SI or DI */
2048 if ((b != -1 && b != R_BP && b != R_BX && b != R_SI
2049 && b != R_DI) || (i != -1 && i != R_BP && i != R_BX
2050 && i != R_SI && i != R_DI))
2051 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002052
Keith Kaniosb7a89542007-04-12 02:40:54 +00002053 /* ensure the user didn't specify DWORD/QWORD */
2054 if (input->addr_size == 32 || input->addr_size == 64)
H. Peter Anvine2c80182005-01-15 22:15:51 +00002055 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002056
H. Peter Anvine2c80182005-01-15 22:15:51 +00002057 if (s != 1 && i != -1)
2058 return NULL; /* no can do, in 16-bit EA */
2059 if (b == -1 && i != -1) {
2060 int tmp = b;
2061 b = i;
2062 i = tmp;
2063 } /* swap */
2064 if ((b == R_SI || b == R_DI) && i != -1) {
2065 int tmp = b;
2066 b = i;
2067 i = tmp;
2068 }
2069 /* have BX/BP as base, SI/DI index */
2070 if (b == i)
2071 return NULL; /* shouldn't ever happen, in theory */
2072 if (i != -1 && b != -1 &&
2073 (i == R_BP || i == R_BX || b == R_SI || b == R_DI))
2074 return NULL; /* invalid combinations */
2075 if (b == -1) /* pure offset: handled above */
2076 return NULL; /* so if it gets to here, panic! */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002077
H. Peter Anvine2c80182005-01-15 22:15:51 +00002078 rm = -1;
2079 if (i != -1)
2080 switch (i * 256 + b) {
2081 case R_SI * 256 + R_BX:
2082 rm = 0;
2083 break;
2084 case R_DI * 256 + R_BX:
2085 rm = 1;
2086 break;
2087 case R_SI * 256 + R_BP:
2088 rm = 2;
2089 break;
2090 case R_DI * 256 + R_BP:
2091 rm = 3;
2092 break;
2093 } else
2094 switch (b) {
2095 case R_SI:
2096 rm = 4;
2097 break;
2098 case R_DI:
2099 rm = 5;
2100 break;
2101 case R_BP:
2102 rm = 6;
2103 break;
2104 case R_BX:
2105 rm = 7;
2106 break;
2107 }
2108 if (rm == -1) /* can't happen, in theory */
2109 return NULL; /* so panic if it does */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002110
H. Peter Anvine2c80182005-01-15 22:15:51 +00002111 if (o == 0 && seg == NO_SEG && !forw_ref && rm != 6 &&
2112 !(input->eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS)))
2113 mod = 0;
2114 else if (input->eaflags & EAF_BYTEOFFS ||
2115 (o >= -128 && o <= 127 && seg == NO_SEG
2116 && !forw_ref
2117 && !(input->eaflags & EAF_WORDOFFS)))
2118 mod = 1;
2119 else
2120 mod = 2;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002121
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002122 output->sib_present = false; /* no SIB - it's 16-bit */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002123 output->bytes = mod; /* bytes of offset needed */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002124 output->modrm = (mod << 6) | ((rfield & 7) << 3) | rm;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002125 }
2126 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002127 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002128
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002129 output->size = 1 + output->sib_present + output->bytes;
2130 return output;
2131}
2132
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002133static void add_asp(insn *instruction, int addrbits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002134{
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002135 int j, valid;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002136
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002137 valid = (addrbits == 64) ? 64|32 : 32|16;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002138
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002139 for (j = 0; j < instruction->operands; j++) {
2140 if (!(MEMORY & ~instruction->oprs[j].type)) {
2141 int32_t i, b;
H. Peter Anvin70653092007-10-19 14:42:29 -07002142
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002143 /* Verify as Register */
2144 if (instruction->oprs[j].indexreg < EXPR_REG_START
2145 || instruction->oprs[j].indexreg >= REG_ENUM_LIMIT)
2146 i = 0;
2147 else
2148 i = reg_flags[instruction->oprs[j].indexreg];
H. Peter Anvin70653092007-10-19 14:42:29 -07002149
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002150 /* Verify as Register */
2151 if (instruction->oprs[j].basereg < EXPR_REG_START
2152 || instruction->oprs[j].basereg >= REG_ENUM_LIMIT)
2153 b = 0;
2154 else
2155 b = reg_flags[instruction->oprs[j].basereg];
H. Peter Anvin70653092007-10-19 14:42:29 -07002156
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002157 if (instruction->oprs[j].scale == 0)
2158 i = 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002159
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002160 if (!i && !b) {
2161 if (instruction->oprs[j].addr_size)
2162 valid &= instruction->oprs[j].addr_size;
2163 } else {
2164 if (!(REG16 & ~b))
2165 valid &= 16;
2166 if (!(REG32 & ~b))
2167 valid &= 32;
2168 if (!(REG64 & ~b))
2169 valid &= 64;
H. Peter Anvin70653092007-10-19 14:42:29 -07002170
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002171 if (!(REG16 & ~i))
2172 valid &= 16;
2173 if (!(REG32 & ~i))
2174 valid &= 32;
2175 if (!(REG64 & ~i))
2176 valid &= 64;
2177 }
2178 }
2179 }
2180
2181 if (valid & addrbits) {
2182 /* Don't do anything */
2183 } else if (valid & ((addrbits == 32) ? 16 : 32)) {
2184 /* Add an instruction size prefix */
2185 enum prefixes pref = (addrbits == 32) ? P_A16 : P_A32;
2186 for (j = 0; j < instruction->nprefix; j++) {
2187 if (instruction->prefixes[j] == pref)
2188 return; /* Already there */
2189 }
2190 instruction->prefixes[j] = pref;
2191 instruction->nprefix++;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002192 } else {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002193 /* Impossible... */
2194 errfunc(ERR_NONFATAL, "impossible combination of address sizes");
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002195 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002196}