blob: 6f229e25bc1d9d1accef3eb155d018ccf98d3897 [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) {
Charles Craynedd462c82007-11-04 15:28:30 -0800155 int64_t lim = ((int64_t)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,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800478 "cs segment base generated, but will be ignored in 64-bit mode");
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000479 }
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,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800485 "ds segment base generated, but will be ignored in 64-bit mode");
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000486 }
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,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800492 "es segment base generated, but will be ignored in 64-bit mode");
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000493 }
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,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800505 "ss segment base generated, but will be ignored in 64-bit mode");
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000506 }
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 Anvin839eca22007-10-29 23:12:47 -0700791 struct operand *opx;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000792
H. Peter Anvine3917fc2007-11-01 14:53:32 -0700793 ins->rex = 0; /* Ensure REX is reset */
794
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700795 if (ins->prefixes[PPS_OSIZE] == P_O64)
796 ins->rex |= REX_W;
797
H. Peter Anvine2c80182005-01-15 22:15:51 +0000798 (void)segment; /* Don't warn that this parameter is unused */
799 (void)offset; /* Don't warn that this parameter is unused */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000800
H. Peter Anvin839eca22007-10-29 23:12:47 -0700801 while (*codes) {
802 c = *codes++;
803 opx = &ins->oprs[c & 3];
804 switch (c) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000805 case 01:
806 case 02:
807 case 03:
808 codes += c, length += c;
809 break;
810 case 04:
811 case 05:
812 case 06:
813 case 07:
814 length++;
815 break;
816 case 010:
817 case 011:
818 case 012:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700819 case 013:
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000820 ins->rex |=
H. Peter Anvin839eca22007-10-29 23:12:47 -0700821 op_rexflags(opx, REX_B|REX_H|REX_P|REX_W);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000822 codes++, length++;
823 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000824 case 014:
825 case 015:
826 case 016:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700827 case 017:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000828 length++;
829 break;
830 case 020:
831 case 021:
832 case 022:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700833 case 023:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000834 length++;
835 break;
836 case 024:
837 case 025:
838 case 026:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700839 case 027:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000840 length++;
841 break;
842 case 030:
843 case 031:
844 case 032:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700845 case 033:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000846 length += 2;
847 break;
848 case 034:
849 case 035:
850 case 036:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700851 case 037:
H. Peter Anvin839eca22007-10-29 23:12:47 -0700852 if (opx->type & (BITS16 | BITS32 | BITS64))
853 length += (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000854 else
855 length += (bits == 16) ? 2 : 4;
856 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000857 case 040:
858 case 041:
859 case 042:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700860 case 043:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000861 length += 4;
862 break;
863 case 044:
864 case 045:
865 case 046:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700866 case 047:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700867 length += ins->addr_size >> 3;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000868 break;
869 case 050:
870 case 051:
871 case 052:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700872 case 053:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000873 length++;
874 break;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000875 case 054:
876 case 055:
877 case 056:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700878 case 057:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000879 length += 8; /* MOV reg64/imm */
880 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000881 case 060:
882 case 061:
883 case 062:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700884 case 063:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000885 length += 2;
886 break;
887 case 064:
888 case 065:
889 case 066:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700890 case 067:
H. Peter Anvin839eca22007-10-29 23:12:47 -0700891 if (opx->type & (BITS16 | BITS32 | BITS64))
892 length += (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000893 else
894 length += (bits == 16) ? 2 : 4;
895 break;
896 case 070:
897 case 071:
898 case 072:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700899 case 073:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000900 length += 4;
901 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700902 case 074:
903 case 075:
904 case 076:
905 case 077:
906 length += 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000907 break;
908 case 0140:
909 case 0141:
910 case 0142:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700911 case 0143:
H. Peter Anvin839eca22007-10-29 23:12:47 -0700912 length += is_sbyte(ins, c & 3, 16) ? 1 : 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000913 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000914 case 0144:
915 case 0145:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700916 case 0146:
917 case 0147:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000918 codes += 2;
919 length++;
920 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700921 case 0150:
922 case 0151:
923 case 0152:
924 case 0153:
H. Peter Anvin839eca22007-10-29 23:12:47 -0700925 length += is_sbyte(ins, c & 3, 32) ? 1 : 4;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700926 break;
927 case 0154:
928 case 0155:
929 case 0156:
930 case 0157:
931 codes += 2;
932 length++;
933 break;
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700934 case 0160:
935 case 0161:
936 case 0162:
937 case 0163:
938 length++;
939 ins->rex |= REX_D;
H. Peter Anvincf5180a2007-09-17 17:25:27 -0700940 ins->drexdst = regval(&ins->oprs[c & 3]);
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700941 break;
942 case 0164:
943 case 0165:
944 case 0166:
945 case 0167:
946 length++;
947 ins->rex |= REX_D|REX_OC;
H. Peter Anvincf5180a2007-09-17 17:25:27 -0700948 ins->drexdst = regval(&ins->oprs[c & 3]);
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700949 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700950 case 0170:
951 length++;
952 break;
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700953 case 0171:
954 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000955 case 0300:
956 case 0301:
H. Peter Anvin70653092007-10-19 14:42:29 -0700957 case 0302:
958 case 0303:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000959 break;
960 case 0310:
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700961 if (bits == 64)
962 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700963 length += (bits != 16) && !has_prefix(ins, PPS_ASIZE, P_A16);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000964 break;
965 case 0311:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700966 length += (bits != 32) && !has_prefix(ins, PPS_ASIZE, P_A32);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000967 break;
968 case 0312:
H. Peter Anvin70653092007-10-19 14:42:29 -0700969 break;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000970 case 0313:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700971 if (bits != 64 || has_prefix(ins, PPS_ASIZE, P_A16) ||
972 has_prefix(ins, PPS_ASIZE, P_A32))
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700973 return -1;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000974 break;
975 case 0320:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000976 length += (bits != 16);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000977 break;
978 case 0321:
979 length += (bits == 16);
980 break;
981 case 0322:
982 break;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000983 case 0323:
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000984 rex_mask &= ~REX_W;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000985 break;
986 case 0324:
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000987 ins->rex |= REX_W;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +0000988 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000989 case 0330:
990 codes++, length++;
991 break;
992 case 0331:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000993 break;
H. Peter Anvincb9b6902007-09-12 21:58:51 -0700994 case 0332:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000995 case 0333:
996 length++;
997 break;
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000998 case 0334:
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000999 ins->rex |= REX_L;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001000 break;
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001001 case 0335:
1002 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001003 case 0340:
1004 case 0341:
1005 case 0342:
1006 if (ins->oprs[0].segment != NO_SEG)
1007 errfunc(ERR_NONFATAL, "attempt to reserve non-constant"
1008 " quantity of BSS space");
1009 else
H. Peter Anvin839eca22007-10-29 23:12:47 -07001010 length += ins->oprs[0].offset << (c & 3);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001011 break;
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001012 case 0364:
1013 case 0365:
1014 break;
Keith Kanios48af1772007-08-17 07:37:52 +00001015 case 0366:
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001016 case 0367:
1017 length++;
1018 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001019 case 0370:
1020 case 0371:
1021 case 0372:
1022 break;
1023 case 0373:
1024 length++;
1025 break;
1026 default: /* can't do it by 'case' statements */
1027 if (c >= 0100 && c <= 0277) { /* it's an EA */
1028 ea ea_data;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001029 int rfield;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001030 int32_t rflags;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001031 ea_data.rex = 0; /* Ensure ea.REX is initially 0 */
H. Peter Anvin70653092007-10-19 14:42:29 -07001032
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001033 if (c <= 0177) {
1034 /* pick rfield from operand b */
1035 rflags = regflag(&ins->oprs[c & 7]);
1036 rfield = regvals[ins->oprs[c & 7].basereg];
1037 } else {
1038 rflags = 0;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001039 rfield = c & 7;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001040 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00001041
H. Peter Anvine2c80182005-01-15 22:15:51 +00001042 if (!process_ea
Keith Kaniosb7a89542007-04-12 02:40:54 +00001043 (&ins->oprs[(c >> 3) & 7], &ea_data, bits,
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001044 ins->addr_size, rfield, rflags, ins->forw_ref)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001045 errfunc(ERR_NONFATAL, "invalid effective address");
1046 return -1;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001047 } else {
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001048 ins->rex |= ea_data.rex;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001049 length += ea_data.size;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001050 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001051 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001052 errfunc(ERR_PANIC, "internal instruction table corrupt"
1053 ": instruction code 0x%02X given", c);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001054 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001055 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001056 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001057
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001058 ins->rex &= rex_mask;
H. Peter Anvin70653092007-10-19 14:42:29 -07001059
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001060 if (ins->rex & REX_D) {
1061 if (ins->rex & REX_H) {
1062 errfunc(ERR_NONFATAL, "cannot use high register in drex instruction");
1063 return -1;
1064 }
H. Peter Anvincf5180a2007-09-17 17:25:27 -07001065 if (bits != 64 && ((ins->rex & (REX_W|REX_X|REX_B)) ||
1066 ins->drexdst > 7)) {
1067 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1068 return -1;
1069 }
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001070 length++;
1071 } else if (ins->rex & REX_REAL) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001072 if (ins->rex & REX_H) {
1073 errfunc(ERR_NONFATAL, "cannot use high register in rex instruction");
1074 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001075 } else if (bits == 64) {
1076 length++;
1077 } else if ((ins->rex & REX_L) &&
1078 !(ins->rex & (REX_P|REX_W|REX_X|REX_B)) &&
1079 cpu >= IF_X86_64) {
1080 /* LOCK-as-REX.R */
1081 assert_no_prefix(ins, PPS_LREP);
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001082 length++;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001083 } else {
H. Peter Anvincf5180a2007-09-17 17:25:27 -07001084 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1085 return -1;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001086 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00001087 }
1088
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001089 return length;
1090}
Keith Kaniosb7a89542007-04-12 02:40:54 +00001091
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001092#define EMIT_REX() \
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001093 if (!(ins->rex & REX_D) && (ins->rex & REX_REAL) && (bits == 64)) { \
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001094 ins->rex = (ins->rex & REX_REAL)|REX_P; \
1095 out(offset, segment, &ins->rex, OUT_RAWDATA+1, NO_SEG, NO_SEG); \
1096 ins->rex = 0; \
1097 offset += 1; \
1098 }
1099
Keith Kaniosb7a89542007-04-12 02:40:54 +00001100static void gencode(int32_t segment, int32_t offset, int bits,
Keith Kaniosa6dfa782007-04-13 16:47:53 +00001101 insn * ins, const char *codes, int32_t insn_end)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001102{
Keith Kaniosa6dfa782007-04-13 16:47:53 +00001103 static char condval[] = { /* conditional opcodes */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001104 0x7, 0x3, 0x2, 0x6, 0x2, 0x4, 0xF, 0xD, 0xC, 0xE, 0x6, 0x2,
1105 0x3, 0x7, 0x3, 0x5, 0xE, 0xC, 0xD, 0xF, 0x1, 0xB, 0x9, 0x5,
1106 0x0, 0xA, 0xA, 0xB, 0x8, 0x4
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001107 };
Keith Kaniosb7a89542007-04-12 02:40:54 +00001108 uint8_t c;
1109 uint8_t bytes[4];
1110 int32_t size;
1111 int64_t data;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001112 struct operand *opx;
H. Peter Anvin70653092007-10-19 14:42:29 -07001113
H. Peter Anvin839eca22007-10-29 23:12:47 -07001114 while (*codes) {
1115 c = *codes++;
1116 opx = &ins->oprs[c & 3];
1117 switch (c) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001118 case 01:
1119 case 02:
1120 case 03:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001121 EMIT_REX();
H. Peter Anvine2c80182005-01-15 22:15:51 +00001122 out(offset, segment, codes, OUT_RAWDATA + c, NO_SEG, NO_SEG);
1123 codes += c;
1124 offset += c;
1125 break;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001126
H. Peter Anvine2c80182005-01-15 22:15:51 +00001127 case 04:
1128 case 06:
1129 switch (ins->oprs[0].basereg) {
1130 case R_CS:
1131 bytes[0] = 0x0E + (c == 0x04 ? 1 : 0);
1132 break;
1133 case R_DS:
1134 bytes[0] = 0x1E + (c == 0x04 ? 1 : 0);
1135 break;
1136 case R_ES:
1137 bytes[0] = 0x06 + (c == 0x04 ? 1 : 0);
1138 break;
1139 case R_SS:
1140 bytes[0] = 0x16 + (c == 0x04 ? 1 : 0);
1141 break;
1142 default:
1143 errfunc(ERR_PANIC,
1144 "bizarre 8086 segment register received");
1145 }
1146 out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG, NO_SEG);
1147 offset++;
1148 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001149
H. Peter Anvine2c80182005-01-15 22:15:51 +00001150 case 05:
1151 case 07:
1152 switch (ins->oprs[0].basereg) {
1153 case R_FS:
1154 bytes[0] = 0xA0 + (c == 0x05 ? 1 : 0);
1155 break;
1156 case R_GS:
1157 bytes[0] = 0xA8 + (c == 0x05 ? 1 : 0);
1158 break;
1159 default:
1160 errfunc(ERR_PANIC,
1161 "bizarre 386 segment register received");
1162 }
1163 out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG, NO_SEG);
1164 offset++;
1165 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001166
H. Peter Anvine2c80182005-01-15 22:15:51 +00001167 case 010:
1168 case 011:
1169 case 012:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001170 case 013:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001171 EMIT_REX();
H. Peter Anvin839eca22007-10-29 23:12:47 -07001172 bytes[0] = *codes++ + ((regval(opx)) & 7);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001173 out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG, NO_SEG);
1174 offset += 1;
1175 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001176
H. Peter Anvine2c80182005-01-15 22:15:51 +00001177 case 014:
1178 case 015:
1179 case 016:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001180 case 017:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001181 if (opx->offset < -128 || opx->offset > 127) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001182 errfunc(ERR_WARNING, "signed byte value exceeds bounds");
1183 }
H. Peter Anvineba20a72002-04-30 20:53:55 +00001184
H. Peter Anvin839eca22007-10-29 23:12:47 -07001185 if (opx->segment != NO_SEG) {
1186 data = opx->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001187 out(offset, segment, &data, OUT_ADDRESS + 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001188 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001189 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001190 bytes[0] = opx->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001191 out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG,
1192 NO_SEG);
1193 }
1194 offset += 1;
1195 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001196
H. Peter Anvine2c80182005-01-15 22:15:51 +00001197 case 020:
1198 case 021:
1199 case 022:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001200 case 023:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001201 if (opx->offset < -256 || opx->offset > 255) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001202 errfunc(ERR_WARNING, "byte value exceeds bounds");
1203 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001204 if (opx->segment != NO_SEG) {
1205 data = opx->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001206 out(offset, segment, &data, OUT_ADDRESS + 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001207 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001208 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001209 bytes[0] = opx->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001210 out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG,
1211 NO_SEG);
1212 }
1213 offset += 1;
1214 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001215
H. Peter Anvine2c80182005-01-15 22:15:51 +00001216 case 024:
1217 case 025:
1218 case 026:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001219 case 027:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001220 if (opx->offset < 0 || opx->offset > 255)
H. Peter Anvine2c80182005-01-15 22:15:51 +00001221 errfunc(ERR_WARNING, "unsigned byte value exceeds bounds");
H. Peter Anvin839eca22007-10-29 23:12:47 -07001222 if (opx->segment != NO_SEG) {
1223 data = opx->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001224 out(offset, segment, &data, OUT_ADDRESS + 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001225 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001226 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001227 bytes[0] = opx->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001228 out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG,
1229 NO_SEG);
1230 }
1231 offset += 1;
1232 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001233
H. Peter Anvine2c80182005-01-15 22:15:51 +00001234 case 030:
1235 case 031:
1236 case 032:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001237 case 033:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001238 data = opx->offset;
1239 if (opx->segment == NO_SEG && opx->wrt == NO_SEG)
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001240 warn_overflow(2, data);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001241 out(offset, segment, &data, OUT_ADDRESS + 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001242 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001243 offset += 2;
1244 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001245
H. Peter Anvine2c80182005-01-15 22:15:51 +00001246 case 034:
1247 case 035:
1248 case 036:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001249 case 037:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001250 if (opx->type & (BITS16 | BITS32))
1251 size = (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001252 else
1253 size = (bits == 16) ? 2 : 4;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001254 data = opx->offset;
1255 if (opx->segment == NO_SEG && opx->wrt == NO_SEG)
H. Peter Anvin10e27272007-10-29 22:56:08 -07001256 warn_overflow(size, data);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001257 out(offset, segment, &data, OUT_ADDRESS + size,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001258 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001259 offset += size;
1260 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001261
H. Peter Anvine2c80182005-01-15 22:15:51 +00001262 case 040:
1263 case 041:
1264 case 042:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001265 case 043:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001266 data = opx->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001267 out(offset, segment, &data, OUT_ADDRESS + 4,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001268 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001269 offset += 4;
1270 break;
H. Peter Anvin3ba46772002-05-27 23:19:35 +00001271
H. Peter Anvine2c80182005-01-15 22:15:51 +00001272 case 044:
1273 case 045:
1274 case 046:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001275 case 047:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001276 data = opx->offset;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001277 size = ins->addr_size >> 3;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001278 if (opx->segment == NO_SEG &&
1279 opx->wrt == NO_SEG)
H. Peter Anvin10e27272007-10-29 22:56:08 -07001280 warn_overflow(size, data);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001281 out(offset, segment, &data, OUT_ADDRESS + size,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001282 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001283 offset += size;
1284 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001285
H. Peter Anvine2c80182005-01-15 22:15:51 +00001286 case 050:
1287 case 051:
1288 case 052:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001289 case 053:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001290 if (opx->segment != segment)
H. Peter Anvine2c80182005-01-15 22:15:51 +00001291 errfunc(ERR_NONFATAL,
1292 "short relative jump outside segment");
H. Peter Anvin839eca22007-10-29 23:12:47 -07001293 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001294 if (data > 127 || data < -128)
1295 errfunc(ERR_NONFATAL, "short jump is out of range");
1296 bytes[0] = data;
1297 out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG, NO_SEG);
1298 offset += 1;
1299 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001300
Keith Kaniosb7a89542007-04-12 02:40:54 +00001301 case 054:
1302 case 055:
1303 case 056:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001304 case 057:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001305 data = (int64_t)opx->offset;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001306 out(offset, segment, &data, OUT_ADDRESS + 8,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001307 opx->segment, opx->wrt);
Keith Kaniosb7a89542007-04-12 02:40:54 +00001308 offset += 8;
1309 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001310
H. Peter Anvine2c80182005-01-15 22:15:51 +00001311 case 060:
1312 case 061:
1313 case 062:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001314 case 063:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001315 if (opx->segment != segment) {
1316 data = opx->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001317 out(offset, segment, &data,
1318 OUT_REL2ADR + insn_end - offset,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001319 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001320 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001321 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001322 out(offset, segment, &data,
1323 OUT_ADDRESS + 2, NO_SEG, NO_SEG);
1324 }
1325 offset += 2;
1326 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001327
H. Peter Anvine2c80182005-01-15 22:15:51 +00001328 case 064:
1329 case 065:
1330 case 066:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001331 case 067:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001332 if (opx->type & (BITS16 | BITS32 | BITS64))
1333 size = (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001334 else
1335 size = (bits == 16) ? 2 : 4;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001336 if (opx->segment != segment) {
Keith Kaniosb7a89542007-04-12 02:40:54 +00001337 int32_t reltype = (size == 2 ? OUT_REL2ADR : OUT_REL4ADR);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001338 data = opx->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001339 out(offset, segment, &data, reltype + insn_end - offset,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001340 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001341 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001342 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001343 out(offset, segment, &data,
1344 OUT_ADDRESS + size, NO_SEG, NO_SEG);
1345 }
1346 offset += size;
1347 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001348
H. Peter Anvine2c80182005-01-15 22:15:51 +00001349 case 070:
1350 case 071:
1351 case 072:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001352 case 073:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001353 if (opx->segment != segment) {
1354 data = opx->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001355 out(offset, segment, &data,
1356 OUT_REL4ADR + insn_end - offset,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001357 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001358 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001359 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001360 out(offset, segment, &data,
1361 OUT_ADDRESS + 4, NO_SEG, NO_SEG);
1362 }
1363 offset += 4;
1364 break;
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001365
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001366 case 074:
1367 case 075:
1368 case 076:
1369 case 077:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001370 if (opx->segment == NO_SEG)
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001371 errfunc(ERR_NONFATAL, "value referenced by FAR is not"
1372 " relocatable");
1373 data = 0L;
1374 out(offset, segment, &data, OUT_ADDRESS + 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001375 outfmt->segbase(1 + opx->segment),
1376 opx->wrt);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001377 offset += 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001378 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001379
H. Peter Anvine2c80182005-01-15 22:15:51 +00001380 case 0140:
1381 case 0141:
1382 case 0142:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001383 case 0143:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001384 data = opx->offset;
1385 if (is_sbyte(ins, c & 3, 16)) {
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001386 bytes[0] = data;
1387 out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG,
1388 NO_SEG);
1389 offset++;
1390 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001391 if (opx->segment == NO_SEG &&
1392 opx->wrt == NO_SEG)
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001393 warn_overflow(2, data);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001394 out(offset, segment, &data, OUT_ADDRESS + 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001395 opx->segment, opx->wrt);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001396 offset += 2;
1397 }
1398 break;
1399
1400 case 0144:
1401 case 0145:
1402 case 0146:
1403 case 0147:
1404 EMIT_REX();
1405 codes++;
1406 bytes[0] = *codes++;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001407 if (is_sbyte(ins, c & 3, 16))
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001408 bytes[0] |= 2; /* s-bit */
1409 out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG, NO_SEG);
1410 offset++;
1411 break;
1412
1413 case 0150:
1414 case 0151:
1415 case 0152:
1416 case 0153:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001417 data = opx->offset;
1418 if (is_sbyte(ins, c & 3, 32)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001419 bytes[0] = data;
1420 out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG,
1421 NO_SEG);
1422 offset++;
1423 } else {
1424 out(offset, segment, &data, OUT_ADDRESS + 4,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001425 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001426 offset += 4;
1427 }
1428 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001429
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001430 case 0154:
1431 case 0155:
1432 case 0156:
1433 case 0157:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001434 EMIT_REX();
H. Peter Anvine2c80182005-01-15 22:15:51 +00001435 codes++;
1436 bytes[0] = *codes++;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001437 if (is_sbyte(ins, c & 3, 32))
H. Peter Anvine2c80182005-01-15 22:15:51 +00001438 bytes[0] |= 2; /* s-bit */
1439 out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG, NO_SEG);
1440 offset++;
1441 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001442
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001443 case 0160:
1444 case 0161:
1445 case 0162:
1446 case 0163:
1447 case 0164:
1448 case 0165:
1449 case 0166:
1450 case 0167:
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001451 break;
1452
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001453 case 0170:
H. Peter Anvinc189b442007-10-05 17:04:32 -07001454 EMIT_REX();
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001455 bytes[0] = 0;
1456 out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG, NO_SEG);
1457 offset += 1;
1458 break;
1459
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001460 case 0171:
1461 bytes[0] =
1462 (ins->drexdst << 4) |
1463 (ins->rex & REX_OC ? 0x08 : 0) |
1464 (ins->rex & (REX_R|REX_X|REX_B));
1465 ins->rex = 0;
1466 out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG, NO_SEG);
1467 offset++;
1468 break;
1469
H. Peter Anvine2c80182005-01-15 22:15:51 +00001470 case 0300:
1471 case 0301:
1472 case 0302:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001473 case 0303:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001474 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001475
H. Peter Anvine2c80182005-01-15 22:15:51 +00001476 case 0310:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001477 if (bits == 32 && !has_prefix(ins, PPS_ASIZE, P_A16)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001478 *bytes = 0x67;
1479 out(offset, segment, bytes,
1480 OUT_RAWDATA + 1, NO_SEG, NO_SEG);
1481 offset += 1;
1482 } else
1483 offset += 0;
1484 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001485
H. Peter Anvine2c80182005-01-15 22:15:51 +00001486 case 0311:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001487 if (bits != 32 && !has_prefix(ins, PPS_ASIZE, P_A32)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001488 *bytes = 0x67;
1489 out(offset, segment, bytes,
1490 OUT_RAWDATA + 1, NO_SEG, NO_SEG);
1491 offset += 1;
1492 } else
1493 offset += 0;
1494 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001495
H. Peter Anvine2c80182005-01-15 22:15:51 +00001496 case 0312:
1497 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001498
Keith Kaniosb7a89542007-04-12 02:40:54 +00001499 case 0313:
1500 ins->rex = 0;
1501 break;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07001502
H. Peter Anvine2c80182005-01-15 22:15:51 +00001503 case 0320:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001504 if (bits != 16) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001505 *bytes = 0x66;
1506 out(offset, segment, bytes,
1507 OUT_RAWDATA + 1, NO_SEG, NO_SEG);
1508 offset += 1;
1509 } else
1510 offset += 0;
1511 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001512
H. Peter Anvine2c80182005-01-15 22:15:51 +00001513 case 0321:
1514 if (bits == 16) {
1515 *bytes = 0x66;
1516 out(offset, segment, bytes,
1517 OUT_RAWDATA + 1, NO_SEG, NO_SEG);
1518 offset += 1;
1519 } else
1520 offset += 0;
1521 break;
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001522
H. Peter Anvine2c80182005-01-15 22:15:51 +00001523 case 0322:
H. Peter Anvin70653092007-10-19 14:42:29 -07001524 case 0323:
1525 break;
1526
Keith Kaniosb7a89542007-04-12 02:40:54 +00001527 case 0324:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001528 ins->rex |= REX_W;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001529 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001530
H. Peter Anvine2c80182005-01-15 22:15:51 +00001531 case 0330:
1532 *bytes = *codes++ ^ condval[ins->condition];
1533 out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG, NO_SEG);
1534 offset += 1;
1535 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001536
H. Peter Anvine2c80182005-01-15 22:15:51 +00001537 case 0331:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001538 break;
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001539
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001540 case 0332:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001541 case 0333:
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001542 *bytes = c - 0332 + 0xF2;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001543 out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG, NO_SEG);
1544 offset += 1;
1545 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001546
Keith Kanios48af1772007-08-17 07:37:52 +00001547 case 0334:
1548 if (ins->rex & REX_R) {
1549 *bytes = 0xF0;
1550 out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG, NO_SEG);
1551 offset += 1;
1552 }
1553 ins->rex &= ~(REX_L|REX_R);
1554 break;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001555
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001556 case 0335:
1557 break;
1558
H. Peter Anvine2c80182005-01-15 22:15:51 +00001559 case 0340:
1560 case 0341:
1561 case 0342:
1562 if (ins->oprs[0].segment != NO_SEG)
1563 errfunc(ERR_PANIC, "non-constant BSS size in pass two");
1564 else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001565 int32_t size = ins->oprs[0].offset << (c & 3);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001566 if (size > 0)
1567 out(offset, segment, NULL,
1568 OUT_RESERVE + size, NO_SEG, NO_SEG);
1569 offset += size;
1570 }
1571 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001572
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001573 case 0364:
1574 case 0365:
1575 break;
1576
Keith Kanios48af1772007-08-17 07:37:52 +00001577 case 0366:
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001578 case 0367:
1579 *bytes = c - 0366 + 0x66;
Keith Kanios48af1772007-08-17 07:37:52 +00001580 out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG, NO_SEG);
1581 offset += 1;
1582 break;
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001583
H. Peter Anvine2c80182005-01-15 22:15:51 +00001584 case 0370:
1585 case 0371:
1586 case 0372:
1587 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001588
H. Peter Anvine2c80182005-01-15 22:15:51 +00001589 case 0373:
1590 *bytes = bits == 16 ? 3 : 5;
1591 out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG, NO_SEG);
1592 offset += 1;
1593 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001594
H. Peter Anvine2c80182005-01-15 22:15:51 +00001595 default: /* can't do it by 'case' statements */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001596 if (c >= 0100 && c <= 0277) { /* it's an EA */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001597 ea ea_data;
1598 int rfield;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001599 int32_t rflags;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001600 uint8_t *p;
1601 int32_t s;
H. Peter Anvin70653092007-10-19 14:42:29 -07001602
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001603 if (c <= 0177) {
1604 /* pick rfield from operand b */
1605 rflags = regflag(&ins->oprs[c & 7]);
1606 rfield = regvals[ins->oprs[c & 7].basereg];
1607 } else {
1608 /* rfield is constant */
1609 rflags = 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001610 rfield = c & 7;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001611 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001612
1613 if (!process_ea
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001614 (&ins->oprs[(c >> 3) & 7], &ea_data, bits,
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001615 ins->addr_size, rfield, rflags, ins->forw_ref)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001616 errfunc(ERR_NONFATAL, "invalid effective address");
1617 }
H. Peter Anvin70653092007-10-19 14:42:29 -07001618
Charles Crayne7e975552007-11-03 22:06:13 -07001619
H. Peter Anvine2c80182005-01-15 22:15:51 +00001620 p = bytes;
1621 *p++ = ea_data.modrm;
1622 if (ea_data.sib_present)
1623 *p++ = ea_data.sib;
1624
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001625 /* DREX suffixes come between the SIB and the displacement */
1626 if (ins->rex & REX_D) {
1627 *p++ =
1628 (ins->drexdst << 4) |
1629 (ins->rex & REX_OC ? 0x08 : 0) |
1630 (ins->rex & (REX_R|REX_X|REX_B));
1631 ins->rex = 0;
1632 }
1633
H. Peter Anvine2c80182005-01-15 22:15:51 +00001634 s = p - bytes;
1635 out(offset, segment, bytes, OUT_RAWDATA + s,
1636 NO_SEG, NO_SEG);
1637
1638 switch (ea_data.bytes) {
1639 case 0:
1640 break;
1641 case 1:
1642 if (ins->oprs[(c >> 3) & 7].segment != NO_SEG) {
1643 data = ins->oprs[(c >> 3) & 7].offset;
1644 out(offset, segment, &data, OUT_ADDRESS + 1,
1645 ins->oprs[(c >> 3) & 7].segment,
1646 ins->oprs[(c >> 3) & 7].wrt);
1647 } else {
1648 *bytes = ins->oprs[(c >> 3) & 7].offset;
1649 out(offset, segment, bytes, OUT_RAWDATA + 1,
1650 NO_SEG, NO_SEG);
1651 }
1652 s++;
1653 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001654 case 8:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001655 case 2:
1656 case 4:
1657 data = ins->oprs[(c >> 3) & 7].offset;
Charles Crayne7e975552007-11-03 22:06:13 -07001658 warn_overflow(ea_data.bytes, data);
H. Peter Anvind0b0d282007-09-28 17:17:20 -07001659 out(offset, segment, &data,
1660 (ea_data.rip ? OUT_REL4ADR : OUT_ADDRESS)
1661 + ea_data.bytes,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001662 ins->oprs[(c >> 3) & 7].segment,
1663 ins->oprs[(c >> 3) & 7].wrt);
1664 s += ea_data.bytes;
1665 break;
1666 }
1667 offset += s;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001668 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001669 errfunc(ERR_PANIC, "internal instruction table corrupt"
1670 ": instruction code 0x%02X given", c);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001671 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001672 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001673 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001674}
1675
H. Peter Anvin0ec60e62007-07-07 01:59:52 +00001676static int32_t regflag(const operand * o)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001677{
1678 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1679 errfunc(ERR_PANIC, "invalid operand passed to regflag()");
1680 }
1681 return reg_flags[o->basereg];
1682}
1683
H. Peter Anvin5b0e3ec2007-07-07 02:01:08 +00001684static int32_t regval(const operand * o)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001685{
H. Peter Anvine2c80182005-01-15 22:15:51 +00001686 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1687 errfunc(ERR_PANIC, "invalid operand passed to regval()");
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001688 }
H. Peter Anvin232badb2002-06-06 02:41:20 +00001689 return regvals[o->basereg];
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001690}
1691
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001692static int op_rexflags(const operand * o, int mask)
1693{
1694 int32_t flags;
1695 int val;
1696
1697 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1698 errfunc(ERR_PANIC, "invalid operand passed to op_rexflags()");
1699 }
1700
1701 flags = reg_flags[o->basereg];
1702 val = regvals[o->basereg];
1703
1704 return rexflags(val, flags, mask);
1705}
1706
1707static int rexflags(int val, int32_t flags, int mask)
1708{
1709 int rex = 0;
1710
1711 if (val >= 8)
1712 rex |= REX_B|REX_X|REX_R;
1713 if (flags & BITS64)
1714 rex |= REX_W;
1715 if (!(REG_HIGH & ~flags)) /* AH, CH, DH, BH */
1716 rex |= REX_H;
1717 else if (!(REG8 & ~flags) && val >= 4) /* SPL, BPL, SIL, DIL */
1718 rex |= REX_P;
1719
1720 return rex & mask;
1721}
1722
H. Peter Anvin3360d792007-09-11 04:16:57 +00001723static int matches(const struct itemplate *itemp, insn * instruction, int bits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001724{
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001725 int i, size[MAX_OPERANDS], asize, oprs, ret;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001726
1727 ret = 100;
1728
1729 /*
1730 * Check the opcode
1731 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001732 if (itemp->opcode != instruction->opcode)
1733 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001734
1735 /*
1736 * Count the operands
1737 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001738 if (itemp->operands != instruction->operands)
1739 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001740
1741 /*
1742 * Check that no spurious colons or TOs are present
1743 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001744 for (i = 0; i < itemp->operands; i++)
1745 if (instruction->oprs[i].type & ~itemp->opd[i] & (COLON | TO))
1746 return 0;
H. Peter Anvin70653092007-10-19 14:42:29 -07001747
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001748 /*
1749 * Check that the operand flags all match up
1750 */
H. Peter Anvin16b0a332007-09-12 20:27:41 -07001751 for (i = 0; i < itemp->operands; i++) {
H. Peter Anvincf5180a2007-09-17 17:25:27 -07001752 if (itemp->opd[i] & SAME_AS) {
1753 int j = itemp->opd[i] & ~SAME_AS;
1754 if (instruction->oprs[i].type != instruction->oprs[j].type ||
1755 instruction->oprs[i].basereg != instruction->oprs[j].basereg)
1756 return 0;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001757 } else if (itemp->opd[i] & ~instruction->oprs[i].type ||
H. Peter Anvine2c80182005-01-15 22:15:51 +00001758 ((itemp->opd[i] & SIZE_MASK) &&
1759 ((itemp->opd[i] ^ instruction->oprs[i].type) & SIZE_MASK))) {
H. Peter Anvin5a640e12007-05-29 23:57:12 +00001760 if ((itemp->opd[i] & ~instruction->oprs[i].type & ~SIZE_MASK) ||
H. Peter Anvine2c80182005-01-15 22:15:51 +00001761 (instruction->oprs[i].type & SIZE_MASK))
1762 return 0;
1763 else
H. Peter Anvine2c80182005-01-15 22:15:51 +00001764 return 1;
1765 }
H. Peter Anvin16b0a332007-09-12 20:27:41 -07001766 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001767
1768 /*
1769 * Check operand sizes
1770 */
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001771 if (itemp->flags & IF_ARMASK) {
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001772 memset(size, 0, sizeof size);
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001773
H. Peter Anvine2c80182005-01-15 22:15:51 +00001774 switch (itemp->flags & IF_ARMASK) {
1775 case IF_AR0:
1776 i = 0;
1777 break;
1778 case IF_AR1:
1779 i = 1;
1780 break;
1781 case IF_AR2:
1782 i = 2;
1783 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001784 case IF_AR3:
1785 i = 3;
1786 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001787 default:
1788 break; /* Shouldn't happen */
1789 }
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001790 switch (itemp->flags & IF_SMASK) {
1791 case IF_SB:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001792 size[i] = BITS8;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001793 break;
1794 case IF_SW:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001795 size[i] = BITS16;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001796 break;
1797 case IF_SD:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001798 size[i] = BITS32;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001799 break;
1800 case IF_SQ:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001801 size[i] = BITS64;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001802 break;
H. Peter Anvin41c9f6f2007-09-18 13:01:32 -07001803 case IF_SO:
1804 size[i] = BITS128;
1805 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001806 default:
1807 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001808 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001809 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001810 asize = 0;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001811 switch (itemp->flags & IF_SMASK) {
1812 case IF_SB:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001813 asize = BITS8;
1814 oprs = itemp->operands;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001815 break;
1816 case IF_SW:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001817 asize = BITS16;
1818 oprs = itemp->operands;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001819 break;
1820 case IF_SD:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001821 asize = BITS32;
1822 oprs = itemp->operands;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001823 break;
1824 case IF_SQ:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001825 asize = BITS64;
1826 oprs = itemp->operands;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001827 break;
H. Peter Anvin41c9f6f2007-09-18 13:01:32 -07001828 case IF_SO:
1829 asize = BITS128;
1830 oprs = itemp->operands;
1831 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001832 default:
1833 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001834 }
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001835 for (i = 0; i < MAX_OPERANDS; i++)
1836 size[i] = asize;
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001837 }
H. Peter Anvin70653092007-10-19 14:42:29 -07001838
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001839 if (itemp->flags & (IF_SM | IF_SM2)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001840 oprs = (itemp->flags & IF_SM2 ? 2 : itemp->operands);
1841 asize = 0;
1842 for (i = 0; i < oprs; i++) {
1843 if ((asize = itemp->opd[i] & SIZE_MASK) != 0) {
1844 int j;
1845 for (j = 0; j < oprs; j++)
1846 size[j] = asize;
1847 break;
1848 }
1849 }
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001850 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001851 oprs = itemp->operands;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001852 }
1853
Keith Kaniosb7a89542007-04-12 02:40:54 +00001854 for (i = 0; i < itemp->operands; i++) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001855 if (!(itemp->opd[i] & SIZE_MASK) &&
1856 (instruction->oprs[i].type & SIZE_MASK & ~size[i]))
H. Peter Anvine2c80182005-01-15 22:15:51 +00001857 return 2;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001858 }
1859
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001860 /*
1861 * Check template is okay at the set cpu level
1862 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00001863 if (((itemp->flags & IF_PLEVEL) > cpu))
H. Peter Anvine2c80182005-01-15 22:15:51 +00001864 return 3;
H. Peter Anvin70653092007-10-19 14:42:29 -07001865
Keith Kaniosb7a89542007-04-12 02:40:54 +00001866 /*
1867 * Check if instruction is available in long mode
1868 */
1869 if ((itemp->flags & IF_NOLONG) && (bits == 64))
1870 return 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001871
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001872 /*
1873 * Check if special handling needed for Jumps
1874 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00001875 if ((uint8_t)(itemp->code[0]) >= 0370)
H. Peter Anvine2c80182005-01-15 22:15:51 +00001876 return 99;
1877
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001878 return ret;
1879}
1880
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001881static ea *process_ea(operand * input, ea * output, int bits,
1882 int addrbits, int rfield, int32_t rflags, int forw_ref)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001883{
H. Peter Anvin6867acc2007-10-10 14:58:45 -07001884 output->rip = false;
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00001885
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001886 /* REX flags for the rfield operand */
1887 output->rex |= rexflags(rfield, rflags, REX_R|REX_P|REX_W|REX_H);
1888
Keith Kaniosb7a89542007-04-12 02:40:54 +00001889 if (!(REGISTER & ~input->type)) { /* register direct */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001890 int i;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001891 int32_t f;
1892
1893 if (input->basereg < EXPR_REG_START /* Verify as Register */
Keith Kaniosb7a89542007-04-12 02:40:54 +00001894 || input->basereg >= REG_ENUM_LIMIT)
H. Peter Anvine2c80182005-01-15 22:15:51 +00001895 return NULL;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001896 f = regflag(input);
Keith Kaniosb7a89542007-04-12 02:40:54 +00001897 i = regvals[input->basereg];
Keith Kaniosb7a89542007-04-12 02:40:54 +00001898
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001899 if (REG_EA & ~f)
1900 return NULL; /* Invalid EA register */
H. Peter Anvin70653092007-10-19 14:42:29 -07001901
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001902 output->rex |= op_rexflags(input, REX_B|REX_P|REX_W|REX_H);
1903
H. Peter Anvin6867acc2007-10-10 14:58:45 -07001904 output->sib_present = false; /* no SIB necessary */
Keith Kaniosb7a89542007-04-12 02:40:54 +00001905 output->bytes = 0; /* no offset necessary either */
1906 output->modrm = 0xC0 | ((rfield & 7) << 3) | (i & 7);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001907 } else { /* it's a memory reference */
1908 if (input->basereg == -1
1909 && (input->indexreg == -1 || input->scale == 0)) {
1910 /* it's a pure offset */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001911 if (bits == 64 && (~input->type & IP_REL)) {
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00001912 int scale, index, base;
H. Peter Anvin6867acc2007-10-10 14:58:45 -07001913 output->sib_present = true;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00001914 scale = 0;
1915 index = 4;
1916 base = 5;
1917 output->sib = (scale << 6) | (index << 3) | base;
1918 output->bytes = 4;
1919 output->modrm = 4 | ((rfield & 7) << 3);
H. Peter Anvin6867acc2007-10-10 14:58:45 -07001920 output->rip = false;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00001921 } else {
H. Peter Anvin6867acc2007-10-10 14:58:45 -07001922 output->sib_present = false;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00001923 output->bytes = (addrbits != 16 ? 4 : 2);
1924 output->modrm = (addrbits != 16 ? 5 : 6) | ((rfield & 7) << 3);
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001925 output->rip = bits == 64;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00001926 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001927 } else { /* it's an indirection */
1928 int i = input->indexreg, b = input->basereg, s = input->scale;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001929 int32_t o = input->offset, seg = input->segment;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001930 int hb = input->hintbase, ht = input->hinttype;
1931 int t;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001932 int it, bt;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001933 int32_t ix, bx; /* register flags */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001934
H. Peter Anvine2c80182005-01-15 22:15:51 +00001935 if (s == 0)
1936 i = -1; /* make this easy, at least */
H. Peter Anvin70653092007-10-19 14:42:29 -07001937
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001938 if (i >= EXPR_REG_START && i < REG_ENUM_LIMIT) {
Keith Kaniosb7a89542007-04-12 02:40:54 +00001939 it = regvals[i];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001940 ix = reg_flags[i];
1941 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00001942 it = -1;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001943 ix = 0;
1944 }
H. Peter Anvin70653092007-10-19 14:42:29 -07001945
H. Peter Anvinb0c54622007-10-28 23:21:46 -07001946 if (b >= EXPR_REG_START && b < REG_ENUM_LIMIT) {
Keith Kaniosb7a89542007-04-12 02:40:54 +00001947 bt = regvals[b];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001948 bx = reg_flags[b];
1949 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00001950 bt = -1;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001951 bx = 0;
1952 }
H. Peter Anvin70653092007-10-19 14:42:29 -07001953
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001954 /* check for a 32/64-bit memory reference... */
1955 if ((ix|bx) & (BITS32|BITS64)) {
Keith Kaniosb7a89542007-04-12 02:40:54 +00001956 /* it must be a 32/64-bit memory reference. Firstly we have
1957 * to check that all registers involved are type E/Rxx. */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001958 int32_t sok = BITS32|BITS64;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001959
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001960 if (it != -1) {
1961 if (!(REG64 & ~ix) || !(REG32 & ~ix))
1962 sok &= ix;
1963 else
1964 return NULL;
1965 }
1966
1967 if (bt != -1) {
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00001968 if (REG_GPR & ~bx)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001969 return NULL; /* Invalid register */
H. Peter Anvina57e8d42007-05-30 03:44:02 +00001970 if (~sok & bx & SIZE_MASK)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001971 return NULL; /* Invalid size */
H. Peter Anvinb0c54622007-10-28 23:21:46 -07001972 sok &= bx;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001973 }
H. Peter Anvin70653092007-10-19 14:42:29 -07001974
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001975 /* While we're here, ensure the user didn't specify
1976 WORD or QWORD. */
1977 if (input->disp_size == 16 || input->disp_size == 64)
1978 return NULL;
1979
1980 if (addrbits == 16 ||
1981 (addrbits == 32 && !(sok & BITS32)) ||
1982 (addrbits == 64 && !(sok & BITS64)))
1983 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001984
Keith Kaniosb7a89542007-04-12 02:40:54 +00001985 /* now reorganize base/index */
1986 if (s == 1 && bt != it && bt != -1 && it != -1 &&
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001987 ((hb == b && ht == EAH_NOTBASE)
1988 || (hb == i && ht == EAH_MAKEBASE))) {
1989 /* swap if hints say so */
1990 t = bt, bt = it, it = t;
1991 t = bx, bx = ix, ix = t;
1992 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00001993 if (bt == it) /* convert EAX+2*EAX to 3*EAX */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001994 bt = -1, bx = 0, s++;
1995 if (bt == -1 && s == 1 && !(hb == it && ht == EAH_NOTBASE)) {
1996 /* make single reg base, unless hint */
1997 bt = it, bx = ix, it = -1, ix = 0;
1998 }
H. Peter Anvinf5843c62007-09-10 18:59:26 +00001999 if (((s == 2 && it != REG_NUM_ESP
H. Peter Anvine2c80182005-01-15 22:15:51 +00002000 && !(input->eaflags & EAF_TIMESTWO)) || s == 3
Keith Kaniosb7a89542007-04-12 02:40:54 +00002001 || s == 5 || s == 9) && bt == -1)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002002 bt = it, bx = ix, s--; /* convert 3*EAX to EAX+2*EAX */
Keith Kanios48af1772007-08-17 07:37:52 +00002003 if (it == -1 && (bt & 7) != REG_NUM_ESP
H. Peter Anvine2c80182005-01-15 22:15:51 +00002004 && (input->eaflags & EAF_TIMESTWO))
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002005 it = bt, ix = bx, bt = -1, bx = 0, s = 1;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002006 /* convert [NOSPLIT EAX] to sib format with 0x0 displacement */
Keith Kanios48af1772007-08-17 07:37:52 +00002007 if (s == 1 && it == REG_NUM_ESP) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002008 /* swap ESP into base if scale is 1 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002009 t = it, it = bt, bt = t;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002010 t = ix, ix = bx, bx = t;
2011 }
Keith Kanios48af1772007-08-17 07:37:52 +00002012 if (it == REG_NUM_ESP
Keith Kaniosb7a89542007-04-12 02:40:54 +00002013 || (s != 1 && s != 2 && s != 4 && s != 8 && it != -1))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002014 return NULL; /* wrong, for various reasons */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002015
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002016 output->rex |= rexflags(it, ix, REX_X);
2017 output->rex |= rexflags(bt, bx, REX_B);
Keith Kaniosb7a89542007-04-12 02:40:54 +00002018
Keith Kanios48af1772007-08-17 07:37:52 +00002019 if (it == -1 && (bt & 7) != REG_NUM_ESP) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002020 /* no SIB needed */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002021 int mod, rm;
H. Peter Anvin70653092007-10-19 14:42:29 -07002022
Keith Kaniosb7a89542007-04-12 02:40:54 +00002023 if (bt == -1) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002024 rm = 5;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002025 mod = 0;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002026 } else {
2027 rm = (bt & 7);
Keith Kanios48af1772007-08-17 07:37:52 +00002028 if (rm != REG_NUM_EBP && o == 0 &&
Keith Kaniosb7a89542007-04-12 02:40:54 +00002029 seg == NO_SEG && !forw_ref &&
2030 !(input->eaflags &
2031 (EAF_BYTEOFFS | EAF_WORDOFFS)))
2032 mod = 0;
2033 else if (input->eaflags & EAF_BYTEOFFS ||
2034 (o >= -128 && o <= 127 && seg == NO_SEG
2035 && !forw_ref
2036 && !(input->eaflags & EAF_WORDOFFS)))
2037 mod = 1;
2038 else
2039 mod = 2;
2040 }
H. Peter Anvinea838272002-04-30 20:51:53 +00002041
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002042 output->sib_present = false;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002043 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2044 output->modrm = (mod << 6) | ((rfield & 7) << 3) | rm;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002045 } else {
2046 /* we need a SIB */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002047 int mod, scale, index, base;
H. Peter Anvin70653092007-10-19 14:42:29 -07002048
Keith Kaniosb7a89542007-04-12 02:40:54 +00002049 if (it == -1)
2050 index = 4, s = 1;
2051 else
2052 index = (it & 7);
H. Peter Anvin70653092007-10-19 14:42:29 -07002053
H. Peter Anvine2c80182005-01-15 22:15:51 +00002054 switch (s) {
2055 case 1:
2056 scale = 0;
2057 break;
2058 case 2:
2059 scale = 1;
2060 break;
2061 case 4:
2062 scale = 2;
2063 break;
2064 case 8:
2065 scale = 3;
2066 break;
2067 default: /* then what the smeg is it? */
2068 return NULL; /* panic */
2069 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002070
Keith Kaniosb7a89542007-04-12 02:40:54 +00002071 if (bt == -1) {
2072 base = 5;
2073 mod = 0;
2074 } else {
2075 base = (bt & 7);
Keith Kanios48af1772007-08-17 07:37:52 +00002076 if (base != REG_NUM_EBP && o == 0 &&
H. Peter Anvine2c80182005-01-15 22:15:51 +00002077 seg == NO_SEG && !forw_ref &&
2078 !(input->eaflags &
Keith Kaniosb7a89542007-04-12 02:40:54 +00002079 (EAF_BYTEOFFS | EAF_WORDOFFS)))
2080 mod = 0;
2081 else if (input->eaflags & EAF_BYTEOFFS ||
2082 (o >= -128 && o <= 127 && seg == NO_SEG
2083 && !forw_ref
2084 && !(input->eaflags & EAF_WORDOFFS)))
2085 mod = 1;
2086 else
2087 mod = 2;
2088 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002089
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002090 output->sib_present = true;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002091 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2092 output->modrm = (mod << 6) | ((rfield & 7) << 3) | 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002093 output->sib = (scale << 6) | (index << 3) | base;
2094 }
2095 } else { /* it's 16-bit */
2096 int mod, rm;
H. Peter Anvin70653092007-10-19 14:42:29 -07002097
Keith Kaniosb7a89542007-04-12 02:40:54 +00002098 /* check for 64-bit long mode */
2099 if (addrbits == 64)
2100 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002101
H. Peter Anvine2c80182005-01-15 22:15:51 +00002102 /* check all registers are BX, BP, SI or DI */
2103 if ((b != -1 && b != R_BP && b != R_BX && b != R_SI
2104 && b != R_DI) || (i != -1 && i != R_BP && i != R_BX
2105 && i != R_SI && i != R_DI))
2106 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002107
Keith Kaniosb7a89542007-04-12 02:40:54 +00002108 /* ensure the user didn't specify DWORD/QWORD */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002109 if (input->disp_size == 32 || input->disp_size == 64)
H. Peter Anvine2c80182005-01-15 22:15:51 +00002110 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002111
H. Peter Anvine2c80182005-01-15 22:15:51 +00002112 if (s != 1 && i != -1)
2113 return NULL; /* no can do, in 16-bit EA */
2114 if (b == -1 && i != -1) {
2115 int tmp = b;
2116 b = i;
2117 i = tmp;
2118 } /* swap */
2119 if ((b == R_SI || b == R_DI) && i != -1) {
2120 int tmp = b;
2121 b = i;
2122 i = tmp;
2123 }
2124 /* have BX/BP as base, SI/DI index */
2125 if (b == i)
2126 return NULL; /* shouldn't ever happen, in theory */
2127 if (i != -1 && b != -1 &&
2128 (i == R_BP || i == R_BX || b == R_SI || b == R_DI))
2129 return NULL; /* invalid combinations */
2130 if (b == -1) /* pure offset: handled above */
2131 return NULL; /* so if it gets to here, panic! */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002132
H. Peter Anvine2c80182005-01-15 22:15:51 +00002133 rm = -1;
2134 if (i != -1)
2135 switch (i * 256 + b) {
2136 case R_SI * 256 + R_BX:
2137 rm = 0;
2138 break;
2139 case R_DI * 256 + R_BX:
2140 rm = 1;
2141 break;
2142 case R_SI * 256 + R_BP:
2143 rm = 2;
2144 break;
2145 case R_DI * 256 + R_BP:
2146 rm = 3;
2147 break;
2148 } else
2149 switch (b) {
2150 case R_SI:
2151 rm = 4;
2152 break;
2153 case R_DI:
2154 rm = 5;
2155 break;
2156 case R_BP:
2157 rm = 6;
2158 break;
2159 case R_BX:
2160 rm = 7;
2161 break;
2162 }
2163 if (rm == -1) /* can't happen, in theory */
2164 return NULL; /* so panic if it does */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002165
H. Peter Anvine2c80182005-01-15 22:15:51 +00002166 if (o == 0 && seg == NO_SEG && !forw_ref && rm != 6 &&
2167 !(input->eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS)))
2168 mod = 0;
2169 else if (input->eaflags & EAF_BYTEOFFS ||
2170 (o >= -128 && o <= 127 && seg == NO_SEG
2171 && !forw_ref
2172 && !(input->eaflags & EAF_WORDOFFS)))
2173 mod = 1;
2174 else
2175 mod = 2;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002176
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002177 output->sib_present = false; /* no SIB - it's 16-bit */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002178 output->bytes = mod; /* bytes of offset needed */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002179 output->modrm = (mod << 6) | ((rfield & 7) << 3) | rm;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002180 }
2181 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002182 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002183
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002184 output->size = 1 + output->sib_present + output->bytes;
2185 return output;
2186}
2187
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002188static void add_asp(insn *ins, int addrbits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002189{
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002190 int j, valid;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002191 int defdisp;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002192
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002193 valid = (addrbits == 64) ? 64|32 : 32|16;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002194
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002195 switch (ins->prefixes[PPS_ASIZE]) {
2196 case P_A16:
2197 valid &= 16;
2198 break;
2199 case P_A32:
2200 valid &= 32;
2201 break;
2202 case P_A64:
2203 valid &= 64;
2204 break;
2205 case P_ASP:
2206 valid &= (addrbits == 32) ? 16 : 32;
2207 break;
2208 default:
2209 break;
2210 }
2211
2212 for (j = 0; j < ins->operands; j++) {
2213 if (!(MEMORY & ~ins->oprs[j].type)) {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002214 int32_t i, b;
H. Peter Anvin70653092007-10-19 14:42:29 -07002215
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002216 /* Verify as Register */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002217 if (ins->oprs[j].indexreg < EXPR_REG_START
2218 || ins->oprs[j].indexreg >= REG_ENUM_LIMIT)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002219 i = 0;
2220 else
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002221 i = reg_flags[ins->oprs[j].indexreg];
H. Peter Anvin70653092007-10-19 14:42:29 -07002222
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002223 /* Verify as Register */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002224 if (ins->oprs[j].basereg < EXPR_REG_START
2225 || ins->oprs[j].basereg >= REG_ENUM_LIMIT)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002226 b = 0;
2227 else
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002228 b = reg_flags[ins->oprs[j].basereg];
H. Peter Anvin70653092007-10-19 14:42:29 -07002229
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002230 if (ins->oprs[j].scale == 0)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002231 i = 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002232
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002233 if (!i && !b) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002234 int ds = ins->oprs[j].disp_size;
2235 if ((addrbits != 64 && ds > 8) ||
2236 (addrbits == 64 && ds == 16))
2237 valid &= ds;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002238 } else {
2239 if (!(REG16 & ~b))
2240 valid &= 16;
2241 if (!(REG32 & ~b))
2242 valid &= 32;
2243 if (!(REG64 & ~b))
2244 valid &= 64;
H. Peter Anvin70653092007-10-19 14:42:29 -07002245
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002246 if (!(REG16 & ~i))
2247 valid &= 16;
2248 if (!(REG32 & ~i))
2249 valid &= 32;
2250 if (!(REG64 & ~i))
2251 valid &= 64;
2252 }
2253 }
2254 }
2255
2256 if (valid & addrbits) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002257 ins->addr_size = addrbits;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002258 } else if (valid & ((addrbits == 32) ? 16 : 32)) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002259 /* Add an address size prefix */
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002260 enum prefixes pref = (addrbits == 32) ? P_A16 : P_A32;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002261 ins->prefixes[PPS_ASIZE] = pref;
2262 ins->addr_size = (addrbits == 32) ? 16 : 32;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002263 } else {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002264 /* Impossible... */
2265 errfunc(ERR_NONFATAL, "impossible combination of address sizes");
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002266 ins->addr_size = addrbits; /* Error recovery */
2267 }
2268
2269 defdisp = ins->addr_size == 16 ? 16 : 32;
2270
2271 for (j = 0; j < ins->operands; j++) {
2272 if (!(MEM_OFFS & ~ins->oprs[j].type) &&
2273 (ins->oprs[j].disp_size ? ins->oprs[j].disp_size : defdisp)
2274 != ins->addr_size) {
2275 /* mem_offs sizes must match the address size; if not,
2276 strip the MEM_OFFS bit and match only EA instructions */
2277 ins->oprs[j].type &= ~(MEM_OFFS & ~MEMORY);
2278 }
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002279 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002280}