blob: 83a9a8a0c05d41edb60c6015c0b1441720bc96e8 [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 Anvinde4b89b2007-10-01 15:41:25 -070025 * depending on the address size of the instruction.
H. Peter Anvin7eb4a382007-09-17 15:49:30 -070026 * \50..\53 - a byte relative operand, from operand 0..3
27 * \54..\57 - a qword immediate operand, from operand 0..3
28 * \60..\63 - a word relative operand, from operand 0..3
29 * \64..\67 - select between \6[0-3] and \7[0-3] depending on 16/32 bit
H. Peter Anvin17799b42002-05-21 03:31:21 +000030 * assembly mode or the operand-size override on the operand
H. Peter Anvin7eb4a382007-09-17 15:49:30 -070031 * \70..\73 - a long relative operand, from operand 0..3
32 * \74..\77 - a word constant, from the _segment_ part of operand 0..3
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000033 * \1ab - a ModRM, calculated on EA in operand a, with the spare
34 * field the register value of operand b.
H. Peter Anvin7eb4a382007-09-17 15:49:30 -070035 * \140..\143 - an immediate word or signed byte for operand 0..3
36 * \144..\147 - or 2 (s-field) into next opcode byte if operand 0..3
H. Peter Anvinaf535c12002-04-30 20:59:21 +000037 * is a signed byte rather than a word.
H. Peter Anvin7eb4a382007-09-17 15:49:30 -070038 * \150..\153 - an immediate dword or signed byte for operand 0..3
39 * \154..\157 - or 2 (s-field) into next opcode byte if operand 0..3
H. Peter Anvinaf535c12002-04-30 20:59:21 +000040 * is a signed byte rather than a dword.
H. Peter Anvin401c07e2007-09-17 16:55:04 -070041 * \160..\163 - this instruction uses DREX rather than REX, with the
42 * OC0 field set to 0, and the dest field taken from
43 * operand 0..3.
44 * \164..\167 - this instruction uses DREX rather than REX, with the
45 * OC0 field set to 1, and the dest field taken from
46 * operand 0..3.
H. Peter Anvin7eb4a382007-09-17 15:49:30 -070047 * \170 - encodes the literal byte 0. (Some compilers don't take
48 * kindly to a zero byte in the _middle_ of a compile time
49 * string constant, so I had to put this hack in.)
H. Peter Anvin401c07e2007-09-17 16:55:04 -070050 * \171 - placement of DREX suffix in the absence of an EA
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000051 * \2ab - a ModRM, calculated on EA in operand a, with the spare
52 * field equal to digit b.
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000053 * \310 - indicates fixed 16-bit address size, i.e. optional 0x67.
54 * \311 - indicates fixed 32-bit address size, i.e. optional 0x67.
Keith Kanios48af1772007-08-17 07:37:52 +000055 * \312 - (disassembler only) marker on LOOP, LOOPxx instructions.
H. Peter Anvince2b3972007-05-30 22:21:11 +000056 * \313 - indicates fixed 64-bit address size, 0x67 invalid.
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000057 * \320 - indicates fixed 16-bit operand size, i.e. optional 0x66.
58 * \321 - indicates fixed 32-bit operand size, i.e. optional 0x66.
59 * \322 - indicates that this instruction is only valid when the
60 * operand size is the default (instruction to disassembler,
61 * generates no code in the assembler)
H. Peter Anvince2b3972007-05-30 22:21:11 +000062 * \323 - indicates fixed 64-bit operand size, REX on extensions only.
Keith Kaniosb7a89542007-04-12 02:40:54 +000063 * \324 - indicates 64-bit operand size requiring REX prefix.
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000064 * \330 - a literal byte follows in the code stream, to be added
65 * to the condition code value of the instruction.
Keith Kanios48af1772007-08-17 07:37:52 +000066 * \331 - instruction not valid with REP prefix. Hint for
H. Peter Anvinef7468f2002-04-30 20:57:59 +000067 * disassembler only; for SSE instructions.
H. Peter Anvincb9b6902007-09-12 21:58:51 -070068 * \332 - REP prefix (0xF2 byte) used as opcode extension.
69 * \333 - REP prefix (0xF3 byte) used as opcode extension.
Keith Kanios48af1772007-08-17 07:37:52 +000070 * \334 - LOCK prefix used instead of REX.R
H. Peter Anvincb9b6902007-09-12 21:58:51 -070071 * \335 - disassemble a rep (0xF3 byte) prefix as repe not rep.
Keith Kaniosb7a89542007-04-12 02:40:54 +000072 * \340 - reserve <operand 0> bytes of uninitialized storage.
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000073 * Operand 0 had better be a segmentless constant.
H. Peter Anvin62cb6062007-09-11 22:44:03 +000074 * \364 - operand-size prefix (0x66) not permitted
75 * \365 - address-size prefix (0x67) not permitted
76 * \366 - operand-size prefix (0x66) used as opcode extension
77 * \367 - address-size prefix (0x67) used as opcode extension
H. Peter Anvin788e6c12002-04-30 21:02:01 +000078 * \370,\371,\372 - match only if operand 0 meets byte jump criteria.
79 * 370 is used for Jcc, 371 is used for JMP.
H. Peter Anvinaf535c12002-04-30 20:59:21 +000080 * \373 - assemble 0x03 if bits==16, 0x05 if bits==32;
81 * used for conditional jump over longer jump
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000082 */
83
H. Peter Anvinfe501952007-10-02 21:53:51 -070084#include "compiler.h"
85
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000086#include <stdio.h>
87#include <string.h>
Keith Kaniosb7a89542007-04-12 02:40:54 +000088#include <inttypes.h>
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000089
90#include "nasm.h"
H. Peter Anvin6768eb72002-04-30 20:52:26 +000091#include "nasmlib.h"
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000092#include "assemble.h"
93#include "insns.h"
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +000094#include "preproc.h"
H. Peter Anvin3df97a72007-05-30 03:25:21 +000095#include "regflags.c"
Keith Kaniosb7a89542007-04-12 02:40:54 +000096#include "regvals.c"
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000097
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000098typedef struct {
Keith Kaniosb7a89542007-04-12 02:40:54 +000099 int sib_present; /* is a SIB byte necessary? */
100 int bytes; /* # of bytes of offset needed */
101 int size; /* lazy - this is sib+bytes+1 */
102 uint8_t modrm, sib, rex, rip; /* the bytes themselves */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000103} ea;
104
Keith Kaniosb7a89542007-04-12 02:40:54 +0000105static uint32_t cpu; /* cpu level received from nasm.c */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000106static efunc errfunc;
107static struct ofmt *outfmt;
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000108static ListGen *list;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000109
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000110static int32_t calcsize(int32_t, int32_t, int, insn *, const char *);
111static void gencode(int32_t, int32_t, int, insn *, const char *, int32_t);
H. Peter Anvin3360d792007-09-11 04:16:57 +0000112static int matches(const struct itemplate *, insn *, int bits);
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000113static int32_t regflag(const operand *);
114static int32_t regval(const operand *);
115static int rexflags(int, int32_t, int);
116static int op_rexflags(const operand *, int);
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700117static ea *process_ea(operand *, ea *, int, int, int, int32_t, int);
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700118static void add_asp(insn *, int);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000119
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700120static int has_prefix(insn * ins, enum prefix_pos pos, enum prefixes prefix)
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000121{
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700122 return ins->prefixes[pos] == prefix;
123}
124
125static void assert_no_prefix(insn * ins, enum prefix_pos pos)
126{
127 if (ins->prefixes[pos])
128 errfunc(ERR_NONFATAL, "invalid %s prefix",
129 prefix_name(ins->prefixes[pos]));
130}
131
132static const char *size_name(int size)
133{
134 switch (size) {
135 case 1:
136 return "byte";
137 case 2:
138 return "word";
139 case 4:
140 return "dword";
141 case 8:
142 return "qword";
143 case 10:
144 return "tword";
145 case 16:
146 return "oword";
147 default:
148 return "???";
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000149 }
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700150}
151
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700152static void warn_overflow(int size, int64_t data)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700153{
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700154 if (size < 8) {
155 int64_t lim = (1 << (size*8))-1;
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000156
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700157 if (data < ~lim || data > lim)
158 errfunc(ERR_WARNING, "%s data exceeds bounds", size_name(size));
159 }
160}
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000161/*
162 * This routine wrappers the real output format's output routine,
163 * in order to pass a copy of the data off to the listing file
164 * generator at the same time.
165 */
Keith Kaniosb7a89542007-04-12 02:40:54 +0000166static void out(int32_t offset, int32_t segto, const void *data,
167 uint32_t type, int32_t segment, int32_t wrt)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000168{
Keith Kaniosb7a89542007-04-12 02:40:54 +0000169 static int32_t lineno = 0; /* static!!! */
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000170 static char *lnfname = NULL;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000171
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000172 if ((type & OUT_TYPMASK) == OUT_ADDRESS) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000173 if (segment != NO_SEG || wrt != NO_SEG) {
174 /*
175 * This address is relocated. We must write it as
176 * OUT_ADDRESS, so there's no work to be done here.
177 */
178 list->output(offset, data, type);
179 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000180 uint8_t p[8], *q = p;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000181 /*
182 * This is a non-relocated address, and we're going to
183 * convert it into RAWDATA format.
184 */
185 if ((type & OUT_SIZMASK) == 4) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000186 WRITELONG(q, *(int32_t *)data);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000187 list->output(offset, p, OUT_RAWDATA + 4);
Keith Kaniosb7a89542007-04-12 02:40:54 +0000188 } else if ((type & OUT_SIZMASK) == 8) {
189 WRITEDLONG(q, *(int64_t *)data);
190 list->output(offset, p, OUT_RAWDATA + 8);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000191 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000192 WRITESHORT(q, *(int32_t *)data);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000193 list->output(offset, p, OUT_RAWDATA + 2);
194 }
195 }
196 } else if ((type & OUT_TYPMASK) == OUT_RAWDATA) {
197 list->output(offset, data, type);
198 } else if ((type & OUT_TYPMASK) == OUT_RESERVE) {
199 list->output(offset, NULL, type);
200 } else if ((type & OUT_TYPMASK) == OUT_REL2ADR ||
201 (type & OUT_TYPMASK) == OUT_REL4ADR) {
202 list->output(offset, data, type);
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000203 }
204
Frank Kotlerabebb082003-09-06 04:45:37 +0000205 /*
206 * this call to src_get determines when we call the
207 * debug-format-specific "linenum" function
208 * it updates lineno and lnfname to the current values
209 * returning 0 if "same as last time", -2 if lnfname
210 * changed, and the amount by which lineno changed,
211 * if it did. thus, these variables must be static
212 */
213
H. Peter Anvine2c80182005-01-15 22:15:51 +0000214 if (src_get(&lineno, &lnfname)) {
215 outfmt->current_dfmt->linenum(lnfname, lineno, segto);
H. Peter Anvince616072002-04-30 21:02:23 +0000216 }
H. Peter Anvineba20a72002-04-30 20:53:55 +0000217
H. Peter Anvine2c80182005-01-15 22:15:51 +0000218 outfmt->output(segto, data, type, segment, wrt);
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000219}
220
Keith Kaniosb7a89542007-04-12 02:40:54 +0000221static int jmp_match(int32_t segment, int32_t offset, int bits,
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000222 insn * ins, const char *code)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000223{
Keith Kaniosb7a89542007-04-12 02:40:54 +0000224 int32_t isize;
225 uint8_t c = code[0];
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000226
H. Peter Anvine2c80182005-01-15 22:15:51 +0000227 if (c != 0370 && c != 0371)
228 return 0;
H. Peter Anvin788e6c12002-04-30 21:02:01 +0000229 if (ins->oprs[0].opflags & OPFLAG_FORWARD) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000230 if ((optimizing < 0 || (ins->oprs[0].type & STRICT))
231 && c == 0370)
232 return 1;
233 else
234 return (pass0 == 0); /* match a forward reference */
H. Peter Anvin788e6c12002-04-30 21:02:01 +0000235 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000236 isize = calcsize(segment, offset, bits, ins, code);
237 if (ins->oprs[0].segment != segment)
238 return 0;
239 isize = ins->oprs[0].offset - offset - isize; /* isize is now the delta */
240 if (isize >= -128L && isize <= 127L)
241 return 1; /* it is byte size */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000242
243 return 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000244}
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000245
Keith Kaniosb7a89542007-04-12 02:40:54 +0000246int32_t assemble(int32_t segment, int32_t offset, int bits, uint32_t cp,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000247 insn * instruction, struct ofmt *output, efunc error,
248 ListGen * listgen)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000249{
H. Peter Anvin3360d792007-09-11 04:16:57 +0000250 const struct itemplate *temp;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000251 int j;
252 int size_prob;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000253 int32_t insn_end;
254 int32_t itimes;
255 int32_t start = offset;
256 int32_t wsize = 0; /* size for DB etc. */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000257
H. Peter Anvine2c80182005-01-15 22:15:51 +0000258 errfunc = error; /* to pass to other functions */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000259 cpu = cp;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000260 outfmt = output; /* likewise */
261 list = listgen; /* and again */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000262
H. Peter Anvine2c80182005-01-15 22:15:51 +0000263 switch (instruction->opcode) {
264 case -1:
265 return 0;
266 case I_DB:
267 wsize = 1;
268 break;
269 case I_DW:
270 wsize = 2;
271 break;
272 case I_DD:
273 wsize = 4;
274 break;
275 case I_DQ:
276 wsize = 8;
277 break;
278 case I_DT:
279 wsize = 10;
280 break;
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700281 case I_DO:
282 wsize = 16;
283 break;
H. Peter Anvin16b0a332007-09-12 20:27:41 -0700284 default:
285 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000286 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000287
H. Peter Anvineba20a72002-04-30 20:53:55 +0000288 if (wsize) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000289 extop *e;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000290 int32_t t = instruction->times;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000291 if (t < 0)
292 errfunc(ERR_PANIC,
293 "instruction->times < 0 (%ld) in assemble()", t);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000294
H. Peter Anvine2c80182005-01-15 22:15:51 +0000295 while (t--) { /* repeat TIMES times */
296 for (e = instruction->eops; e; e = e->next) {
297 if (e->type == EOT_DB_NUMBER) {
298 if (wsize == 1) {
299 if (e->segment != NO_SEG)
300 errfunc(ERR_NONFATAL,
301 "one-byte relocation attempted");
302 else {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000303 uint8_t out_byte = e->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000304 out(offset, segment, &out_byte,
305 OUT_RAWDATA + 1, NO_SEG, NO_SEG);
306 }
Keith Kanios61ff53c2007-04-14 18:54:52 +0000307 } else if (wsize > 8) {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700308 errfunc(ERR_NONFATAL, "integer supplied to a DT or DO"
Keith Kanios61ff53c2007-04-14 18:54:52 +0000309 " instruction");
H. Peter Anvine2c80182005-01-15 22:15:51 +0000310 } else
311 out(offset, segment, &e->offset,
312 OUT_ADDRESS + wsize, e->segment, e->wrt);
313 offset += wsize;
314 } else if (e->type == EOT_DB_STRING) {
315 int align;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000316
H. Peter Anvine2c80182005-01-15 22:15:51 +0000317 out(offset, segment, e->stringval,
318 OUT_RAWDATA + e->stringlen, NO_SEG, NO_SEG);
319 align = e->stringlen % wsize;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000320
H. Peter Anvine2c80182005-01-15 22:15:51 +0000321 if (align) {
322 align = wsize - align;
323 out(offset, segment, "\0\0\0\0\0\0\0\0",
324 OUT_RAWDATA + align, NO_SEG, NO_SEG);
325 }
326 offset += e->stringlen + align;
327 }
328 }
329 if (t > 0 && t == instruction->times - 1) {
330 /*
331 * Dummy call to list->output to give the offset to the
332 * listing module.
333 */
334 list->output(offset, NULL, OUT_RAWDATA);
335 list->uplevel(LIST_TIMES);
336 }
337 }
338 if (instruction->times > 1)
339 list->downlevel(LIST_TIMES);
340 return offset - start;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000341 }
342
H. Peter Anvine2c80182005-01-15 22:15:51 +0000343 if (instruction->opcode == I_INCBIN) {
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000344 static char fname[FILENAME_MAX];
H. Peter Anvine2c80182005-01-15 22:15:51 +0000345 FILE *fp;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000346 int32_t len;
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000347 char *prefix = "", *combine;
348 char **pPrevPath = NULL;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000349
H. Peter Anvine2c80182005-01-15 22:15:51 +0000350 len = FILENAME_MAX - 1;
351 if (len > instruction->eops->stringlen)
352 len = instruction->eops->stringlen;
353 strncpy(fname, instruction->eops->stringval, len);
354 fname[len] = '\0';
H. Peter Anvineba20a72002-04-30 20:53:55 +0000355
Keith Kaniosb7a89542007-04-12 02:40:54 +0000356 while (1) { /* added by alexfru: 'incbin' uses include paths */
H. Peter Anvine2c80182005-01-15 22:15:51 +0000357 combine = nasm_malloc(strlen(prefix) + len + 1);
358 strcpy(combine, prefix);
359 strcat(combine, fname);
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000360
H. Peter Anvine2c80182005-01-15 22:15:51 +0000361 if ((fp = fopen(combine, "rb")) != NULL) {
362 nasm_free(combine);
363 break;
364 }
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000365
H. Peter Anvine2c80182005-01-15 22:15:51 +0000366 nasm_free(combine);
367 pPrevPath = pp_get_include_path_ptr(pPrevPath);
368 if (pPrevPath == NULL)
369 break;
370 prefix = *pPrevPath;
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000371 }
372
373 if (fp == NULL)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000374 error(ERR_NONFATAL, "`incbin': unable to open file `%s'",
375 fname);
376 else if (fseek(fp, 0L, SEEK_END) < 0)
377 error(ERR_NONFATAL, "`incbin': unable to seek on file `%s'",
378 fname);
379 else {
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000380 static char buf[2048];
Keith Kaniosb7a89542007-04-12 02:40:54 +0000381 int32_t t = instruction->times;
382 int32_t base = 0;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000383
H. Peter Anvine2c80182005-01-15 22:15:51 +0000384 len = ftell(fp);
385 if (instruction->eops->next) {
386 base = instruction->eops->next->offset;
387 len -= base;
388 if (instruction->eops->next->next &&
389 len > instruction->eops->next->next->offset)
390 len = instruction->eops->next->next->offset;
391 }
392 /*
393 * Dummy call to list->output to give the offset to the
394 * listing module.
395 */
396 list->output(offset, NULL, OUT_RAWDATA);
397 list->uplevel(LIST_INCBIN);
398 while (t--) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000399 int32_t l;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000400
H. Peter Anvine2c80182005-01-15 22:15:51 +0000401 fseek(fp, base, SEEK_SET);
402 l = len;
403 while (l > 0) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000404 int32_t m =
Charles Crayne192d5b52007-10-18 19:02:42 -0700405 fread(buf, 1, (l > (int32_t) sizeof(buf) ? (int32_t) sizeof(buf) : l),
H. Peter Anvine2c80182005-01-15 22:15:51 +0000406 fp);
407 if (!m) {
408 /*
409 * This shouldn't happen unless the file
410 * actually changes while we are reading
411 * it.
412 */
413 error(ERR_NONFATAL,
414 "`incbin': unexpected EOF while"
415 " reading file `%s'", fname);
416 t = 0; /* Try to exit cleanly */
417 break;
418 }
419 out(offset, segment, buf, OUT_RAWDATA + m,
420 NO_SEG, NO_SEG);
421 l -= m;
422 }
423 }
424 list->downlevel(LIST_INCBIN);
425 if (instruction->times > 1) {
426 /*
427 * Dummy call to list->output to give the offset to the
428 * listing module.
429 */
430 list->output(offset, NULL, OUT_RAWDATA);
431 list->uplevel(LIST_TIMES);
432 list->downlevel(LIST_TIMES);
433 }
434 fclose(fp);
435 return instruction->times * len;
436 }
437 return 0; /* if we're here, there's an error */
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000438 }
439
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700440 /* Check to see if we need an address-size prefix */
441 add_asp(instruction, bits);
442
H. Peter Anvin6867acc2007-10-10 14:58:45 -0700443 size_prob = false;
H. Peter Anvin70653092007-10-19 14:42:29 -0700444
445 for (temp = nasm_instructions[instruction->opcode]; temp->opcode != -1; temp++){
Keith Kaniosb7a89542007-04-12 02:40:54 +0000446 int m = matches(temp, instruction, bits);
H. Peter Anvin70653092007-10-19 14:42:29 -0700447
H. Peter Anvine2c80182005-01-15 22:15:51 +0000448 if (m == 99)
449 m += jmp_match(segment, offset, bits, instruction, temp->code);
H. Peter Anvineba20a72002-04-30 20:53:55 +0000450
H. Peter Anvine2c80182005-01-15 22:15:51 +0000451 if (m == 100) { /* matches! */
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000452 const char *codes = temp->code;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000453 int32_t insn_size = calcsize(segment, offset, bits,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000454 instruction, codes);
455 itimes = instruction->times;
456 if (insn_size < 0) /* shouldn't be, on pass two */
457 error(ERR_PANIC, "errors made it through from pass one");
458 else
459 while (itimes--) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700460 for (j = 0; j < MAXPREFIX; j++) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000461 uint8_t c = 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000462 switch (instruction->prefixes[j]) {
463 case P_LOCK:
464 c = 0xF0;
465 break;
466 case P_REPNE:
467 case P_REPNZ:
468 c = 0xF2;
469 break;
470 case P_REPE:
471 case P_REPZ:
472 case P_REP:
473 c = 0xF3;
474 break;
475 case R_CS:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000476 if (bits == 64) {
477 error(ERR_WARNING,
478 "cs segment base ignored in 64-bit mode");
479 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000480 c = 0x2E;
481 break;
482 case R_DS:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000483 if (bits == 64) {
484 error(ERR_WARNING,
485 "ds segment base ignored in 64-bit mode");
486 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000487 c = 0x3E;
488 break;
489 case R_ES:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000490 if (bits == 64) {
491 error(ERR_WARNING,
492 "es segment base ignored in 64-bit mode");
493 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000494 c = 0x26;
495 break;
496 case R_FS:
497 c = 0x64;
498 break;
499 case R_GS:
500 c = 0x65;
501 break;
502 case R_SS:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000503 if (bits == 64) {
504 error(ERR_WARNING,
505 "ss segment base ignored in 64-bit mode");
506 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000507 c = 0x36;
508 break;
509 case R_SEGR6:
510 case R_SEGR7:
511 error(ERR_NONFATAL,
512 "segr6 and segr7 cannot be used as prefixes");
513 break;
514 case P_A16:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000515 if (bits == 64) {
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000516 error(ERR_NONFATAL,
517 "16-bit addressing is not supported "
518 "in 64-bit mode");
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700519 } else if (bits != 16)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000520 c = 0x67;
521 break;
522 case P_A32:
523 if (bits != 32)
524 c = 0x67;
525 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700526 case P_A64:
527 if (bits != 64) {
528 error(ERR_NONFATAL,
529 "64-bit addressing is only supported "
530 "in 64-bit mode");
531 }
532 break;
533 case P_ASP:
534 c = 0x67;
535 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000536 case P_O16:
537 if (bits != 16)
538 c = 0x66;
539 break;
540 case P_O32:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000541 if (bits == 16)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000542 c = 0x66;
543 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700544 case P_O64:
545 /* REX.W */
546 break;
547 case P_OSP:
548 c = 0x66;
549 break;
550 case P_none:
551 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000552 default:
553 error(ERR_PANIC, "invalid instruction prefix");
554 }
555 if (c != 0) {
556 out(offset, segment, &c, OUT_RAWDATA + 1,
557 NO_SEG, NO_SEG);
558 offset++;
559 }
H. Peter Anvin70653092007-10-19 14:42:29 -0700560 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000561 insn_end = offset + insn_size;
562 gencode(segment, offset, bits, instruction, codes,
563 insn_end);
564 offset += insn_size;
565 if (itimes > 0 && itimes == instruction->times - 1) {
566 /*
567 * Dummy call to list->output to give the offset to the
568 * listing module.
569 */
570 list->output(offset, NULL, OUT_RAWDATA);
571 list->uplevel(LIST_TIMES);
572 }
573 }
574 if (instruction->times > 1)
575 list->downlevel(LIST_TIMES);
576 return offset - start;
577 } else if (m > 0 && m > size_prob) {
578 size_prob = m;
579 }
Keith Kaniosb7a89542007-04-12 02:40:54 +0000580// temp++;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000581 }
H. Peter Anvineba20a72002-04-30 20:53:55 +0000582
H. Peter Anvine2c80182005-01-15 22:15:51 +0000583 if (temp->opcode == -1) { /* didn't match any instruction */
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000584 switch (size_prob) {
585 case 1:
586 error(ERR_NONFATAL, "operation size not specified");
587 break;
588 case 2:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000589 error(ERR_NONFATAL, "mismatch in operand sizes");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000590 break;
591 case 3:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000592 error(ERR_NONFATAL, "no instruction for this cpu level");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000593 break;
594 case 4:
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000595 error(ERR_NONFATAL, "instruction not supported in 64-bit mode");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000596 break;
597 default:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000598 error(ERR_NONFATAL,
599 "invalid combination of opcode and operands");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000600 break;
601 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000602 }
603 return 0;
604}
605
Keith Kaniosb7a89542007-04-12 02:40:54 +0000606int32_t insn_size(int32_t segment, int32_t offset, int bits, uint32_t cp,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000607 insn * instruction, efunc error)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000608{
H. Peter Anvin3360d792007-09-11 04:16:57 +0000609 const struct itemplate *temp;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000610
H. Peter Anvine2c80182005-01-15 22:15:51 +0000611 errfunc = error; /* to pass to other functions */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000612 cpu = cp;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000613
614 if (instruction->opcode == -1)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000615 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000616
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700617 if (instruction->opcode == I_DB || instruction->opcode == I_DW ||
618 instruction->opcode == I_DD || instruction->opcode == I_DQ ||
619 instruction->opcode == I_DT || instruction->opcode == I_DO) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000620 extop *e;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000621 int32_t isize, osize, wsize = 0; /* placate gcc */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000622
H. Peter Anvine2c80182005-01-15 22:15:51 +0000623 isize = 0;
624 switch (instruction->opcode) {
625 case I_DB:
626 wsize = 1;
627 break;
628 case I_DW:
629 wsize = 2;
630 break;
631 case I_DD:
632 wsize = 4;
633 break;
634 case I_DQ:
635 wsize = 8;
636 break;
637 case I_DT:
638 wsize = 10;
639 break;
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700640 case I_DO:
641 wsize = 16;
642 break;
H. Peter Anvin16b0a332007-09-12 20:27:41 -0700643 default:
644 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000645 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000646
H. Peter Anvine2c80182005-01-15 22:15:51 +0000647 for (e = instruction->eops; e; e = e->next) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000648 int32_t align;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000649
H. Peter Anvine2c80182005-01-15 22:15:51 +0000650 osize = 0;
651 if (e->type == EOT_DB_NUMBER)
652 osize = 1;
653 else if (e->type == EOT_DB_STRING)
654 osize = e->stringlen;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000655
H. Peter Anvine2c80182005-01-15 22:15:51 +0000656 align = (-osize) % wsize;
657 if (align < 0)
658 align += wsize;
659 isize += osize + align;
660 }
661 return isize * instruction->times;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000662 }
663
H. Peter Anvine2c80182005-01-15 22:15:51 +0000664 if (instruction->opcode == I_INCBIN) {
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000665 char fname[FILENAME_MAX];
H. Peter Anvine2c80182005-01-15 22:15:51 +0000666 FILE *fp;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000667 int32_t len;
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000668 char *prefix = "", *combine;
669 char **pPrevPath = NULL;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000670
H. Peter Anvine2c80182005-01-15 22:15:51 +0000671 len = FILENAME_MAX - 1;
672 if (len > instruction->eops->stringlen)
673 len = instruction->eops->stringlen;
674 strncpy(fname, instruction->eops->stringval, len);
675 fname[len] = '\0';
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000676
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700677 /* added by alexfru: 'incbin' uses include paths */
678 while (1) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000679 combine = nasm_malloc(strlen(prefix) + len + 1);
680 strcpy(combine, prefix);
681 strcat(combine, fname);
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000682
H. Peter Anvine2c80182005-01-15 22:15:51 +0000683 if ((fp = fopen(combine, "rb")) != NULL) {
684 nasm_free(combine);
685 break;
686 }
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000687
H. Peter Anvine2c80182005-01-15 22:15:51 +0000688 nasm_free(combine);
689 pPrevPath = pp_get_include_path_ptr(pPrevPath);
690 if (pPrevPath == NULL)
691 break;
692 prefix = *pPrevPath;
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000693 }
694
695 if (fp == NULL)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000696 error(ERR_NONFATAL, "`incbin': unable to open file `%s'",
697 fname);
698 else if (fseek(fp, 0L, SEEK_END) < 0)
699 error(ERR_NONFATAL, "`incbin': unable to seek on file `%s'",
700 fname);
701 else {
702 len = ftell(fp);
703 fclose(fp);
704 if (instruction->eops->next) {
705 len -= instruction->eops->next->offset;
706 if (instruction->eops->next->next &&
707 len > instruction->eops->next->next->offset) {
708 len = instruction->eops->next->next->offset;
709 }
710 }
711 return instruction->times * len;
712 }
713 return 0; /* if we're here, there's an error */
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000714 }
715
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700716 /* Check to see if we need an address-size prefix */
717 add_asp(instruction, bits);
718
Keith Kaniosb7a89542007-04-12 02:40:54 +0000719 for (temp = nasm_instructions[instruction->opcode]; temp->opcode != -1; temp++) {
720 int m = matches(temp, instruction, bits);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000721 if (m == 99)
722 m += jmp_match(segment, offset, bits, instruction, temp->code);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000723
H. Peter Anvine2c80182005-01-15 22:15:51 +0000724 if (m == 100) {
725 /* we've matched an instruction. */
Keith Kaniosb7a89542007-04-12 02:40:54 +0000726 int32_t isize;
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000727 const char *codes = temp->code;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000728 int j;
729
730 isize = calcsize(segment, offset, bits, instruction, codes);
731 if (isize < 0)
732 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700733 for (j = 0; j < MAXPREFIX; j++) {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700734 switch (instruction->prefixes[j]) {
735 case P_A16:
736 if (bits != 16)
737 isize++;
738 break;
739 case P_A32:
740 if (bits != 32)
741 isize++;
742 break;
743 case P_O16:
744 if (bits != 16)
745 isize++;
746 break;
747 case P_O32:
748 if (bits == 16)
749 isize++;
750 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700751 case P_A64:
752 case P_O64:
753 case P_none:
754 break;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700755 default:
756 isize++;
757 break;
758 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000759 }
760 return isize * instruction->times;
761 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000762 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000763 return -1; /* didn't match any instruction */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000764}
765
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000766/* check that opn[op] is a signed byte of size 16 or 32,
767 and return the signed value*/
H. Peter Anvine2c80182005-01-15 22:15:51 +0000768static int is_sbyte(insn * ins, int op, int size)
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000769{
Keith Kaniosb7a89542007-04-12 02:40:54 +0000770 int32_t v;
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000771 int ret;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000772
773 ret = !(ins->forw_ref && ins->oprs[op].opflags) && /* dead in the water on forward reference or External */
774 optimizing >= 0 &&
775 !(ins->oprs[op].type & STRICT) &&
776 ins->oprs[op].wrt == NO_SEG && ins->oprs[op].segment == NO_SEG;
H. Peter Anvin734b1882002-04-30 21:01:08 +0000777
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000778 v = ins->oprs[op].offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000779 if (size == 16)
Keith Kaniosb7a89542007-04-12 02:40:54 +0000780 v = (int16_t)v; /* sign extend if 16 bits */
H. Peter Anvine2c80182005-01-15 22:15:51 +0000781
782 return ret && v >= -128L && v <= 127L;
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000783}
784
Keith Kaniosb7a89542007-04-12 02:40:54 +0000785static int32_t calcsize(int32_t segment, int32_t offset, int bits,
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000786 insn * ins, const char *codes)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000787{
Keith Kaniosb7a89542007-04-12 02:40:54 +0000788 int32_t length = 0;
789 uint8_t c;
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000790 int rex_mask = ~0;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +0000791 ins->rex = 0; /* Ensure REX is reset */
H. Peter Anvineba20a72002-04-30 20:53:55 +0000792
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700793 if (ins->prefixes[PPS_OSIZE] == P_O64)
794 ins->rex |= REX_W;
795
H. Peter Anvine2c80182005-01-15 22:15:51 +0000796 (void)segment; /* Don't warn that this parameter is unused */
797 (void)offset; /* Don't warn that this parameter is unused */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000798
H. Peter Anvine2c80182005-01-15 22:15:51 +0000799 while (*codes)
800 switch (c = *codes++) {
801 case 01:
802 case 02:
803 case 03:
804 codes += c, length += c;
805 break;
806 case 04:
807 case 05:
808 case 06:
809 case 07:
810 length++;
811 break;
812 case 010:
813 case 011:
814 case 012:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700815 case 013:
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000816 ins->rex |=
817 op_rexflags(&ins->oprs[c - 010], REX_B|REX_H|REX_P|REX_W);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000818 codes++, length++;
819 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000820 case 014:
821 case 015:
822 case 016:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700823 case 017:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000824 length++;
825 break;
826 case 020:
827 case 021:
828 case 022:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700829 case 023:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000830 length++;
831 break;
832 case 024:
833 case 025:
834 case 026:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700835 case 027:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000836 length++;
837 break;
838 case 030:
839 case 031:
840 case 032:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700841 case 033:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000842 length += 2;
843 break;
844 case 034:
845 case 035:
846 case 036:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700847 case 037:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000848 if (ins->oprs[c - 034].type & (BITS16 | BITS32 | BITS64))
H. Peter Anvine2c80182005-01-15 22:15:51 +0000849 length += (ins->oprs[c - 034].type & BITS16) ? 2 : 4;
850 else
851 length += (bits == 16) ? 2 : 4;
852 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000853 case 040:
854 case 041:
855 case 042:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700856 case 043:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000857 length += 4;
858 break;
859 case 044:
860 case 045:
861 case 046:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700862 case 047:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700863 length += ins->addr_size >> 3;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000864 break;
865 case 050:
866 case 051:
867 case 052:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700868 case 053:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000869 length++;
870 break;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000871 case 054:
872 case 055:
873 case 056:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700874 case 057:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000875 length += 8; /* MOV reg64/imm */
876 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000877 case 060:
878 case 061:
879 case 062:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700880 case 063:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000881 length += 2;
882 break;
883 case 064:
884 case 065:
885 case 066:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700886 case 067:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000887 if (ins->oprs[c - 064].type & (BITS16 | BITS32 | BITS64))
H. Peter Anvine2c80182005-01-15 22:15:51 +0000888 length += (ins->oprs[c - 064].type & BITS16) ? 2 : 4;
889 else
890 length += (bits == 16) ? 2 : 4;
891 break;
892 case 070:
893 case 071:
894 case 072:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700895 case 073:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000896 length += 4;
897 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700898 case 074:
899 case 075:
900 case 076:
901 case 077:
902 length += 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000903 break;
904 case 0140:
905 case 0141:
906 case 0142:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700907 case 0143:
908 length += is_sbyte(ins, c - 0140, 16) ? 1 : 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000909 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000910 case 0144:
911 case 0145:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700912 case 0146:
913 case 0147:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000914 codes += 2;
915 length++;
916 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700917 case 0150:
918 case 0151:
919 case 0152:
920 case 0153:
921 length += is_sbyte(ins, c - 0150, 32) ? 1 : 4;
922 break;
923 case 0154:
924 case 0155:
925 case 0156:
926 case 0157:
927 codes += 2;
928 length++;
929 break;
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700930 case 0160:
931 case 0161:
932 case 0162:
933 case 0163:
934 length++;
935 ins->rex |= REX_D;
H. Peter Anvincf5180a2007-09-17 17:25:27 -0700936 ins->drexdst = regval(&ins->oprs[c & 3]);
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700937 break;
938 case 0164:
939 case 0165:
940 case 0166:
941 case 0167:
942 length++;
943 ins->rex |= REX_D|REX_OC;
H. Peter Anvincf5180a2007-09-17 17:25:27 -0700944 ins->drexdst = regval(&ins->oprs[c & 3]);
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700945 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700946 case 0170:
947 length++;
948 break;
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700949 case 0171:
950 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000951 case 0300:
952 case 0301:
H. Peter Anvin70653092007-10-19 14:42:29 -0700953 case 0302:
954 case 0303:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000955 break;
956 case 0310:
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700957 if (bits == 64)
958 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700959 length += (bits != 16) && !has_prefix(ins, PPS_ASIZE, P_A16);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000960 break;
961 case 0311:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700962 length += (bits != 32) && !has_prefix(ins, PPS_ASIZE, P_A32);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000963 break;
964 case 0312:
H. Peter Anvin70653092007-10-19 14:42:29 -0700965 break;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000966 case 0313:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700967 if (bits != 64 || has_prefix(ins, PPS_ASIZE, P_A16) ||
968 has_prefix(ins, PPS_ASIZE, P_A32))
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700969 return -1;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000970 break;
971 case 0320:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000972 length += (bits != 16);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000973 break;
974 case 0321:
975 length += (bits == 16);
976 break;
977 case 0322:
978 break;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000979 case 0323:
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000980 rex_mask &= ~REX_W;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000981 break;
982 case 0324:
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000983 ins->rex |= REX_W;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +0000984 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000985 case 0330:
986 codes++, length++;
987 break;
988 case 0331:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000989 break;
H. Peter Anvincb9b6902007-09-12 21:58:51 -0700990 case 0332:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000991 case 0333:
992 length++;
993 break;
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000994 case 0334:
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000995 ins->rex |= REX_L;
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000996 break;
H. Peter Anvincb9b6902007-09-12 21:58:51 -0700997 case 0335:
998 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000999 case 0340:
1000 case 0341:
1001 case 0342:
1002 if (ins->oprs[0].segment != NO_SEG)
1003 errfunc(ERR_NONFATAL, "attempt to reserve non-constant"
1004 " quantity of BSS space");
1005 else
1006 length += ins->oprs[0].offset << (c - 0340);
1007 break;
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001008 case 0364:
1009 case 0365:
1010 break;
Keith Kanios48af1772007-08-17 07:37:52 +00001011 case 0366:
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001012 case 0367:
1013 length++;
1014 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001015 case 0370:
1016 case 0371:
1017 case 0372:
1018 break;
1019 case 0373:
1020 length++;
1021 break;
1022 default: /* can't do it by 'case' statements */
1023 if (c >= 0100 && c <= 0277) { /* it's an EA */
1024 ea ea_data;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001025 int rfield;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001026 int32_t rflags;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001027 ea_data.rex = 0; /* Ensure ea.REX is initially 0 */
H. Peter Anvin70653092007-10-19 14:42:29 -07001028
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001029 if (c <= 0177) {
1030 /* pick rfield from operand b */
1031 rflags = regflag(&ins->oprs[c & 7]);
1032 rfield = regvals[ins->oprs[c & 7].basereg];
1033 } else {
1034 rflags = 0;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001035 rfield = c & 7;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001036 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00001037
H. Peter Anvine2c80182005-01-15 22:15:51 +00001038 if (!process_ea
Keith Kaniosb7a89542007-04-12 02:40:54 +00001039 (&ins->oprs[(c >> 3) & 7], &ea_data, bits,
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001040 ins->addr_size, rfield, rflags, ins->forw_ref)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001041 errfunc(ERR_NONFATAL, "invalid effective address");
1042 return -1;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001043 } else {
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001044 ins->rex |= ea_data.rex;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001045 length += ea_data.size;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001046 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001047 } else
1048 errfunc(ERR_PANIC, "internal instruction table corrupt"
1049 ": instruction code 0x%02X given", c);
1050 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001051
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001052 ins->rex &= rex_mask;
H. Peter Anvin70653092007-10-19 14:42:29 -07001053
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001054 if (ins->rex & REX_D) {
1055 if (ins->rex & REX_H) {
1056 errfunc(ERR_NONFATAL, "cannot use high register in drex instruction");
1057 return -1;
1058 }
H. Peter Anvincf5180a2007-09-17 17:25:27 -07001059 if (bits != 64 && ((ins->rex & (REX_W|REX_X|REX_B)) ||
1060 ins->drexdst > 7)) {
1061 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1062 return -1;
1063 }
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001064 length++;
1065 } else if (ins->rex & REX_REAL) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001066 if (ins->rex & REX_H) {
1067 errfunc(ERR_NONFATAL, "cannot use high register in rex instruction");
1068 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001069 } else if (bits == 64) {
1070 length++;
1071 } else if ((ins->rex & REX_L) &&
1072 !(ins->rex & (REX_P|REX_W|REX_X|REX_B)) &&
1073 cpu >= IF_X86_64) {
1074 /* LOCK-as-REX.R */
1075 assert_no_prefix(ins, PPS_LREP);
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001076 length++;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001077 } else {
H. Peter Anvincf5180a2007-09-17 17:25:27 -07001078 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1079 return -1;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001080 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00001081 }
1082
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001083 return length;
1084}
Keith Kaniosb7a89542007-04-12 02:40:54 +00001085
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001086#define EMIT_REX() \
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001087 if (!(ins->rex & REX_D) && (ins->rex & REX_REAL) && (bits == 64)) { \
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001088 ins->rex = (ins->rex & REX_REAL)|REX_P; \
1089 out(offset, segment, &ins->rex, OUT_RAWDATA+1, NO_SEG, NO_SEG); \
1090 ins->rex = 0; \
1091 offset += 1; \
1092 }
1093
Keith Kaniosb7a89542007-04-12 02:40:54 +00001094static void gencode(int32_t segment, int32_t offset, int bits,
Keith Kaniosa6dfa782007-04-13 16:47:53 +00001095 insn * ins, const char *codes, int32_t insn_end)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001096{
Keith Kaniosa6dfa782007-04-13 16:47:53 +00001097 static char condval[] = { /* conditional opcodes */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001098 0x7, 0x3, 0x2, 0x6, 0x2, 0x4, 0xF, 0xD, 0xC, 0xE, 0x6, 0x2,
1099 0x3, 0x7, 0x3, 0x5, 0xE, 0xC, 0xD, 0xF, 0x1, 0xB, 0x9, 0x5,
1100 0x0, 0xA, 0xA, 0xB, 0x8, 0x4
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001101 };
Keith Kaniosb7a89542007-04-12 02:40:54 +00001102 uint8_t c;
1103 uint8_t bytes[4];
1104 int32_t size;
1105 int64_t data;
H. Peter Anvin70653092007-10-19 14:42:29 -07001106
H. Peter Anvineba20a72002-04-30 20:53:55 +00001107 while (*codes)
H. Peter Anvine2c80182005-01-15 22:15:51 +00001108 switch (c = *codes++) {
1109 case 01:
1110 case 02:
1111 case 03:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001112 EMIT_REX();
H. Peter Anvine2c80182005-01-15 22:15:51 +00001113 out(offset, segment, codes, OUT_RAWDATA + c, NO_SEG, NO_SEG);
1114 codes += c;
1115 offset += c;
1116 break;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001117
H. Peter Anvine2c80182005-01-15 22:15:51 +00001118 case 04:
1119 case 06:
1120 switch (ins->oprs[0].basereg) {
1121 case R_CS:
1122 bytes[0] = 0x0E + (c == 0x04 ? 1 : 0);
1123 break;
1124 case R_DS:
1125 bytes[0] = 0x1E + (c == 0x04 ? 1 : 0);
1126 break;
1127 case R_ES:
1128 bytes[0] = 0x06 + (c == 0x04 ? 1 : 0);
1129 break;
1130 case R_SS:
1131 bytes[0] = 0x16 + (c == 0x04 ? 1 : 0);
1132 break;
1133 default:
1134 errfunc(ERR_PANIC,
1135 "bizarre 8086 segment register received");
1136 }
1137 out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG, NO_SEG);
1138 offset++;
1139 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001140
H. Peter Anvine2c80182005-01-15 22:15:51 +00001141 case 05:
1142 case 07:
1143 switch (ins->oprs[0].basereg) {
1144 case R_FS:
1145 bytes[0] = 0xA0 + (c == 0x05 ? 1 : 0);
1146 break;
1147 case R_GS:
1148 bytes[0] = 0xA8 + (c == 0x05 ? 1 : 0);
1149 break;
1150 default:
1151 errfunc(ERR_PANIC,
1152 "bizarre 386 segment register received");
1153 }
1154 out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG, NO_SEG);
1155 offset++;
1156 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001157
H. Peter Anvine2c80182005-01-15 22:15:51 +00001158 case 010:
1159 case 011:
1160 case 012:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001161 case 013:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001162 EMIT_REX();
Keith Kaniosb7a89542007-04-12 02:40:54 +00001163 bytes[0] = *codes++ + ((regval(&ins->oprs[c - 010])) & 7);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001164 out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG, NO_SEG);
1165 offset += 1;
1166 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001167
H. Peter Anvine2c80182005-01-15 22:15:51 +00001168 case 014:
1169 case 015:
1170 case 016:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001171 case 017:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001172 if (ins->oprs[c - 014].offset < -128
1173 || ins->oprs[c - 014].offset > 127) {
1174 errfunc(ERR_WARNING, "signed byte value exceeds bounds");
1175 }
H. Peter Anvineba20a72002-04-30 20:53:55 +00001176
H. Peter Anvine2c80182005-01-15 22:15:51 +00001177 if (ins->oprs[c - 014].segment != NO_SEG) {
1178 data = ins->oprs[c - 014].offset;
1179 out(offset, segment, &data, OUT_ADDRESS + 1,
1180 ins->oprs[c - 014].segment, ins->oprs[c - 014].wrt);
1181 } else {
1182 bytes[0] = ins->oprs[c - 014].offset;
1183 out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG,
1184 NO_SEG);
1185 }
1186 offset += 1;
1187 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001188
H. Peter Anvine2c80182005-01-15 22:15:51 +00001189 case 020:
1190 case 021:
1191 case 022:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001192 case 023:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001193 if (ins->oprs[c - 020].offset < -256
1194 || ins->oprs[c - 020].offset > 255) {
1195 errfunc(ERR_WARNING, "byte value exceeds bounds");
1196 }
1197 if (ins->oprs[c - 020].segment != NO_SEG) {
1198 data = ins->oprs[c - 020].offset;
1199 out(offset, segment, &data, OUT_ADDRESS + 1,
1200 ins->oprs[c - 020].segment, ins->oprs[c - 020].wrt);
1201 } else {
1202 bytes[0] = ins->oprs[c - 020].offset;
1203 out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG,
1204 NO_SEG);
1205 }
1206 offset += 1;
1207 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001208
H. Peter Anvine2c80182005-01-15 22:15:51 +00001209 case 024:
1210 case 025:
1211 case 026:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001212 case 027:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001213 if (ins->oprs[c - 024].offset < 0
1214 || ins->oprs[c - 024].offset > 255)
1215 errfunc(ERR_WARNING, "unsigned byte value exceeds bounds");
1216 if (ins->oprs[c - 024].segment != NO_SEG) {
1217 data = ins->oprs[c - 024].offset;
1218 out(offset, segment, &data, OUT_ADDRESS + 1,
1219 ins->oprs[c - 024].segment, ins->oprs[c - 024].wrt);
1220 } else {
1221 bytes[0] = ins->oprs[c - 024].offset;
1222 out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG,
1223 NO_SEG);
1224 }
1225 offset += 1;
1226 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001227
H. Peter Anvine2c80182005-01-15 22:15:51 +00001228 case 030:
1229 case 031:
1230 case 032:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001231 case 033:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001232 data = ins->oprs[c - 030].offset;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001233 if (ins->oprs[c - 030].segment == NO_SEG &&
1234 ins->oprs[c - 030].wrt == NO_SEG)
1235 warn_overflow(2, data);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001236 out(offset, segment, &data, OUT_ADDRESS + 2,
1237 ins->oprs[c - 030].segment, ins->oprs[c - 030].wrt);
1238 offset += 2;
1239 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001240
H. Peter Anvine2c80182005-01-15 22:15:51 +00001241 case 034:
1242 case 035:
1243 case 036:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001244 case 037:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001245 if (ins->oprs[c - 034].type & (BITS16 | BITS32))
1246 size = (ins->oprs[c - 034].type & BITS16) ? 2 : 4;
1247 else
1248 size = (bits == 16) ? 2 : 4;
1249 data = ins->oprs[c - 034].offset;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001250 warn_overflow(size, data);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001251 out(offset, segment, &data, OUT_ADDRESS + size,
1252 ins->oprs[c - 034].segment, ins->oprs[c - 034].wrt);
1253 offset += size;
1254 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001255
H. Peter Anvine2c80182005-01-15 22:15:51 +00001256 case 040:
1257 case 041:
1258 case 042:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001259 case 043:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001260 data = ins->oprs[c - 040].offset;
1261 out(offset, segment, &data, OUT_ADDRESS + 4,
1262 ins->oprs[c - 040].segment, ins->oprs[c - 040].wrt);
1263 offset += 4;
1264 break;
H. Peter Anvin3ba46772002-05-27 23:19:35 +00001265
H. Peter Anvine2c80182005-01-15 22:15:51 +00001266 case 044:
1267 case 045:
1268 case 046:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001269 case 047:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001270 data = ins->oprs[c - 044].offset;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001271 size = ins->addr_size >> 3;
1272 warn_overflow(size, data);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001273 out(offset, segment, &data, OUT_ADDRESS + size,
1274 ins->oprs[c - 044].segment, ins->oprs[c - 044].wrt);
1275 offset += size;
1276 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001277
H. Peter Anvine2c80182005-01-15 22:15:51 +00001278 case 050:
1279 case 051:
1280 case 052:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001281 case 053:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001282 if (ins->oprs[c - 050].segment != segment)
1283 errfunc(ERR_NONFATAL,
1284 "short relative jump outside segment");
1285 data = ins->oprs[c - 050].offset - insn_end;
1286 if (data > 127 || data < -128)
1287 errfunc(ERR_NONFATAL, "short jump is out of range");
1288 bytes[0] = data;
1289 out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG, NO_SEG);
1290 offset += 1;
1291 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001292
Keith Kaniosb7a89542007-04-12 02:40:54 +00001293 case 054:
1294 case 055:
1295 case 056:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001296 case 057:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001297 data = (int64_t)ins->oprs[c - 054].offset;
1298 out(offset, segment, &data, OUT_ADDRESS + 8,
1299 ins->oprs[c - 054].segment, ins->oprs[c - 054].wrt);
1300 offset += 8;
1301 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001302
H. Peter Anvine2c80182005-01-15 22:15:51 +00001303 case 060:
1304 case 061:
1305 case 062:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001306 case 063:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001307 if (ins->oprs[c - 060].segment != segment) {
1308 data = ins->oprs[c - 060].offset;
1309 out(offset, segment, &data,
1310 OUT_REL2ADR + insn_end - offset,
1311 ins->oprs[c - 060].segment, ins->oprs[c - 060].wrt);
1312 } else {
1313 data = ins->oprs[c - 060].offset - insn_end;
1314 out(offset, segment, &data,
1315 OUT_ADDRESS + 2, NO_SEG, NO_SEG);
1316 }
1317 offset += 2;
1318 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001319
H. Peter Anvine2c80182005-01-15 22:15:51 +00001320 case 064:
1321 case 065:
1322 case 066:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001323 case 067:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001324 if (ins->oprs[c - 064].type & (BITS16 | BITS32 | BITS64))
H. Peter Anvine2c80182005-01-15 22:15:51 +00001325 size = (ins->oprs[c - 064].type & BITS16) ? 2 : 4;
1326 else
1327 size = (bits == 16) ? 2 : 4;
1328 if (ins->oprs[c - 064].segment != segment) {
Keith Kaniosb7a89542007-04-12 02:40:54 +00001329 int32_t reltype = (size == 2 ? OUT_REL2ADR : OUT_REL4ADR);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001330 data = ins->oprs[c - 064].offset;
1331 out(offset, segment, &data, reltype + insn_end - offset,
1332 ins->oprs[c - 064].segment, ins->oprs[c - 064].wrt);
1333 } else {
1334 data = ins->oprs[c - 064].offset - insn_end;
1335 out(offset, segment, &data,
1336 OUT_ADDRESS + size, NO_SEG, NO_SEG);
1337 }
1338 offset += size;
1339 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001340
H. Peter Anvine2c80182005-01-15 22:15:51 +00001341 case 070:
1342 case 071:
1343 case 072:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001344 case 073:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001345 if (ins->oprs[c - 070].segment != segment) {
1346 data = ins->oprs[c - 070].offset;
1347 out(offset, segment, &data,
1348 OUT_REL4ADR + insn_end - offset,
1349 ins->oprs[c - 070].segment, ins->oprs[c - 070].wrt);
1350 } else {
1351 data = ins->oprs[c - 070].offset - insn_end;
1352 out(offset, segment, &data,
1353 OUT_ADDRESS + 4, NO_SEG, NO_SEG);
1354 }
1355 offset += 4;
1356 break;
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001357
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001358 case 074:
1359 case 075:
1360 case 076:
1361 case 077:
1362 if (ins->oprs[c - 074].segment == NO_SEG)
1363 errfunc(ERR_NONFATAL, "value referenced by FAR is not"
1364 " relocatable");
1365 data = 0L;
1366 out(offset, segment, &data, OUT_ADDRESS + 2,
1367 outfmt->segbase(1 + ins->oprs[c - 074].segment),
1368 ins->oprs[c - 074].wrt);
1369 offset += 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001370 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001371
H. Peter Anvine2c80182005-01-15 22:15:51 +00001372 case 0140:
1373 case 0141:
1374 case 0142:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001375 case 0143:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001376 data = ins->oprs[c - 0140].offset;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001377 if (is_sbyte(ins, c - 0140, 16)) {
1378 bytes[0] = data;
1379 out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG,
1380 NO_SEG);
1381 offset++;
1382 } else {
1383 if (ins->oprs[c - 0140].segment == NO_SEG &&
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001384 ins->oprs[c - 0140].wrt == NO_SEG)
1385 warn_overflow(2, data);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001386 out(offset, segment, &data, OUT_ADDRESS + 2,
H. Peter Anvin8f94f982007-09-17 16:31:33 -07001387 ins->oprs[c - 0140].segment, ins->oprs[c - 0140].wrt);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001388 offset += 2;
1389 }
1390 break;
1391
1392 case 0144:
1393 case 0145:
1394 case 0146:
1395 case 0147:
1396 EMIT_REX();
1397 codes++;
1398 bytes[0] = *codes++;
1399 if (is_sbyte(ins, c - 0144, 16))
1400 bytes[0] |= 2; /* s-bit */
1401 out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG, NO_SEG);
1402 offset++;
1403 break;
1404
1405 case 0150:
1406 case 0151:
1407 case 0152:
1408 case 0153:
1409 data = ins->oprs[c - 0150].offset;
1410 if (is_sbyte(ins, c - 0150, 32)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001411 bytes[0] = data;
1412 out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG,
1413 NO_SEG);
1414 offset++;
1415 } else {
1416 out(offset, segment, &data, OUT_ADDRESS + 4,
H. Peter Anvin8f94f982007-09-17 16:31:33 -07001417 ins->oprs[c - 0150].segment, ins->oprs[c - 0150].wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001418 offset += 4;
1419 }
1420 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001421
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001422 case 0154:
1423 case 0155:
1424 case 0156:
1425 case 0157:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001426 EMIT_REX();
H. Peter Anvine2c80182005-01-15 22:15:51 +00001427 codes++;
1428 bytes[0] = *codes++;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001429 if (is_sbyte(ins, c - 0154, 32))
H. Peter Anvine2c80182005-01-15 22:15:51 +00001430 bytes[0] |= 2; /* s-bit */
1431 out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG, NO_SEG);
1432 offset++;
1433 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001434
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001435 case 0160:
1436 case 0161:
1437 case 0162:
1438 case 0163:
1439 case 0164:
1440 case 0165:
1441 case 0166:
1442 case 0167:
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001443 break;
1444
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001445 case 0170:
H. Peter Anvinc189b442007-10-05 17:04:32 -07001446 EMIT_REX();
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001447 bytes[0] = 0;
1448 out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG, NO_SEG);
1449 offset += 1;
1450 break;
1451
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001452 case 0171:
1453 bytes[0] =
1454 (ins->drexdst << 4) |
1455 (ins->rex & REX_OC ? 0x08 : 0) |
1456 (ins->rex & (REX_R|REX_X|REX_B));
1457 ins->rex = 0;
1458 out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG, NO_SEG);
1459 offset++;
1460 break;
1461
H. Peter Anvine2c80182005-01-15 22:15:51 +00001462 case 0300:
1463 case 0301:
1464 case 0302:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001465 case 0303:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001466 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001467
H. Peter Anvine2c80182005-01-15 22:15:51 +00001468 case 0310:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001469 if (bits == 32 && !has_prefix(ins, PPS_ASIZE, P_A16)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001470 *bytes = 0x67;
1471 out(offset, segment, bytes,
1472 OUT_RAWDATA + 1, NO_SEG, NO_SEG);
1473 offset += 1;
1474 } else
1475 offset += 0;
1476 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001477
H. Peter Anvine2c80182005-01-15 22:15:51 +00001478 case 0311:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001479 if (bits != 32 && !has_prefix(ins, PPS_ASIZE, P_A32)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001480 *bytes = 0x67;
1481 out(offset, segment, bytes,
1482 OUT_RAWDATA + 1, NO_SEG, NO_SEG);
1483 offset += 1;
1484 } else
1485 offset += 0;
1486 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001487
H. Peter Anvine2c80182005-01-15 22:15:51 +00001488 case 0312:
1489 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001490
Keith Kaniosb7a89542007-04-12 02:40:54 +00001491 case 0313:
1492 ins->rex = 0;
1493 break;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07001494
H. Peter Anvine2c80182005-01-15 22:15:51 +00001495 case 0320:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001496 if (bits != 16) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001497 *bytes = 0x66;
1498 out(offset, segment, bytes,
1499 OUT_RAWDATA + 1, NO_SEG, NO_SEG);
1500 offset += 1;
1501 } else
1502 offset += 0;
1503 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001504
H. Peter Anvine2c80182005-01-15 22:15:51 +00001505 case 0321:
1506 if (bits == 16) {
1507 *bytes = 0x66;
1508 out(offset, segment, bytes,
1509 OUT_RAWDATA + 1, NO_SEG, NO_SEG);
1510 offset += 1;
1511 } else
1512 offset += 0;
1513 break;
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001514
H. Peter Anvine2c80182005-01-15 22:15:51 +00001515 case 0322:
H. Peter Anvin70653092007-10-19 14:42:29 -07001516 case 0323:
1517 break;
1518
Keith Kaniosb7a89542007-04-12 02:40:54 +00001519 case 0324:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001520 ins->rex |= REX_W;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001521 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001522
H. Peter Anvine2c80182005-01-15 22:15:51 +00001523 case 0330:
1524 *bytes = *codes++ ^ condval[ins->condition];
1525 out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG, NO_SEG);
1526 offset += 1;
1527 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001528
H. Peter Anvine2c80182005-01-15 22:15:51 +00001529 case 0331:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001530 break;
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001531
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001532 case 0332:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001533 case 0333:
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001534 *bytes = c - 0332 + 0xF2;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001535 out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG, NO_SEG);
1536 offset += 1;
1537 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001538
Keith Kanios48af1772007-08-17 07:37:52 +00001539 case 0334:
1540 if (ins->rex & REX_R) {
1541 *bytes = 0xF0;
1542 out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG, NO_SEG);
1543 offset += 1;
1544 }
1545 ins->rex &= ~(REX_L|REX_R);
1546 break;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001547
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001548 case 0335:
1549 break;
1550
H. Peter Anvine2c80182005-01-15 22:15:51 +00001551 case 0340:
1552 case 0341:
1553 case 0342:
1554 if (ins->oprs[0].segment != NO_SEG)
1555 errfunc(ERR_PANIC, "non-constant BSS size in pass two");
1556 else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00001557 int32_t size = ins->oprs[0].offset << (c - 0340);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001558 if (size > 0)
1559 out(offset, segment, NULL,
1560 OUT_RESERVE + size, NO_SEG, NO_SEG);
1561 offset += size;
1562 }
1563 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001564
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001565 case 0364:
1566 case 0365:
1567 break;
1568
Keith Kanios48af1772007-08-17 07:37:52 +00001569 case 0366:
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001570 case 0367:
1571 *bytes = c - 0366 + 0x66;
Keith Kanios48af1772007-08-17 07:37:52 +00001572 out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG, NO_SEG);
1573 offset += 1;
1574 break;
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001575
H. Peter Anvine2c80182005-01-15 22:15:51 +00001576 case 0370:
1577 case 0371:
1578 case 0372:
1579 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001580
H. Peter Anvine2c80182005-01-15 22:15:51 +00001581 case 0373:
1582 *bytes = bits == 16 ? 3 : 5;
1583 out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG, NO_SEG);
1584 offset += 1;
1585 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001586
H. Peter Anvine2c80182005-01-15 22:15:51 +00001587 default: /* can't do it by 'case' statements */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001588 if (c >= 0100 && c <= 0277) { /* it's an EA */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001589 ea ea_data;
1590 int rfield;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001591 int32_t rflags;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001592 uint8_t *p;
1593 int32_t s;
H. Peter Anvin70653092007-10-19 14:42:29 -07001594
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001595 if (c <= 0177) {
1596 /* pick rfield from operand b */
1597 rflags = regflag(&ins->oprs[c & 7]);
1598 rfield = regvals[ins->oprs[c & 7].basereg];
1599 } else {
1600 /* rfield is constant */
1601 rflags = 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001602 rfield = c & 7;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001603 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001604
1605 if (!process_ea
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001606 (&ins->oprs[(c >> 3) & 7], &ea_data, bits,
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001607 ins->addr_size, rfield, rflags, ins->forw_ref)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001608 errfunc(ERR_NONFATAL, "invalid effective address");
1609 }
H. Peter Anvin70653092007-10-19 14:42:29 -07001610
H. Peter Anvine2c80182005-01-15 22:15:51 +00001611 p = bytes;
1612 *p++ = ea_data.modrm;
1613 if (ea_data.sib_present)
1614 *p++ = ea_data.sib;
1615
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001616 /* DREX suffixes come between the SIB and the displacement */
1617 if (ins->rex & REX_D) {
1618 *p++ =
1619 (ins->drexdst << 4) |
1620 (ins->rex & REX_OC ? 0x08 : 0) |
1621 (ins->rex & (REX_R|REX_X|REX_B));
1622 ins->rex = 0;
1623 }
1624
H. Peter Anvine2c80182005-01-15 22:15:51 +00001625 s = p - bytes;
1626 out(offset, segment, bytes, OUT_RAWDATA + s,
1627 NO_SEG, NO_SEG);
1628
1629 switch (ea_data.bytes) {
1630 case 0:
1631 break;
1632 case 1:
1633 if (ins->oprs[(c >> 3) & 7].segment != NO_SEG) {
1634 data = ins->oprs[(c >> 3) & 7].offset;
1635 out(offset, segment, &data, OUT_ADDRESS + 1,
1636 ins->oprs[(c >> 3) & 7].segment,
1637 ins->oprs[(c >> 3) & 7].wrt);
1638 } else {
1639 *bytes = ins->oprs[(c >> 3) & 7].offset;
1640 out(offset, segment, bytes, OUT_RAWDATA + 1,
1641 NO_SEG, NO_SEG);
1642 }
1643 s++;
1644 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001645 case 8:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001646 case 2:
1647 case 4:
1648 data = ins->oprs[(c >> 3) & 7].offset;
H. Peter Anvind0b0d282007-09-28 17:17:20 -07001649 out(offset, segment, &data,
1650 (ea_data.rip ? OUT_REL4ADR : OUT_ADDRESS)
1651 + ea_data.bytes,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001652 ins->oprs[(c >> 3) & 7].segment,
1653 ins->oprs[(c >> 3) & 7].wrt);
1654 s += ea_data.bytes;
1655 break;
1656 }
1657 offset += s;
1658 } else
1659 errfunc(ERR_PANIC, "internal instruction table corrupt"
1660 ": instruction code 0x%02X given", c);
1661 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001662}
1663
H. Peter Anvin0ec60e62007-07-07 01:59:52 +00001664static int32_t regflag(const operand * o)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001665{
1666 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1667 errfunc(ERR_PANIC, "invalid operand passed to regflag()");
1668 }
1669 return reg_flags[o->basereg];
1670}
1671
H. Peter Anvin5b0e3ec2007-07-07 02:01:08 +00001672static int32_t regval(const operand * o)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001673{
H. Peter Anvine2c80182005-01-15 22:15:51 +00001674 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1675 errfunc(ERR_PANIC, "invalid operand passed to regval()");
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001676 }
H. Peter Anvin232badb2002-06-06 02:41:20 +00001677 return regvals[o->basereg];
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001678}
1679
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001680static int op_rexflags(const operand * o, int mask)
1681{
1682 int32_t flags;
1683 int val;
1684
1685 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1686 errfunc(ERR_PANIC, "invalid operand passed to op_rexflags()");
1687 }
1688
1689 flags = reg_flags[o->basereg];
1690 val = regvals[o->basereg];
1691
1692 return rexflags(val, flags, mask);
1693}
1694
1695static int rexflags(int val, int32_t flags, int mask)
1696{
1697 int rex = 0;
1698
1699 if (val >= 8)
1700 rex |= REX_B|REX_X|REX_R;
1701 if (flags & BITS64)
1702 rex |= REX_W;
1703 if (!(REG_HIGH & ~flags)) /* AH, CH, DH, BH */
1704 rex |= REX_H;
1705 else if (!(REG8 & ~flags) && val >= 4) /* SPL, BPL, SIL, DIL */
1706 rex |= REX_P;
1707
1708 return rex & mask;
1709}
1710
H. Peter Anvin3360d792007-09-11 04:16:57 +00001711static int matches(const struct itemplate *itemp, insn * instruction, int bits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001712{
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001713 int i, size[MAX_OPERANDS], asize, oprs, ret;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001714
1715 ret = 100;
1716
1717 /*
1718 * Check the opcode
1719 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001720 if (itemp->opcode != instruction->opcode)
1721 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001722
1723 /*
1724 * Count the operands
1725 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001726 if (itemp->operands != instruction->operands)
1727 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001728
1729 /*
1730 * Check that no spurious colons or TOs are present
1731 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001732 for (i = 0; i < itemp->operands; i++)
1733 if (instruction->oprs[i].type & ~itemp->opd[i] & (COLON | TO))
1734 return 0;
H. Peter Anvin70653092007-10-19 14:42:29 -07001735
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001736 /*
1737 * Check that the operand flags all match up
1738 */
H. Peter Anvin16b0a332007-09-12 20:27:41 -07001739 for (i = 0; i < itemp->operands; i++) {
H. Peter Anvincf5180a2007-09-17 17:25:27 -07001740 if (itemp->opd[i] & SAME_AS) {
1741 int j = itemp->opd[i] & ~SAME_AS;
1742 if (instruction->oprs[i].type != instruction->oprs[j].type ||
1743 instruction->oprs[i].basereg != instruction->oprs[j].basereg)
1744 return 0;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001745 } else if (itemp->opd[i] & ~instruction->oprs[i].type ||
H. Peter Anvine2c80182005-01-15 22:15:51 +00001746 ((itemp->opd[i] & SIZE_MASK) &&
1747 ((itemp->opd[i] ^ instruction->oprs[i].type) & SIZE_MASK))) {
H. Peter Anvin5a640e12007-05-29 23:57:12 +00001748 if ((itemp->opd[i] & ~instruction->oprs[i].type & ~SIZE_MASK) ||
H. Peter Anvine2c80182005-01-15 22:15:51 +00001749 (instruction->oprs[i].type & SIZE_MASK))
1750 return 0;
1751 else
H. Peter Anvine2c80182005-01-15 22:15:51 +00001752 return 1;
1753 }
H. Peter Anvin16b0a332007-09-12 20:27:41 -07001754 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001755
1756 /*
1757 * Check operand sizes
1758 */
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001759 if (itemp->flags & IF_ARMASK) {
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001760 memset(size, 0, sizeof size);
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001761
H. Peter Anvine2c80182005-01-15 22:15:51 +00001762 switch (itemp->flags & IF_ARMASK) {
1763 case IF_AR0:
1764 i = 0;
1765 break;
1766 case IF_AR1:
1767 i = 1;
1768 break;
1769 case IF_AR2:
1770 i = 2;
1771 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001772 case IF_AR3:
1773 i = 3;
1774 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001775 default:
1776 break; /* Shouldn't happen */
1777 }
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001778 switch (itemp->flags & IF_SMASK) {
1779 case IF_SB:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001780 size[i] = BITS8;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001781 break;
1782 case IF_SW:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001783 size[i] = BITS16;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001784 break;
1785 case IF_SD:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001786 size[i] = BITS32;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001787 break;
1788 case IF_SQ:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001789 size[i] = BITS64;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001790 break;
H. Peter Anvin41c9f6f2007-09-18 13:01:32 -07001791 case IF_SO:
1792 size[i] = BITS128;
1793 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001794 default:
1795 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001796 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001797 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001798 asize = 0;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001799 switch (itemp->flags & IF_SMASK) {
1800 case IF_SB:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001801 asize = BITS8;
1802 oprs = itemp->operands;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001803 break;
1804 case IF_SW:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001805 asize = BITS16;
1806 oprs = itemp->operands;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001807 break;
1808 case IF_SD:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001809 asize = BITS32;
1810 oprs = itemp->operands;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001811 break;
1812 case IF_SQ:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001813 asize = BITS64;
1814 oprs = itemp->operands;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001815 break;
H. Peter Anvin41c9f6f2007-09-18 13:01:32 -07001816 case IF_SO:
1817 asize = BITS128;
1818 oprs = itemp->operands;
1819 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001820 default:
1821 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001822 }
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001823 for (i = 0; i < MAX_OPERANDS; i++)
1824 size[i] = asize;
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001825 }
H. Peter Anvin70653092007-10-19 14:42:29 -07001826
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001827 if (itemp->flags & (IF_SM | IF_SM2)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001828 oprs = (itemp->flags & IF_SM2 ? 2 : itemp->operands);
1829 asize = 0;
1830 for (i = 0; i < oprs; i++) {
1831 if ((asize = itemp->opd[i] & SIZE_MASK) != 0) {
1832 int j;
1833 for (j = 0; j < oprs; j++)
1834 size[j] = asize;
1835 break;
1836 }
1837 }
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001838 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001839 oprs = itemp->operands;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001840 }
1841
Keith Kaniosb7a89542007-04-12 02:40:54 +00001842 for (i = 0; i < itemp->operands; i++) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001843 if (!(itemp->opd[i] & SIZE_MASK) &&
1844 (instruction->oprs[i].type & SIZE_MASK & ~size[i]))
H. Peter Anvine2c80182005-01-15 22:15:51 +00001845 return 2;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001846 }
1847
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001848 /*
1849 * Check template is okay at the set cpu level
1850 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00001851 if (((itemp->flags & IF_PLEVEL) > cpu))
H. Peter Anvine2c80182005-01-15 22:15:51 +00001852 return 3;
H. Peter Anvin70653092007-10-19 14:42:29 -07001853
Keith Kaniosb7a89542007-04-12 02:40:54 +00001854 /*
1855 * Check if instruction is available in long mode
1856 */
1857 if ((itemp->flags & IF_NOLONG) && (bits == 64))
1858 return 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001859
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001860 /*
1861 * Check if special handling needed for Jumps
1862 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00001863 if ((uint8_t)(itemp->code[0]) >= 0370)
H. Peter Anvine2c80182005-01-15 22:15:51 +00001864 return 99;
1865
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001866 return ret;
1867}
1868
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001869static ea *process_ea(operand * input, ea * output, int bits,
1870 int addrbits, int rfield, int32_t rflags, int forw_ref)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001871{
H. Peter Anvin6867acc2007-10-10 14:58:45 -07001872 output->rip = false;
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00001873
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001874 /* REX flags for the rfield operand */
1875 output->rex |= rexflags(rfield, rflags, REX_R|REX_P|REX_W|REX_H);
1876
Keith Kaniosb7a89542007-04-12 02:40:54 +00001877 if (!(REGISTER & ~input->type)) { /* register direct */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001878 int i;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001879 int32_t f;
1880
1881 if (input->basereg < EXPR_REG_START /* Verify as Register */
Keith Kaniosb7a89542007-04-12 02:40:54 +00001882 || input->basereg >= REG_ENUM_LIMIT)
H. Peter Anvine2c80182005-01-15 22:15:51 +00001883 return NULL;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001884 f = regflag(input);
Keith Kaniosb7a89542007-04-12 02:40:54 +00001885 i = regvals[input->basereg];
Keith Kaniosb7a89542007-04-12 02:40:54 +00001886
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001887 if (REG_EA & ~f)
1888 return NULL; /* Invalid EA register */
H. Peter Anvin70653092007-10-19 14:42:29 -07001889
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001890 output->rex |= op_rexflags(input, REX_B|REX_P|REX_W|REX_H);
1891
H. Peter Anvin6867acc2007-10-10 14:58:45 -07001892 output->sib_present = false; /* no SIB necessary */
Keith Kaniosb7a89542007-04-12 02:40:54 +00001893 output->bytes = 0; /* no offset necessary either */
1894 output->modrm = 0xC0 | ((rfield & 7) << 3) | (i & 7);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001895 } else { /* it's a memory reference */
1896 if (input->basereg == -1
1897 && (input->indexreg == -1 || input->scale == 0)) {
1898 /* it's a pure offset */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001899 if (bits == 64 && (~input->type & IP_REL)) {
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00001900 int scale, index, base;
H. Peter Anvin6867acc2007-10-10 14:58:45 -07001901 output->sib_present = true;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00001902 scale = 0;
1903 index = 4;
1904 base = 5;
1905 output->sib = (scale << 6) | (index << 3) | base;
1906 output->bytes = 4;
1907 output->modrm = 4 | ((rfield & 7) << 3);
H. Peter Anvin6867acc2007-10-10 14:58:45 -07001908 output->rip = false;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00001909 } else {
H. Peter Anvin6867acc2007-10-10 14:58:45 -07001910 output->sib_present = false;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00001911 output->bytes = (addrbits != 16 ? 4 : 2);
1912 output->modrm = (addrbits != 16 ? 5 : 6) | ((rfield & 7) << 3);
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001913 output->rip = bits == 64;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00001914 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001915 } else { /* it's an indirection */
1916 int i = input->indexreg, b = input->basereg, s = input->scale;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001917 int32_t o = input->offset, seg = input->segment;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001918 int hb = input->hintbase, ht = input->hinttype;
1919 int t;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001920 int it, bt;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001921 int32_t ix, bx; /* register flags */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001922
H. Peter Anvine2c80182005-01-15 22:15:51 +00001923 if (s == 0)
1924 i = -1; /* make this easy, at least */
H. Peter Anvin70653092007-10-19 14:42:29 -07001925
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001926 if (i >= EXPR_REG_START && i < REG_ENUM_LIMIT) {
Keith Kaniosb7a89542007-04-12 02:40:54 +00001927 it = regvals[i];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001928 ix = reg_flags[i];
1929 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00001930 it = -1;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001931 ix = 0;
1932 }
H. Peter Anvin70653092007-10-19 14:42:29 -07001933
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001934 if (b != -1 && b >= EXPR_REG_START && b < REG_ENUM_LIMIT) {
Keith Kaniosb7a89542007-04-12 02:40:54 +00001935 bt = regvals[b];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001936 bx = reg_flags[b];
1937 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00001938 bt = -1;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001939 bx = 0;
1940 }
H. Peter Anvin70653092007-10-19 14:42:29 -07001941
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001942 /* check for a 32/64-bit memory reference... */
1943 if ((ix|bx) & (BITS32|BITS64)) {
Keith Kaniosb7a89542007-04-12 02:40:54 +00001944 /* it must be a 32/64-bit memory reference. Firstly we have
1945 * to check that all registers involved are type E/Rxx. */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001946 int32_t sok = BITS32|BITS64;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001947
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001948 if (it != -1) {
1949 if (!(REG64 & ~ix) || !(REG32 & ~ix))
1950 sok &= ix;
1951 else
1952 return NULL;
1953 }
1954
1955 if (bt != -1) {
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00001956 if (REG_GPR & ~bx)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001957 return NULL; /* Invalid register */
H. Peter Anvina57e8d42007-05-30 03:44:02 +00001958 if (~sok & bx & SIZE_MASK)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001959 return NULL; /* Invalid size */
1960 sok &= ~bx;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001961 }
H. Peter Anvin70653092007-10-19 14:42:29 -07001962
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001963 /* While we're here, ensure the user didn't specify
1964 WORD or QWORD. */
1965 if (input->disp_size == 16 || input->disp_size == 64)
1966 return NULL;
1967
1968 if (addrbits == 16 ||
1969 (addrbits == 32 && !(sok & BITS32)) ||
1970 (addrbits == 64 && !(sok & BITS64)))
1971 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001972
Keith Kaniosb7a89542007-04-12 02:40:54 +00001973 /* now reorganize base/index */
1974 if (s == 1 && bt != it && bt != -1 && it != -1 &&
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001975 ((hb == b && ht == EAH_NOTBASE)
1976 || (hb == i && ht == EAH_MAKEBASE))) {
1977 /* swap if hints say so */
1978 t = bt, bt = it, it = t;
1979 t = bx, bx = ix, ix = t;
1980 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00001981 if (bt == it) /* convert EAX+2*EAX to 3*EAX */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001982 bt = -1, bx = 0, s++;
1983 if (bt == -1 && s == 1 && !(hb == it && ht == EAH_NOTBASE)) {
1984 /* make single reg base, unless hint */
1985 bt = it, bx = ix, it = -1, ix = 0;
1986 }
H. Peter Anvinf5843c62007-09-10 18:59:26 +00001987 if (((s == 2 && it != REG_NUM_ESP
H. Peter Anvine2c80182005-01-15 22:15:51 +00001988 && !(input->eaflags & EAF_TIMESTWO)) || s == 3
Keith Kaniosb7a89542007-04-12 02:40:54 +00001989 || s == 5 || s == 9) && bt == -1)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001990 bt = it, bx = ix, s--; /* convert 3*EAX to EAX+2*EAX */
Keith Kanios48af1772007-08-17 07:37:52 +00001991 if (it == -1 && (bt & 7) != REG_NUM_ESP
H. Peter Anvine2c80182005-01-15 22:15:51 +00001992 && (input->eaflags & EAF_TIMESTWO))
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001993 it = bt, ix = bx, bt = -1, bx = 0, s = 1;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001994 /* convert [NOSPLIT EAX] to sib format with 0x0 displacement */
Keith Kanios48af1772007-08-17 07:37:52 +00001995 if (s == 1 && it == REG_NUM_ESP) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001996 /* swap ESP into base if scale is 1 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00001997 t = it, it = bt, bt = t;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001998 t = ix, ix = bx, bx = t;
1999 }
Keith Kanios48af1772007-08-17 07:37:52 +00002000 if (it == REG_NUM_ESP
Keith Kaniosb7a89542007-04-12 02:40:54 +00002001 || (s != 1 && s != 2 && s != 4 && s != 8 && it != -1))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002002 return NULL; /* wrong, for various reasons */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002003
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002004 output->rex |= rexflags(it, ix, REX_X);
2005 output->rex |= rexflags(bt, bx, REX_B);
Keith Kaniosb7a89542007-04-12 02:40:54 +00002006
Keith Kanios48af1772007-08-17 07:37:52 +00002007 if (it == -1 && (bt & 7) != REG_NUM_ESP) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002008 /* no SIB needed */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002009 int mod, rm;
H. Peter Anvin70653092007-10-19 14:42:29 -07002010
Keith Kaniosb7a89542007-04-12 02:40:54 +00002011 if (bt == -1) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002012 rm = 5;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002013 mod = 0;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002014 } else {
2015 rm = (bt & 7);
Keith Kanios48af1772007-08-17 07:37:52 +00002016 if (rm != REG_NUM_EBP && o == 0 &&
Keith Kaniosb7a89542007-04-12 02:40:54 +00002017 seg == NO_SEG && !forw_ref &&
2018 !(input->eaflags &
2019 (EAF_BYTEOFFS | EAF_WORDOFFS)))
2020 mod = 0;
2021 else if (input->eaflags & EAF_BYTEOFFS ||
2022 (o >= -128 && o <= 127 && seg == NO_SEG
2023 && !forw_ref
2024 && !(input->eaflags & EAF_WORDOFFS)))
2025 mod = 1;
2026 else
2027 mod = 2;
2028 }
H. Peter Anvinea838272002-04-30 20:51:53 +00002029
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002030 output->sib_present = false;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002031 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2032 output->modrm = (mod << 6) | ((rfield & 7) << 3) | rm;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002033 } else {
2034 /* we need a SIB */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002035 int mod, scale, index, base;
H. Peter Anvin70653092007-10-19 14:42:29 -07002036
Keith Kaniosb7a89542007-04-12 02:40:54 +00002037 if (it == -1)
2038 index = 4, s = 1;
2039 else
2040 index = (it & 7);
H. Peter Anvin70653092007-10-19 14:42:29 -07002041
H. Peter Anvine2c80182005-01-15 22:15:51 +00002042 switch (s) {
2043 case 1:
2044 scale = 0;
2045 break;
2046 case 2:
2047 scale = 1;
2048 break;
2049 case 4:
2050 scale = 2;
2051 break;
2052 case 8:
2053 scale = 3;
2054 break;
2055 default: /* then what the smeg is it? */
2056 return NULL; /* panic */
2057 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002058
Keith Kaniosb7a89542007-04-12 02:40:54 +00002059 if (bt == -1) {
2060 base = 5;
2061 mod = 0;
2062 } else {
2063 base = (bt & 7);
Keith Kanios48af1772007-08-17 07:37:52 +00002064 if (base != REG_NUM_EBP && o == 0 &&
H. Peter Anvine2c80182005-01-15 22:15:51 +00002065 seg == NO_SEG && !forw_ref &&
2066 !(input->eaflags &
Keith Kaniosb7a89542007-04-12 02:40:54 +00002067 (EAF_BYTEOFFS | EAF_WORDOFFS)))
2068 mod = 0;
2069 else if (input->eaflags & EAF_BYTEOFFS ||
2070 (o >= -128 && o <= 127 && seg == NO_SEG
2071 && !forw_ref
2072 && !(input->eaflags & EAF_WORDOFFS)))
2073 mod = 1;
2074 else
2075 mod = 2;
2076 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002077
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002078 output->sib_present = true;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002079 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2080 output->modrm = (mod << 6) | ((rfield & 7) << 3) | 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002081 output->sib = (scale << 6) | (index << 3) | base;
2082 }
2083 } else { /* it's 16-bit */
2084 int mod, rm;
H. Peter Anvin70653092007-10-19 14:42:29 -07002085
Keith Kaniosb7a89542007-04-12 02:40:54 +00002086 /* check for 64-bit long mode */
2087 if (addrbits == 64)
2088 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002089
H. Peter Anvine2c80182005-01-15 22:15:51 +00002090 /* check all registers are BX, BP, SI or DI */
2091 if ((b != -1 && b != R_BP && b != R_BX && b != R_SI
2092 && b != R_DI) || (i != -1 && i != R_BP && i != R_BX
2093 && i != R_SI && i != R_DI))
2094 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002095
Keith Kaniosb7a89542007-04-12 02:40:54 +00002096 /* ensure the user didn't specify DWORD/QWORD */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002097 if (input->disp_size == 32 || input->disp_size == 64)
H. Peter Anvine2c80182005-01-15 22:15:51 +00002098 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002099
H. Peter Anvine2c80182005-01-15 22:15:51 +00002100 if (s != 1 && i != -1)
2101 return NULL; /* no can do, in 16-bit EA */
2102 if (b == -1 && i != -1) {
2103 int tmp = b;
2104 b = i;
2105 i = tmp;
2106 } /* swap */
2107 if ((b == R_SI || b == R_DI) && i != -1) {
2108 int tmp = b;
2109 b = i;
2110 i = tmp;
2111 }
2112 /* have BX/BP as base, SI/DI index */
2113 if (b == i)
2114 return NULL; /* shouldn't ever happen, in theory */
2115 if (i != -1 && b != -1 &&
2116 (i == R_BP || i == R_BX || b == R_SI || b == R_DI))
2117 return NULL; /* invalid combinations */
2118 if (b == -1) /* pure offset: handled above */
2119 return NULL; /* so if it gets to here, panic! */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002120
H. Peter Anvine2c80182005-01-15 22:15:51 +00002121 rm = -1;
2122 if (i != -1)
2123 switch (i * 256 + b) {
2124 case R_SI * 256 + R_BX:
2125 rm = 0;
2126 break;
2127 case R_DI * 256 + R_BX:
2128 rm = 1;
2129 break;
2130 case R_SI * 256 + R_BP:
2131 rm = 2;
2132 break;
2133 case R_DI * 256 + R_BP:
2134 rm = 3;
2135 break;
2136 } else
2137 switch (b) {
2138 case R_SI:
2139 rm = 4;
2140 break;
2141 case R_DI:
2142 rm = 5;
2143 break;
2144 case R_BP:
2145 rm = 6;
2146 break;
2147 case R_BX:
2148 rm = 7;
2149 break;
2150 }
2151 if (rm == -1) /* can't happen, in theory */
2152 return NULL; /* so panic if it does */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002153
H. Peter Anvine2c80182005-01-15 22:15:51 +00002154 if (o == 0 && seg == NO_SEG && !forw_ref && rm != 6 &&
2155 !(input->eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS)))
2156 mod = 0;
2157 else if (input->eaflags & EAF_BYTEOFFS ||
2158 (o >= -128 && o <= 127 && seg == NO_SEG
2159 && !forw_ref
2160 && !(input->eaflags & EAF_WORDOFFS)))
2161 mod = 1;
2162 else
2163 mod = 2;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002164
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002165 output->sib_present = false; /* no SIB - it's 16-bit */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002166 output->bytes = mod; /* bytes of offset needed */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002167 output->modrm = (mod << 6) | ((rfield & 7) << 3) | rm;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002168 }
2169 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002170 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002171
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002172 output->size = 1 + output->sib_present + output->bytes;
2173 return output;
2174}
2175
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002176static void add_asp(insn *ins, int addrbits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002177{
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002178 int j, valid;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002179 int defdisp;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002180
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002181 valid = (addrbits == 64) ? 64|32 : 32|16;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002182
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002183 switch (ins->prefixes[PPS_ASIZE]) {
2184 case P_A16:
2185 valid &= 16;
2186 break;
2187 case P_A32:
2188 valid &= 32;
2189 break;
2190 case P_A64:
2191 valid &= 64;
2192 break;
2193 case P_ASP:
2194 valid &= (addrbits == 32) ? 16 : 32;
2195 break;
2196 default:
2197 break;
2198 }
2199
2200 for (j = 0; j < ins->operands; j++) {
2201 if (!(MEMORY & ~ins->oprs[j].type)) {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002202 int32_t i, b;
H. Peter Anvin70653092007-10-19 14:42:29 -07002203
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002204 /* Verify as Register */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002205 if (ins->oprs[j].indexreg < EXPR_REG_START
2206 || ins->oprs[j].indexreg >= REG_ENUM_LIMIT)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002207 i = 0;
2208 else
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002209 i = reg_flags[ins->oprs[j].indexreg];
H. Peter Anvin70653092007-10-19 14:42:29 -07002210
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002211 /* Verify as Register */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002212 if (ins->oprs[j].basereg < EXPR_REG_START
2213 || ins->oprs[j].basereg >= REG_ENUM_LIMIT)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002214 b = 0;
2215 else
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002216 b = reg_flags[ins->oprs[j].basereg];
H. Peter Anvin70653092007-10-19 14:42:29 -07002217
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002218 if (ins->oprs[j].scale == 0)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002219 i = 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002220
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002221 if (!i && !b) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002222 int ds = ins->oprs[j].disp_size;
2223 if ((addrbits != 64 && ds > 8) ||
2224 (addrbits == 64 && ds == 16))
2225 valid &= ds;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002226 } else {
2227 if (!(REG16 & ~b))
2228 valid &= 16;
2229 if (!(REG32 & ~b))
2230 valid &= 32;
2231 if (!(REG64 & ~b))
2232 valid &= 64;
H. Peter Anvin70653092007-10-19 14:42:29 -07002233
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002234 if (!(REG16 & ~i))
2235 valid &= 16;
2236 if (!(REG32 & ~i))
2237 valid &= 32;
2238 if (!(REG64 & ~i))
2239 valid &= 64;
2240 }
2241 }
2242 }
2243
2244 if (valid & addrbits) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002245 ins->addr_size = addrbits;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002246 } else if (valid & ((addrbits == 32) ? 16 : 32)) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002247 /* Add an address size prefix */
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002248 enum prefixes pref = (addrbits == 32) ? P_A16 : P_A32;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002249 ins->prefixes[PPS_ASIZE] = pref;
2250 ins->addr_size = (addrbits == 32) ? 16 : 32;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002251 } else {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002252 /* Impossible... */
2253 errfunc(ERR_NONFATAL, "impossible combination of address sizes");
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002254 ins->addr_size = addrbits; /* Error recovery */
2255 }
2256
2257 defdisp = ins->addr_size == 16 ? 16 : 32;
2258
2259 for (j = 0; j < ins->operands; j++) {
2260 if (!(MEM_OFFS & ~ins->oprs[j].type) &&
2261 (ins->oprs[j].disp_size ? ins->oprs[j].disp_size : defdisp)
2262 != ins->addr_size) {
2263 /* mem_offs sizes must match the address size; if not,
2264 strip the MEM_OFFS bit and match only EA instructions */
2265 ins->oprs[j].type &= ~(MEM_OFFS & ~MEMORY);
2266 }
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002267 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002268}