blob: b6b447e2b63b8af031425c0db48b97c4c682772c [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
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800110static int64_t calcsize(int32_t, int64_t, int, insn *, const char *);
111static void gencode(int32_t, int64_t, int, insn *, const char *, int64_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 */
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800166static void out(int64_t offset, int32_t segto, const void *data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800167 enum out_type type, uint64_t size,
168 int32_t segment, int32_t wrt)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000169{
Keith Kaniosb7a89542007-04-12 02:40:54 +0000170 static int32_t lineno = 0; /* static!!! */
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000171 static char *lnfname = NULL;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800172 uint8_t p[8];
H. Peter Anvineba20a72002-04-30 20:53:55 +0000173
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800174 if (type == OUT_ADDRESS && segment == NO_SEG && wrt == NO_SEG) {
175 /*
176 * This is a non-relocated address, and we're going to
177 * convert it into RAWDATA format.
178 */
179 uint8_t *q = p;
180
181 switch (size) {
182 case 2:
183 WRITESHORT(q, *(int32_t *)data);
184 break;
185 case 4:
186 WRITELONG(q, *(int32_t *)data);
187 break;
188 case 8:
189 WRITEDLONG(q, *(int64_t *)data);
190 break;
191 }
192 data = p;
193 type = OUT_RAWDATA;
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000194 }
195
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800196 list->output(offset, data, type, size);
197
Frank Kotlerabebb082003-09-06 04:45:37 +0000198 /*
199 * this call to src_get determines when we call the
200 * debug-format-specific "linenum" function
201 * it updates lineno and lnfname to the current values
202 * returning 0 if "same as last time", -2 if lnfname
203 * changed, and the amount by which lineno changed,
204 * if it did. thus, these variables must be static
205 */
206
H. Peter Anvine2c80182005-01-15 22:15:51 +0000207 if (src_get(&lineno, &lnfname)) {
208 outfmt->current_dfmt->linenum(lnfname, lineno, segto);
H. Peter Anvince616072002-04-30 21:02:23 +0000209 }
H. Peter Anvineba20a72002-04-30 20:53:55 +0000210
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800211 outfmt->output(segto, data, type, size, segment, wrt);
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000212}
213
Charles Crayne5fbbc8c2007-11-07 19:03:46 -0800214static int jmp_match(int32_t segment, int64_t offset, int bits,
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000215 insn * ins, const char *code)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000216{
Charles Crayne5fbbc8c2007-11-07 19:03:46 -0800217 int64_t isize;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000218 uint8_t c = code[0];
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000219
H. Peter Anvine2c80182005-01-15 22:15:51 +0000220 if (c != 0370 && c != 0371)
221 return 0;
H. Peter Anvin788e6c12002-04-30 21:02:01 +0000222 if (ins->oprs[0].opflags & OPFLAG_FORWARD) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000223 if ((optimizing < 0 || (ins->oprs[0].type & STRICT))
224 && c == 0370)
225 return 1;
226 else
227 return (pass0 == 0); /* match a forward reference */
H. Peter Anvin788e6c12002-04-30 21:02:01 +0000228 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000229 isize = calcsize(segment, offset, bits, ins, code);
230 if (ins->oprs[0].segment != segment)
231 return 0;
232 isize = ins->oprs[0].offset - offset - isize; /* isize is now the delta */
233 if (isize >= -128L && isize <= 127L)
234 return 1; /* it is byte size */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000235
236 return 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000237}
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000238
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800239int64_t assemble(int32_t segment, int64_t offset, int bits, uint32_t cp,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000240 insn * instruction, struct ofmt *output, efunc error,
241 ListGen * listgen)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000242{
H. Peter Anvin3360d792007-09-11 04:16:57 +0000243 const struct itemplate *temp;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000244 int j;
245 int size_prob;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800246 int64_t insn_end;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000247 int32_t itimes;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800248 int64_t start = offset;
249 int64_t wsize = 0; /* size for DB etc. */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000250
H. Peter Anvine2c80182005-01-15 22:15:51 +0000251 errfunc = error; /* to pass to other functions */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000252 cpu = cp;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000253 outfmt = output; /* likewise */
254 list = listgen; /* and again */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000255
H. Peter Anvine2c80182005-01-15 22:15:51 +0000256 switch (instruction->opcode) {
257 case -1:
258 return 0;
259 case I_DB:
260 wsize = 1;
261 break;
262 case I_DW:
263 wsize = 2;
264 break;
265 case I_DD:
266 wsize = 4;
267 break;
268 case I_DQ:
269 wsize = 8;
270 break;
271 case I_DT:
272 wsize = 10;
273 break;
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700274 case I_DO:
275 wsize = 16;
276 break;
H. Peter Anvin16b0a332007-09-12 20:27:41 -0700277 default:
278 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000279 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000280
H. Peter Anvineba20a72002-04-30 20:53:55 +0000281 if (wsize) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000282 extop *e;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000283 int32_t t = instruction->times;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000284 if (t < 0)
285 errfunc(ERR_PANIC,
286 "instruction->times < 0 (%ld) in assemble()", t);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000287
H. Peter Anvine2c80182005-01-15 22:15:51 +0000288 while (t--) { /* repeat TIMES times */
289 for (e = instruction->eops; e; e = e->next) {
290 if (e->type == EOT_DB_NUMBER) {
291 if (wsize == 1) {
292 if (e->segment != NO_SEG)
293 errfunc(ERR_NONFATAL,
294 "one-byte relocation attempted");
295 else {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000296 uint8_t out_byte = e->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000297 out(offset, segment, &out_byte,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800298 OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000299 }
Keith Kanios61ff53c2007-04-14 18:54:52 +0000300 } else if (wsize > 8) {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700301 errfunc(ERR_NONFATAL, "integer supplied to a DT or DO"
Keith Kanios61ff53c2007-04-14 18:54:52 +0000302 " instruction");
H. Peter Anvine2c80182005-01-15 22:15:51 +0000303 } else
304 out(offset, segment, &e->offset,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800305 OUT_ADDRESS, wsize, e->segment, e->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000306 offset += wsize;
307 } else if (e->type == EOT_DB_STRING) {
308 int align;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000309
H. Peter Anvine2c80182005-01-15 22:15:51 +0000310 out(offset, segment, e->stringval,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800311 OUT_RAWDATA, e->stringlen, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000312 align = e->stringlen % wsize;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000313
H. Peter Anvine2c80182005-01-15 22:15:51 +0000314 if (align) {
315 align = wsize - align;
316 out(offset, segment, "\0\0\0\0\0\0\0\0",
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800317 OUT_RAWDATA, align, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000318 }
319 offset += e->stringlen + align;
320 }
321 }
322 if (t > 0 && t == instruction->times - 1) {
323 /*
324 * Dummy call to list->output to give the offset to the
325 * listing module.
326 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800327 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000328 list->uplevel(LIST_TIMES);
329 }
330 }
331 if (instruction->times > 1)
332 list->downlevel(LIST_TIMES);
333 return offset - start;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000334 }
335
H. Peter Anvine2c80182005-01-15 22:15:51 +0000336 if (instruction->opcode == I_INCBIN) {
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000337 static char fname[FILENAME_MAX];
H. Peter Anvine2c80182005-01-15 22:15:51 +0000338 FILE *fp;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000339 int32_t len;
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000340 char *prefix = "", *combine;
341 char **pPrevPath = NULL;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000342
H. Peter Anvine2c80182005-01-15 22:15:51 +0000343 len = FILENAME_MAX - 1;
344 if (len > instruction->eops->stringlen)
345 len = instruction->eops->stringlen;
346 strncpy(fname, instruction->eops->stringval, len);
347 fname[len] = '\0';
H. Peter Anvineba20a72002-04-30 20:53:55 +0000348
Keith Kaniosb7a89542007-04-12 02:40:54 +0000349 while (1) { /* added by alexfru: 'incbin' uses include paths */
H. Peter Anvine2c80182005-01-15 22:15:51 +0000350 combine = nasm_malloc(strlen(prefix) + len + 1);
351 strcpy(combine, prefix);
352 strcat(combine, fname);
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000353
H. Peter Anvine2c80182005-01-15 22:15:51 +0000354 if ((fp = fopen(combine, "rb")) != NULL) {
355 nasm_free(combine);
356 break;
357 }
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000358
H. Peter Anvine2c80182005-01-15 22:15:51 +0000359 nasm_free(combine);
360 pPrevPath = pp_get_include_path_ptr(pPrevPath);
361 if (pPrevPath == NULL)
362 break;
363 prefix = *pPrevPath;
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000364 }
365
366 if (fp == NULL)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000367 error(ERR_NONFATAL, "`incbin': unable to open file `%s'",
368 fname);
369 else if (fseek(fp, 0L, SEEK_END) < 0)
370 error(ERR_NONFATAL, "`incbin': unable to seek on file `%s'",
371 fname);
372 else {
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000373 static char buf[2048];
Keith Kaniosb7a89542007-04-12 02:40:54 +0000374 int32_t t = instruction->times;
375 int32_t base = 0;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000376
H. Peter Anvine2c80182005-01-15 22:15:51 +0000377 len = ftell(fp);
378 if (instruction->eops->next) {
379 base = instruction->eops->next->offset;
380 len -= base;
381 if (instruction->eops->next->next &&
382 len > instruction->eops->next->next->offset)
383 len = instruction->eops->next->next->offset;
384 }
385 /*
386 * Dummy call to list->output to give the offset to the
387 * listing module.
388 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800389 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000390 list->uplevel(LIST_INCBIN);
391 while (t--) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000392 int32_t l;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000393
H. Peter Anvine2c80182005-01-15 22:15:51 +0000394 fseek(fp, base, SEEK_SET);
395 l = len;
396 while (l > 0) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000397 int32_t m =
Charles Crayne192d5b52007-10-18 19:02:42 -0700398 fread(buf, 1, (l > (int32_t) sizeof(buf) ? (int32_t) sizeof(buf) : l),
H. Peter Anvine2c80182005-01-15 22:15:51 +0000399 fp);
400 if (!m) {
401 /*
402 * This shouldn't happen unless the file
403 * actually changes while we are reading
404 * it.
405 */
406 error(ERR_NONFATAL,
407 "`incbin': unexpected EOF while"
408 " reading file `%s'", fname);
409 t = 0; /* Try to exit cleanly */
410 break;
411 }
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800412 out(offset, segment, buf, OUT_RAWDATA, m,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000413 NO_SEG, NO_SEG);
414 l -= m;
415 }
416 }
417 list->downlevel(LIST_INCBIN);
418 if (instruction->times > 1) {
419 /*
420 * Dummy call to list->output to give the offset to the
421 * listing module.
422 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800423 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000424 list->uplevel(LIST_TIMES);
425 list->downlevel(LIST_TIMES);
426 }
427 fclose(fp);
428 return instruction->times * len;
429 }
430 return 0; /* if we're here, there's an error */
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000431 }
432
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700433 /* Check to see if we need an address-size prefix */
434 add_asp(instruction, bits);
435
H. Peter Anvin6867acc2007-10-10 14:58:45 -0700436 size_prob = false;
H. Peter Anvin70653092007-10-19 14:42:29 -0700437
438 for (temp = nasm_instructions[instruction->opcode]; temp->opcode != -1; temp++){
Keith Kaniosb7a89542007-04-12 02:40:54 +0000439 int m = matches(temp, instruction, bits);
H. Peter Anvin70653092007-10-19 14:42:29 -0700440
H. Peter Anvine2c80182005-01-15 22:15:51 +0000441 if (m == 99)
442 m += jmp_match(segment, offset, bits, instruction, temp->code);
H. Peter Anvineba20a72002-04-30 20:53:55 +0000443
H. Peter Anvine2c80182005-01-15 22:15:51 +0000444 if (m == 100) { /* matches! */
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000445 const char *codes = temp->code;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800446 int64_t insn_size = calcsize(segment, offset, bits,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000447 instruction, codes);
448 itimes = instruction->times;
449 if (insn_size < 0) /* shouldn't be, on pass two */
450 error(ERR_PANIC, "errors made it through from pass one");
451 else
452 while (itimes--) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700453 for (j = 0; j < MAXPREFIX; j++) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000454 uint8_t c = 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000455 switch (instruction->prefixes[j]) {
456 case P_LOCK:
457 c = 0xF0;
458 break;
459 case P_REPNE:
460 case P_REPNZ:
461 c = 0xF2;
462 break;
463 case P_REPE:
464 case P_REPZ:
465 case P_REP:
466 c = 0xF3;
467 break;
468 case R_CS:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000469 if (bits == 64) {
470 error(ERR_WARNING,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800471 "cs segment base generated, but will be ignored in 64-bit mode");
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000472 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000473 c = 0x2E;
474 break;
475 case R_DS:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000476 if (bits == 64) {
477 error(ERR_WARNING,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800478 "ds 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 = 0x3E;
481 break;
482 case R_ES:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000483 if (bits == 64) {
484 error(ERR_WARNING,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800485 "es 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 = 0x26;
488 break;
489 case R_FS:
490 c = 0x64;
491 break;
492 case R_GS:
493 c = 0x65;
494 break;
495 case R_SS:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000496 if (bits == 64) {
497 error(ERR_WARNING,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800498 "ss segment base generated, but will be ignored in 64-bit mode");
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000499 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000500 c = 0x36;
501 break;
502 case R_SEGR6:
503 case R_SEGR7:
504 error(ERR_NONFATAL,
505 "segr6 and segr7 cannot be used as prefixes");
506 break;
507 case P_A16:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000508 if (bits == 64) {
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000509 error(ERR_NONFATAL,
510 "16-bit addressing is not supported "
511 "in 64-bit mode");
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700512 } else if (bits != 16)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000513 c = 0x67;
514 break;
515 case P_A32:
516 if (bits != 32)
517 c = 0x67;
518 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700519 case P_A64:
520 if (bits != 64) {
521 error(ERR_NONFATAL,
522 "64-bit addressing is only supported "
523 "in 64-bit mode");
524 }
525 break;
526 case P_ASP:
527 c = 0x67;
528 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000529 case P_O16:
530 if (bits != 16)
531 c = 0x66;
532 break;
533 case P_O32:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000534 if (bits == 16)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000535 c = 0x66;
536 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700537 case P_O64:
538 /* REX.W */
539 break;
540 case P_OSP:
541 c = 0x66;
542 break;
543 case P_none:
544 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000545 default:
546 error(ERR_PANIC, "invalid instruction prefix");
547 }
548 if (c != 0) {
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800549 out(offset, segment, &c, OUT_RAWDATA, 1,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000550 NO_SEG, NO_SEG);
551 offset++;
552 }
H. Peter Anvin70653092007-10-19 14:42:29 -0700553 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000554 insn_end = offset + insn_size;
555 gencode(segment, offset, bits, instruction, codes,
556 insn_end);
557 offset += insn_size;
558 if (itimes > 0 && itimes == instruction->times - 1) {
559 /*
560 * Dummy call to list->output to give the offset to the
561 * listing module.
562 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800563 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000564 list->uplevel(LIST_TIMES);
565 }
566 }
567 if (instruction->times > 1)
568 list->downlevel(LIST_TIMES);
569 return offset - start;
570 } else if (m > 0 && m > size_prob) {
571 size_prob = m;
572 }
Keith Kaniosb7a89542007-04-12 02:40:54 +0000573// temp++;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000574 }
H. Peter Anvineba20a72002-04-30 20:53:55 +0000575
H. Peter Anvine2c80182005-01-15 22:15:51 +0000576 if (temp->opcode == -1) { /* didn't match any instruction */
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000577 switch (size_prob) {
578 case 1:
579 error(ERR_NONFATAL, "operation size not specified");
580 break;
581 case 2:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000582 error(ERR_NONFATAL, "mismatch in operand sizes");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000583 break;
584 case 3:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000585 error(ERR_NONFATAL, "no instruction for this cpu level");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000586 break;
587 case 4:
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000588 error(ERR_NONFATAL, "instruction not supported in 64-bit mode");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000589 break;
590 default:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000591 error(ERR_NONFATAL,
592 "invalid combination of opcode and operands");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000593 break;
594 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000595 }
596 return 0;
597}
598
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800599int64_t insn_size(int32_t segment, int64_t offset, int bits, uint32_t cp,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000600 insn * instruction, efunc error)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000601{
H. Peter Anvin3360d792007-09-11 04:16:57 +0000602 const struct itemplate *temp;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000603
H. Peter Anvine2c80182005-01-15 22:15:51 +0000604 errfunc = error; /* to pass to other functions */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000605 cpu = cp;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000606
607 if (instruction->opcode == -1)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000608 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000609
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700610 if (instruction->opcode == I_DB || instruction->opcode == I_DW ||
611 instruction->opcode == I_DD || instruction->opcode == I_DQ ||
612 instruction->opcode == I_DT || instruction->opcode == I_DO) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000613 extop *e;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000614 int32_t isize, osize, wsize = 0; /* placate gcc */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000615
H. Peter Anvine2c80182005-01-15 22:15:51 +0000616 isize = 0;
617 switch (instruction->opcode) {
618 case I_DB:
619 wsize = 1;
620 break;
621 case I_DW:
622 wsize = 2;
623 break;
624 case I_DD:
625 wsize = 4;
626 break;
627 case I_DQ:
628 wsize = 8;
629 break;
630 case I_DT:
631 wsize = 10;
632 break;
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700633 case I_DO:
634 wsize = 16;
635 break;
H. Peter Anvin16b0a332007-09-12 20:27:41 -0700636 default:
637 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000638 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000639
H. Peter Anvine2c80182005-01-15 22:15:51 +0000640 for (e = instruction->eops; e; e = e->next) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000641 int32_t align;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000642
H. Peter Anvine2c80182005-01-15 22:15:51 +0000643 osize = 0;
644 if (e->type == EOT_DB_NUMBER)
645 osize = 1;
646 else if (e->type == EOT_DB_STRING)
647 osize = e->stringlen;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000648
H. Peter Anvine2c80182005-01-15 22:15:51 +0000649 align = (-osize) % wsize;
650 if (align < 0)
651 align += wsize;
652 isize += osize + align;
653 }
654 return isize * instruction->times;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000655 }
656
H. Peter Anvine2c80182005-01-15 22:15:51 +0000657 if (instruction->opcode == I_INCBIN) {
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000658 char fname[FILENAME_MAX];
H. Peter Anvine2c80182005-01-15 22:15:51 +0000659 FILE *fp;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000660 int32_t len;
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000661 char *prefix = "", *combine;
662 char **pPrevPath = NULL;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000663
H. Peter Anvine2c80182005-01-15 22:15:51 +0000664 len = FILENAME_MAX - 1;
665 if (len > instruction->eops->stringlen)
666 len = instruction->eops->stringlen;
667 strncpy(fname, instruction->eops->stringval, len);
668 fname[len] = '\0';
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000669
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700670 /* added by alexfru: 'incbin' uses include paths */
671 while (1) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000672 combine = nasm_malloc(strlen(prefix) + len + 1);
673 strcpy(combine, prefix);
674 strcat(combine, fname);
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000675
H. Peter Anvine2c80182005-01-15 22:15:51 +0000676 if ((fp = fopen(combine, "rb")) != NULL) {
677 nasm_free(combine);
678 break;
679 }
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000680
H. Peter Anvine2c80182005-01-15 22:15:51 +0000681 nasm_free(combine);
682 pPrevPath = pp_get_include_path_ptr(pPrevPath);
683 if (pPrevPath == NULL)
684 break;
685 prefix = *pPrevPath;
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000686 }
687
688 if (fp == NULL)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000689 error(ERR_NONFATAL, "`incbin': unable to open file `%s'",
690 fname);
691 else if (fseek(fp, 0L, SEEK_END) < 0)
692 error(ERR_NONFATAL, "`incbin': unable to seek on file `%s'",
693 fname);
694 else {
695 len = ftell(fp);
696 fclose(fp);
697 if (instruction->eops->next) {
698 len -= instruction->eops->next->offset;
699 if (instruction->eops->next->next &&
700 len > instruction->eops->next->next->offset) {
701 len = instruction->eops->next->next->offset;
702 }
703 }
704 return instruction->times * len;
705 }
706 return 0; /* if we're here, there's an error */
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000707 }
708
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700709 /* Check to see if we need an address-size prefix */
710 add_asp(instruction, bits);
711
Keith Kaniosb7a89542007-04-12 02:40:54 +0000712 for (temp = nasm_instructions[instruction->opcode]; temp->opcode != -1; temp++) {
713 int m = matches(temp, instruction, bits);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000714 if (m == 99)
715 m += jmp_match(segment, offset, bits, instruction, temp->code);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000716
H. Peter Anvine2c80182005-01-15 22:15:51 +0000717 if (m == 100) {
718 /* we've matched an instruction. */
Charles Crayne5fbbc8c2007-11-07 19:03:46 -0800719 int64_t isize;
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000720 const char *codes = temp->code;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000721 int j;
722
723 isize = calcsize(segment, offset, bits, instruction, codes);
724 if (isize < 0)
725 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700726 for (j = 0; j < MAXPREFIX; j++) {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700727 switch (instruction->prefixes[j]) {
728 case P_A16:
729 if (bits != 16)
730 isize++;
731 break;
732 case P_A32:
733 if (bits != 32)
734 isize++;
735 break;
736 case P_O16:
737 if (bits != 16)
738 isize++;
739 break;
740 case P_O32:
741 if (bits == 16)
742 isize++;
743 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700744 case P_A64:
745 case P_O64:
746 case P_none:
747 break;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700748 default:
749 isize++;
750 break;
751 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000752 }
753 return isize * instruction->times;
754 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000755 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000756 return -1; /* didn't match any instruction */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000757}
758
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000759/* check that opn[op] is a signed byte of size 16 or 32,
760 and return the signed value*/
H. Peter Anvine2c80182005-01-15 22:15:51 +0000761static int is_sbyte(insn * ins, int op, int size)
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000762{
Keith Kaniosb7a89542007-04-12 02:40:54 +0000763 int32_t v;
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000764 int ret;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000765
766 ret = !(ins->forw_ref && ins->oprs[op].opflags) && /* dead in the water on forward reference or External */
767 optimizing >= 0 &&
768 !(ins->oprs[op].type & STRICT) &&
769 ins->oprs[op].wrt == NO_SEG && ins->oprs[op].segment == NO_SEG;
H. Peter Anvin734b1882002-04-30 21:01:08 +0000770
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000771 v = ins->oprs[op].offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000772 if (size == 16)
Keith Kaniosb7a89542007-04-12 02:40:54 +0000773 v = (int16_t)v; /* sign extend if 16 bits */
H. Peter Anvine2c80182005-01-15 22:15:51 +0000774
775 return ret && v >= -128L && v <= 127L;
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000776}
777
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800778static int64_t calcsize(int32_t segment, int64_t offset, int bits,
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000779 insn * ins, const char *codes)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000780{
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800781 int64_t length = 0;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000782 uint8_t c;
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000783 int rex_mask = ~0;
H. Peter Anvin839eca22007-10-29 23:12:47 -0700784 struct operand *opx;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000785
H. Peter Anvine3917fc2007-11-01 14:53:32 -0700786 ins->rex = 0; /* Ensure REX is reset */
787
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700788 if (ins->prefixes[PPS_OSIZE] == P_O64)
789 ins->rex |= REX_W;
790
H. Peter Anvine2c80182005-01-15 22:15:51 +0000791 (void)segment; /* Don't warn that this parameter is unused */
792 (void)offset; /* Don't warn that this parameter is unused */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000793
H. Peter Anvin839eca22007-10-29 23:12:47 -0700794 while (*codes) {
795 c = *codes++;
796 opx = &ins->oprs[c & 3];
797 switch (c) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000798 case 01:
799 case 02:
800 case 03:
801 codes += c, length += c;
802 break;
803 case 04:
804 case 05:
805 case 06:
806 case 07:
807 length++;
808 break;
809 case 010:
810 case 011:
811 case 012:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700812 case 013:
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000813 ins->rex |=
H. Peter Anvin839eca22007-10-29 23:12:47 -0700814 op_rexflags(opx, REX_B|REX_H|REX_P|REX_W);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000815 codes++, length++;
816 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000817 case 014:
818 case 015:
819 case 016:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700820 case 017:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000821 length++;
822 break;
823 case 020:
824 case 021:
825 case 022:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700826 case 023:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000827 length++;
828 break;
829 case 024:
830 case 025:
831 case 026:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700832 case 027:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000833 length++;
834 break;
835 case 030:
836 case 031:
837 case 032:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700838 case 033:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000839 length += 2;
840 break;
841 case 034:
842 case 035:
843 case 036:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700844 case 037:
H. Peter Anvin839eca22007-10-29 23:12:47 -0700845 if (opx->type & (BITS16 | BITS32 | BITS64))
846 length += (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000847 else
848 length += (bits == 16) ? 2 : 4;
849 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000850 case 040:
851 case 041:
852 case 042:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700853 case 043:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000854 length += 4;
855 break;
856 case 044:
857 case 045:
858 case 046:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700859 case 047:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700860 length += ins->addr_size >> 3;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000861 break;
862 case 050:
863 case 051:
864 case 052:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700865 case 053:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000866 length++;
867 break;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000868 case 054:
869 case 055:
870 case 056:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700871 case 057:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000872 length += 8; /* MOV reg64/imm */
873 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000874 case 060:
875 case 061:
876 case 062:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700877 case 063:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000878 length += 2;
879 break;
880 case 064:
881 case 065:
882 case 066:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700883 case 067:
H. Peter Anvin839eca22007-10-29 23:12:47 -0700884 if (opx->type & (BITS16 | BITS32 | BITS64))
885 length += (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000886 else
887 length += (bits == 16) ? 2 : 4;
888 break;
889 case 070:
890 case 071:
891 case 072:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700892 case 073:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000893 length += 4;
894 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700895 case 074:
896 case 075:
897 case 076:
898 case 077:
899 length += 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000900 break;
901 case 0140:
902 case 0141:
903 case 0142:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700904 case 0143:
H. Peter Anvin839eca22007-10-29 23:12:47 -0700905 length += is_sbyte(ins, c & 3, 16) ? 1 : 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000906 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000907 case 0144:
908 case 0145:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700909 case 0146:
910 case 0147:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000911 codes += 2;
912 length++;
913 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700914 case 0150:
915 case 0151:
916 case 0152:
917 case 0153:
H. Peter Anvin839eca22007-10-29 23:12:47 -0700918 length += is_sbyte(ins, c & 3, 32) ? 1 : 4;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700919 break;
920 case 0154:
921 case 0155:
922 case 0156:
923 case 0157:
924 codes += 2;
925 length++;
926 break;
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700927 case 0160:
928 case 0161:
929 case 0162:
930 case 0163:
931 length++;
932 ins->rex |= REX_D;
H. Peter Anvincf5180a2007-09-17 17:25:27 -0700933 ins->drexdst = regval(&ins->oprs[c & 3]);
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700934 break;
935 case 0164:
936 case 0165:
937 case 0166:
938 case 0167:
939 length++;
940 ins->rex |= REX_D|REX_OC;
H. Peter Anvincf5180a2007-09-17 17:25:27 -0700941 ins->drexdst = regval(&ins->oprs[c & 3]);
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700942 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700943 case 0170:
944 length++;
945 break;
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700946 case 0171:
947 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000948 case 0300:
949 case 0301:
H. Peter Anvin70653092007-10-19 14:42:29 -0700950 case 0302:
951 case 0303:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000952 break;
953 case 0310:
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700954 if (bits == 64)
955 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700956 length += (bits != 16) && !has_prefix(ins, PPS_ASIZE, P_A16);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000957 break;
958 case 0311:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700959 length += (bits != 32) && !has_prefix(ins, PPS_ASIZE, P_A32);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000960 break;
961 case 0312:
H. Peter Anvin70653092007-10-19 14:42:29 -0700962 break;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000963 case 0313:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700964 if (bits != 64 || has_prefix(ins, PPS_ASIZE, P_A16) ||
965 has_prefix(ins, PPS_ASIZE, P_A32))
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700966 return -1;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000967 break;
968 case 0320:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000969 length += (bits != 16);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000970 break;
971 case 0321:
972 length += (bits == 16);
973 break;
974 case 0322:
975 break;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000976 case 0323:
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000977 rex_mask &= ~REX_W;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000978 break;
979 case 0324:
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000980 ins->rex |= REX_W;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +0000981 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000982 case 0330:
983 codes++, length++;
984 break;
985 case 0331:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000986 break;
H. Peter Anvincb9b6902007-09-12 21:58:51 -0700987 case 0332:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000988 case 0333:
989 length++;
990 break;
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000991 case 0334:
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000992 ins->rex |= REX_L;
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000993 break;
H. Peter Anvincb9b6902007-09-12 21:58:51 -0700994 case 0335:
995 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000996 case 0340:
997 case 0341:
998 case 0342:
999 if (ins->oprs[0].segment != NO_SEG)
1000 errfunc(ERR_NONFATAL, "attempt to reserve non-constant"
1001 " quantity of BSS space");
1002 else
H. Peter Anvin839eca22007-10-29 23:12:47 -07001003 length += ins->oprs[0].offset << (c & 3);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001004 break;
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001005 case 0364:
1006 case 0365:
1007 break;
Keith Kanios48af1772007-08-17 07:37:52 +00001008 case 0366:
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001009 case 0367:
1010 length++;
1011 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001012 case 0370:
1013 case 0371:
1014 case 0372:
1015 break;
1016 case 0373:
1017 length++;
1018 break;
1019 default: /* can't do it by 'case' statements */
1020 if (c >= 0100 && c <= 0277) { /* it's an EA */
1021 ea ea_data;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001022 int rfield;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001023 int32_t rflags;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001024 ea_data.rex = 0; /* Ensure ea.REX is initially 0 */
H. Peter Anvin70653092007-10-19 14:42:29 -07001025
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001026 if (c <= 0177) {
1027 /* pick rfield from operand b */
1028 rflags = regflag(&ins->oprs[c & 7]);
1029 rfield = regvals[ins->oprs[c & 7].basereg];
1030 } else {
1031 rflags = 0;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001032 rfield = c & 7;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001033 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00001034
H. Peter Anvine2c80182005-01-15 22:15:51 +00001035 if (!process_ea
Keith Kaniosb7a89542007-04-12 02:40:54 +00001036 (&ins->oprs[(c >> 3) & 7], &ea_data, bits,
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001037 ins->addr_size, rfield, rflags, ins->forw_ref)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001038 errfunc(ERR_NONFATAL, "invalid effective address");
1039 return -1;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001040 } else {
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001041 ins->rex |= ea_data.rex;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001042 length += ea_data.size;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001043 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001044 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001045 errfunc(ERR_PANIC, "internal instruction table corrupt"
1046 ": instruction code 0x%02X given", c);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001047 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001048 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001049 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001050
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001051 ins->rex &= rex_mask;
H. Peter Anvin70653092007-10-19 14:42:29 -07001052
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001053 if (ins->rex & REX_D) {
1054 if (ins->rex & REX_H) {
1055 errfunc(ERR_NONFATAL, "cannot use high register in drex instruction");
1056 return -1;
1057 }
H. Peter Anvincf5180a2007-09-17 17:25:27 -07001058 if (bits != 64 && ((ins->rex & (REX_W|REX_X|REX_B)) ||
1059 ins->drexdst > 7)) {
1060 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1061 return -1;
1062 }
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001063 length++;
1064 } else if (ins->rex & REX_REAL) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001065 if (ins->rex & REX_H) {
1066 errfunc(ERR_NONFATAL, "cannot use high register in rex instruction");
1067 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001068 } else if (bits == 64) {
1069 length++;
1070 } else if ((ins->rex & REX_L) &&
1071 !(ins->rex & (REX_P|REX_W|REX_X|REX_B)) &&
1072 cpu >= IF_X86_64) {
1073 /* LOCK-as-REX.R */
1074 assert_no_prefix(ins, PPS_LREP);
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001075 length++;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001076 } else {
H. Peter Anvincf5180a2007-09-17 17:25:27 -07001077 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1078 return -1;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001079 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00001080 }
1081
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001082 return length;
1083}
Keith Kaniosb7a89542007-04-12 02:40:54 +00001084
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001085#define EMIT_REX() \
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001086 if (!(ins->rex & REX_D) && (ins->rex & REX_REAL) && (bits == 64)) { \
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001087 ins->rex = (ins->rex & REX_REAL)|REX_P; \
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001088 out(offset, segment, &ins->rex, OUT_RAWDATA, 1, NO_SEG, NO_SEG); \
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001089 ins->rex = 0; \
1090 offset += 1; \
1091 }
1092
Charles Crayne1f8bc4c2007-11-06 18:27:23 -08001093static void gencode(int32_t segment, int64_t offset, int bits,
1094 insn * ins, const char *codes, int64_t insn_end)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001095{
Keith Kaniosa6dfa782007-04-13 16:47:53 +00001096 static char condval[] = { /* conditional opcodes */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001097 0x7, 0x3, 0x2, 0x6, 0x2, 0x4, 0xF, 0xD, 0xC, 0xE, 0x6, 0x2,
1098 0x3, 0x7, 0x3, 0x5, 0xE, 0xC, 0xD, 0xF, 0x1, 0xB, 0x9, 0x5,
1099 0x0, 0xA, 0xA, 0xB, 0x8, 0x4
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001100 };
Keith Kaniosb7a89542007-04-12 02:40:54 +00001101 uint8_t c;
1102 uint8_t bytes[4];
Charles Crayne1f8bc4c2007-11-06 18:27:23 -08001103 int64_t size;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001104 int64_t data;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001105 struct operand *opx;
H. Peter Anvin70653092007-10-19 14:42:29 -07001106
H. Peter Anvin839eca22007-10-29 23:12:47 -07001107 while (*codes) {
1108 c = *codes++;
1109 opx = &ins->oprs[c & 3];
1110 switch (c) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001111 case 01:
1112 case 02:
1113 case 03:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001114 EMIT_REX();
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001115 out(offset, segment, codes, OUT_RAWDATA, c, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001116 codes += c;
1117 offset += c;
1118 break;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001119
H. Peter Anvine2c80182005-01-15 22:15:51 +00001120 case 04:
1121 case 06:
1122 switch (ins->oprs[0].basereg) {
1123 case R_CS:
1124 bytes[0] = 0x0E + (c == 0x04 ? 1 : 0);
1125 break;
1126 case R_DS:
1127 bytes[0] = 0x1E + (c == 0x04 ? 1 : 0);
1128 break;
1129 case R_ES:
1130 bytes[0] = 0x06 + (c == 0x04 ? 1 : 0);
1131 break;
1132 case R_SS:
1133 bytes[0] = 0x16 + (c == 0x04 ? 1 : 0);
1134 break;
1135 default:
1136 errfunc(ERR_PANIC,
1137 "bizarre 8086 segment register received");
1138 }
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001139 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001140 offset++;
1141 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001142
H. Peter Anvine2c80182005-01-15 22:15:51 +00001143 case 05:
1144 case 07:
1145 switch (ins->oprs[0].basereg) {
1146 case R_FS:
1147 bytes[0] = 0xA0 + (c == 0x05 ? 1 : 0);
1148 break;
1149 case R_GS:
1150 bytes[0] = 0xA8 + (c == 0x05 ? 1 : 0);
1151 break;
1152 default:
1153 errfunc(ERR_PANIC,
1154 "bizarre 386 segment register received");
1155 }
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001156 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001157 offset++;
1158 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001159
H. Peter Anvine2c80182005-01-15 22:15:51 +00001160 case 010:
1161 case 011:
1162 case 012:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001163 case 013:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001164 EMIT_REX();
H. Peter Anvin839eca22007-10-29 23:12:47 -07001165 bytes[0] = *codes++ + ((regval(opx)) & 7);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001166 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001167 offset += 1;
1168 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001169
H. Peter Anvine2c80182005-01-15 22:15:51 +00001170 case 014:
1171 case 015:
1172 case 016:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001173 case 017:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001174 if (opx->offset < -128 || opx->offset > 127) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001175 errfunc(ERR_WARNING, "signed byte value exceeds bounds");
1176 }
H. Peter Anvineba20a72002-04-30 20:53:55 +00001177
H. Peter Anvin839eca22007-10-29 23:12:47 -07001178 if (opx->segment != NO_SEG) {
1179 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001180 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001181 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001182 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001183 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001184 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001185 NO_SEG);
1186 }
1187 offset += 1;
1188 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001189
H. Peter Anvine2c80182005-01-15 22:15:51 +00001190 case 020:
1191 case 021:
1192 case 022:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001193 case 023:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001194 if (opx->offset < -256 || opx->offset > 255) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001195 errfunc(ERR_WARNING, "byte value exceeds bounds");
1196 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001197 if (opx->segment != NO_SEG) {
1198 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001199 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001200 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001201 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001202 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001203 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001204 NO_SEG);
1205 }
1206 offset += 1;
1207 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001208
H. Peter Anvine2c80182005-01-15 22:15:51 +00001209 case 024:
1210 case 025:
1211 case 026:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001212 case 027:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001213 if (opx->offset < 0 || opx->offset > 255)
H. Peter Anvine2c80182005-01-15 22:15:51 +00001214 errfunc(ERR_WARNING, "unsigned byte value exceeds bounds");
H. Peter Anvin839eca22007-10-29 23:12:47 -07001215 if (opx->segment != NO_SEG) {
1216 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001217 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001218 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001219 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001220 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001221 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001222 NO_SEG);
1223 }
1224 offset += 1;
1225 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001226
H. Peter Anvine2c80182005-01-15 22:15:51 +00001227 case 030:
1228 case 031:
1229 case 032:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001230 case 033:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001231 data = opx->offset;
1232 if (opx->segment == NO_SEG && opx->wrt == NO_SEG)
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001233 warn_overflow(2, data);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001234 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001235 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001236 offset += 2;
1237 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001238
H. Peter Anvine2c80182005-01-15 22:15:51 +00001239 case 034:
1240 case 035:
1241 case 036:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001242 case 037:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001243 if (opx->type & (BITS16 | BITS32))
1244 size = (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001245 else
1246 size = (bits == 16) ? 2 : 4;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001247 data = opx->offset;
1248 if (opx->segment == NO_SEG && opx->wrt == NO_SEG)
H. Peter Anvin10e27272007-10-29 22:56:08 -07001249 warn_overflow(size, data);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001250 out(offset, segment, &data, OUT_ADDRESS, size,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001251 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001252 offset += size;
1253 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001254
H. Peter Anvine2c80182005-01-15 22:15:51 +00001255 case 040:
1256 case 041:
1257 case 042:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001258 case 043:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001259 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001260 out(offset, segment, &data, OUT_ADDRESS, 4,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001261 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001262 offset += 4;
1263 break;
H. Peter Anvin3ba46772002-05-27 23:19:35 +00001264
H. Peter Anvine2c80182005-01-15 22:15:51 +00001265 case 044:
1266 case 045:
1267 case 046:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001268 case 047:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001269 data = opx->offset;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001270 size = ins->addr_size >> 3;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001271 if (opx->segment == NO_SEG &&
1272 opx->wrt == NO_SEG)
H. Peter Anvin10e27272007-10-29 22:56:08 -07001273 warn_overflow(size, data);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001274 out(offset, segment, &data, OUT_ADDRESS, size,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001275 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001276 offset += size;
1277 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001278
H. Peter Anvine2c80182005-01-15 22:15:51 +00001279 case 050:
1280 case 051:
1281 case 052:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001282 case 053:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001283 if (opx->segment != segment)
H. Peter Anvine2c80182005-01-15 22:15:51 +00001284 errfunc(ERR_NONFATAL,
1285 "short relative jump outside segment");
H. Peter Anvin839eca22007-10-29 23:12:47 -07001286 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001287 if (data > 127 || data < -128)
1288 errfunc(ERR_NONFATAL, "short jump is out of range");
1289 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001290 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001291 offset += 1;
1292 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001293
Keith Kaniosb7a89542007-04-12 02:40:54 +00001294 case 054:
1295 case 055:
1296 case 056:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001297 case 057:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001298 data = (int64_t)opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001299 out(offset, segment, &data, OUT_ADDRESS, 8,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001300 opx->segment, opx->wrt);
Keith Kaniosb7a89542007-04-12 02:40:54 +00001301 offset += 8;
1302 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001303
H. Peter Anvine2c80182005-01-15 22:15:51 +00001304 case 060:
1305 case 061:
1306 case 062:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001307 case 063:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001308 if (opx->segment != segment) {
1309 data = opx->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001310 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001311 OUT_REL2ADR, insn_end - offset,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001312 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001313 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001314 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001315 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001316 OUT_ADDRESS, 2, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001317 }
1318 offset += 2;
1319 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001320
H. Peter Anvine2c80182005-01-15 22:15:51 +00001321 case 064:
1322 case 065:
1323 case 066:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001324 case 067:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001325 if (opx->type & (BITS16 | BITS32 | BITS64))
1326 size = (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001327 else
1328 size = (bits == 16) ? 2 : 4;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001329 if (opx->segment != segment) {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001330 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001331 out(offset, segment, &data,
1332 size == 2 ? OUT_REL2ADR : OUT_REL4ADR,
1333 insn_end - offset, opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001334 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001335 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001336 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001337 OUT_ADDRESS, size, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001338 }
1339 offset += size;
1340 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001341
H. Peter Anvine2c80182005-01-15 22:15:51 +00001342 case 070:
1343 case 071:
1344 case 072:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001345 case 073:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001346 if (opx->segment != segment) {
1347 data = opx->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001348 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001349 OUT_REL4ADR, insn_end - offset,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001350 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001351 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001352 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001353 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001354 OUT_ADDRESS, 4, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001355 }
1356 offset += 4;
1357 break;
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001358
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001359 case 074:
1360 case 075:
1361 case 076:
1362 case 077:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001363 if (opx->segment == NO_SEG)
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001364 errfunc(ERR_NONFATAL, "value referenced by FAR is not"
1365 " relocatable");
1366 data = 0L;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001367 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001368 outfmt->segbase(1 + opx->segment),
1369 opx->wrt);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001370 offset += 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001371 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001372
H. Peter Anvine2c80182005-01-15 22:15:51 +00001373 case 0140:
1374 case 0141:
1375 case 0142:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001376 case 0143:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001377 data = opx->offset;
1378 if (is_sbyte(ins, c & 3, 16)) {
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001379 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001380 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001381 NO_SEG);
1382 offset++;
1383 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001384 if (opx->segment == NO_SEG &&
1385 opx->wrt == NO_SEG)
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001386 warn_overflow(2, data);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001387 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001388 opx->segment, opx->wrt);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001389 offset += 2;
1390 }
1391 break;
1392
1393 case 0144:
1394 case 0145:
1395 case 0146:
1396 case 0147:
1397 EMIT_REX();
1398 codes++;
1399 bytes[0] = *codes++;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001400 if (is_sbyte(ins, c & 3, 16))
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001401 bytes[0] |= 2; /* s-bit */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001402 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001403 offset++;
1404 break;
1405
1406 case 0150:
1407 case 0151:
1408 case 0152:
1409 case 0153:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001410 data = opx->offset;
1411 if (is_sbyte(ins, c & 3, 32)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001412 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001413 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001414 NO_SEG);
1415 offset++;
1416 } else {
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001417 out(offset, segment, &data, OUT_ADDRESS, 4,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001418 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001419 offset += 4;
1420 }
1421 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001422
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001423 case 0154:
1424 case 0155:
1425 case 0156:
1426 case 0157:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001427 EMIT_REX();
H. Peter Anvine2c80182005-01-15 22:15:51 +00001428 codes++;
1429 bytes[0] = *codes++;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001430 if (is_sbyte(ins, c & 3, 32))
H. Peter Anvine2c80182005-01-15 22:15:51 +00001431 bytes[0] |= 2; /* s-bit */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001432 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001433 offset++;
1434 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001435
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001436 case 0160:
1437 case 0161:
1438 case 0162:
1439 case 0163:
1440 case 0164:
1441 case 0165:
1442 case 0166:
1443 case 0167:
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001444 break;
1445
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001446 case 0170:
H. Peter Anvinc189b442007-10-05 17:04:32 -07001447 EMIT_REX();
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001448 bytes[0] = 0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001449 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001450 offset += 1;
1451 break;
1452
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001453 case 0171:
1454 bytes[0] =
1455 (ins->drexdst << 4) |
1456 (ins->rex & REX_OC ? 0x08 : 0) |
1457 (ins->rex & (REX_R|REX_X|REX_B));
1458 ins->rex = 0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001459 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001460 offset++;
1461 break;
1462
H. Peter Anvine2c80182005-01-15 22:15:51 +00001463 case 0300:
1464 case 0301:
1465 case 0302:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001466 case 0303:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001467 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001468
H. Peter Anvine2c80182005-01-15 22:15:51 +00001469 case 0310:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001470 if (bits == 32 && !has_prefix(ins, PPS_ASIZE, P_A16)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001471 *bytes = 0x67;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001472 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001473 offset += 1;
1474 } else
1475 offset += 0;
1476 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001477
H. Peter Anvine2c80182005-01-15 22:15:51 +00001478 case 0311:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001479 if (bits != 32 && !has_prefix(ins, PPS_ASIZE, P_A32)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001480 *bytes = 0x67;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001481 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001482 offset += 1;
1483 } else
1484 offset += 0;
1485 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001486
H. Peter Anvine2c80182005-01-15 22:15:51 +00001487 case 0312:
1488 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001489
Keith Kaniosb7a89542007-04-12 02:40:54 +00001490 case 0313:
1491 ins->rex = 0;
1492 break;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07001493
H. Peter Anvine2c80182005-01-15 22:15:51 +00001494 case 0320:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001495 if (bits != 16) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001496 *bytes = 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001497 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001498 offset += 1;
1499 } else
1500 offset += 0;
1501 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001502
H. Peter Anvine2c80182005-01-15 22:15:51 +00001503 case 0321:
1504 if (bits == 16) {
1505 *bytes = 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001506 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001507 offset += 1;
1508 } else
1509 offset += 0;
1510 break;
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001511
H. Peter Anvine2c80182005-01-15 22:15:51 +00001512 case 0322:
H. Peter Anvin70653092007-10-19 14:42:29 -07001513 case 0323:
1514 break;
1515
Keith Kaniosb7a89542007-04-12 02:40:54 +00001516 case 0324:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001517 ins->rex |= REX_W;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001518 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001519
H. Peter Anvine2c80182005-01-15 22:15:51 +00001520 case 0330:
1521 *bytes = *codes++ ^ condval[ins->condition];
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001522 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001523 offset += 1;
1524 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001525
H. Peter Anvine2c80182005-01-15 22:15:51 +00001526 case 0331:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001527 break;
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001528
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001529 case 0332:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001530 case 0333:
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001531 *bytes = c - 0332 + 0xF2;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001532 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001533 offset += 1;
1534 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001535
Keith Kanios48af1772007-08-17 07:37:52 +00001536 case 0334:
1537 if (ins->rex & REX_R) {
1538 *bytes = 0xF0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001539 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
Keith Kanios48af1772007-08-17 07:37:52 +00001540 offset += 1;
1541 }
1542 ins->rex &= ~(REX_L|REX_R);
1543 break;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001544
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001545 case 0335:
1546 break;
1547
H. Peter Anvine2c80182005-01-15 22:15:51 +00001548 case 0340:
1549 case 0341:
1550 case 0342:
1551 if (ins->oprs[0].segment != NO_SEG)
1552 errfunc(ERR_PANIC, "non-constant BSS size in pass two");
1553 else {
Charles Crayne1f8bc4c2007-11-06 18:27:23 -08001554 int64_t size = ins->oprs[0].offset << (c & 3);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001555 if (size > 0)
1556 out(offset, segment, NULL,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001557 OUT_RESERVE, size, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001558 offset += size;
1559 }
1560 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001561
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001562 case 0364:
1563 case 0365:
1564 break;
1565
Keith Kanios48af1772007-08-17 07:37:52 +00001566 case 0366:
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001567 case 0367:
1568 *bytes = c - 0366 + 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001569 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
Keith Kanios48af1772007-08-17 07:37:52 +00001570 offset += 1;
1571 break;
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001572
H. Peter Anvine2c80182005-01-15 22:15:51 +00001573 case 0370:
1574 case 0371:
1575 case 0372:
1576 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001577
H. Peter Anvine2c80182005-01-15 22:15:51 +00001578 case 0373:
1579 *bytes = bits == 16 ? 3 : 5;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001580 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001581 offset += 1;
1582 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001583
H. Peter Anvine2c80182005-01-15 22:15:51 +00001584 default: /* can't do it by 'case' statements */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001585 if (c >= 0100 && c <= 0277) { /* it's an EA */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001586 ea ea_data;
1587 int rfield;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001588 int32_t rflags;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001589 uint8_t *p;
1590 int32_t s;
H. Peter Anvin70653092007-10-19 14:42:29 -07001591
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001592 if (c <= 0177) {
1593 /* pick rfield from operand b */
1594 rflags = regflag(&ins->oprs[c & 7]);
1595 rfield = regvals[ins->oprs[c & 7].basereg];
1596 } else {
1597 /* rfield is constant */
1598 rflags = 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001599 rfield = c & 7;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001600 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001601
1602 if (!process_ea
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001603 (&ins->oprs[(c >> 3) & 7], &ea_data, bits,
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001604 ins->addr_size, rfield, rflags, ins->forw_ref)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001605 errfunc(ERR_NONFATAL, "invalid effective address");
1606 }
H. Peter Anvin70653092007-10-19 14:42:29 -07001607
Charles Crayne7e975552007-11-03 22:06:13 -07001608
H. Peter Anvine2c80182005-01-15 22:15:51 +00001609 p = bytes;
1610 *p++ = ea_data.modrm;
1611 if (ea_data.sib_present)
1612 *p++ = ea_data.sib;
1613
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001614 /* DREX suffixes come between the SIB and the displacement */
1615 if (ins->rex & REX_D) {
1616 *p++ =
1617 (ins->drexdst << 4) |
1618 (ins->rex & REX_OC ? 0x08 : 0) |
1619 (ins->rex & (REX_R|REX_X|REX_B));
1620 ins->rex = 0;
1621 }
1622
H. Peter Anvine2c80182005-01-15 22:15:51 +00001623 s = p - bytes;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001624 out(offset, segment, bytes, OUT_RAWDATA, s, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001625
1626 switch (ea_data.bytes) {
1627 case 0:
1628 break;
1629 case 1:
1630 if (ins->oprs[(c >> 3) & 7].segment != NO_SEG) {
1631 data = ins->oprs[(c >> 3) & 7].offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001632 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001633 ins->oprs[(c >> 3) & 7].segment,
1634 ins->oprs[(c >> 3) & 7].wrt);
1635 } else {
1636 *bytes = ins->oprs[(c >> 3) & 7].offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001637 out(offset, segment, bytes, OUT_RAWDATA, 1,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001638 NO_SEG, NO_SEG);
1639 }
1640 s++;
1641 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001642 case 8:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001643 case 2:
1644 case 4:
1645 data = ins->oprs[(c >> 3) & 7].offset;
Charles Crayne7e975552007-11-03 22:06:13 -07001646 warn_overflow(ea_data.bytes, data);
H. Peter Anvind0b0d282007-09-28 17:17:20 -07001647 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001648 ea_data.rip ? OUT_REL4ADR : OUT_ADDRESS,
1649 ea_data.bytes,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001650 ins->oprs[(c >> 3) & 7].segment,
1651 ins->oprs[(c >> 3) & 7].wrt);
1652 s += ea_data.bytes;
1653 break;
1654 }
1655 offset += s;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001656 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001657 errfunc(ERR_PANIC, "internal instruction table corrupt"
1658 ": instruction code 0x%02X given", c);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001659 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001660 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001661 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001662}
1663
H. Peter Anvin0ec60e62007-07-07 01:59:52 +00001664static int32_t regflag(const operand * o)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001665{
1666 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1667 errfunc(ERR_PANIC, "invalid operand passed to regflag()");
1668 }
1669 return reg_flags[o->basereg];
1670}
1671
H. Peter Anvin5b0e3ec2007-07-07 02:01:08 +00001672static int32_t regval(const operand * o)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001673{
H. Peter Anvine2c80182005-01-15 22:15:51 +00001674 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1675 errfunc(ERR_PANIC, "invalid operand passed to regval()");
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001676 }
H. Peter Anvin232badb2002-06-06 02:41:20 +00001677 return regvals[o->basereg];
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001678}
1679
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001680static int op_rexflags(const operand * o, int mask)
1681{
1682 int32_t flags;
1683 int val;
1684
1685 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1686 errfunc(ERR_PANIC, "invalid operand passed to op_rexflags()");
1687 }
1688
1689 flags = reg_flags[o->basereg];
1690 val = regvals[o->basereg];
1691
1692 return rexflags(val, flags, mask);
1693}
1694
1695static int rexflags(int val, int32_t flags, int mask)
1696{
1697 int rex = 0;
1698
1699 if (val >= 8)
1700 rex |= REX_B|REX_X|REX_R;
1701 if (flags & BITS64)
1702 rex |= REX_W;
1703 if (!(REG_HIGH & ~flags)) /* AH, CH, DH, BH */
1704 rex |= REX_H;
1705 else if (!(REG8 & ~flags) && val >= 4) /* SPL, BPL, SIL, DIL */
1706 rex |= REX_P;
1707
1708 return rex & mask;
1709}
1710
H. Peter Anvin3360d792007-09-11 04:16:57 +00001711static int matches(const struct itemplate *itemp, insn * instruction, int bits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001712{
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001713 int i, size[MAX_OPERANDS], asize, oprs, ret;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001714
1715 ret = 100;
1716
1717 /*
1718 * Check the opcode
1719 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001720 if (itemp->opcode != instruction->opcode)
1721 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001722
1723 /*
1724 * Count the operands
1725 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001726 if (itemp->operands != instruction->operands)
1727 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001728
1729 /*
1730 * Check that no spurious colons or TOs are present
1731 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001732 for (i = 0; i < itemp->operands; i++)
1733 if (instruction->oprs[i].type & ~itemp->opd[i] & (COLON | TO))
1734 return 0;
H. Peter Anvin70653092007-10-19 14:42:29 -07001735
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001736 /*
1737 * Check that the operand flags all match up
1738 */
H. Peter Anvin16b0a332007-09-12 20:27:41 -07001739 for (i = 0; i < itemp->operands; i++) {
H. Peter Anvincf5180a2007-09-17 17:25:27 -07001740 if (itemp->opd[i] & SAME_AS) {
1741 int j = itemp->opd[i] & ~SAME_AS;
1742 if (instruction->oprs[i].type != instruction->oprs[j].type ||
1743 instruction->oprs[i].basereg != instruction->oprs[j].basereg)
1744 return 0;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001745 } else if (itemp->opd[i] & ~instruction->oprs[i].type ||
H. Peter Anvine2c80182005-01-15 22:15:51 +00001746 ((itemp->opd[i] & SIZE_MASK) &&
1747 ((itemp->opd[i] ^ instruction->oprs[i].type) & SIZE_MASK))) {
H. Peter Anvin5a640e12007-05-29 23:57:12 +00001748 if ((itemp->opd[i] & ~instruction->oprs[i].type & ~SIZE_MASK) ||
H. Peter Anvine2c80182005-01-15 22:15:51 +00001749 (instruction->oprs[i].type & SIZE_MASK))
1750 return 0;
1751 else
H. Peter Anvine2c80182005-01-15 22:15:51 +00001752 return 1;
1753 }
H. Peter Anvin16b0a332007-09-12 20:27:41 -07001754 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001755
1756 /*
1757 * Check operand sizes
1758 */
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001759 if (itemp->flags & IF_ARMASK) {
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001760 memset(size, 0, sizeof size);
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001761
H. Peter Anvine2c80182005-01-15 22:15:51 +00001762 switch (itemp->flags & IF_ARMASK) {
1763 case IF_AR0:
1764 i = 0;
1765 break;
1766 case IF_AR1:
1767 i = 1;
1768 break;
1769 case IF_AR2:
1770 i = 2;
1771 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001772 case IF_AR3:
1773 i = 3;
1774 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001775 default:
1776 break; /* Shouldn't happen */
1777 }
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001778 switch (itemp->flags & IF_SMASK) {
1779 case IF_SB:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001780 size[i] = BITS8;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001781 break;
1782 case IF_SW:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001783 size[i] = BITS16;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001784 break;
1785 case IF_SD:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001786 size[i] = BITS32;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001787 break;
1788 case IF_SQ:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001789 size[i] = BITS64;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001790 break;
H. Peter Anvin41c9f6f2007-09-18 13:01:32 -07001791 case IF_SO:
1792 size[i] = BITS128;
1793 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001794 default:
1795 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001796 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001797 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001798 asize = 0;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001799 switch (itemp->flags & IF_SMASK) {
1800 case IF_SB:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001801 asize = BITS8;
1802 oprs = itemp->operands;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001803 break;
1804 case IF_SW:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001805 asize = BITS16;
1806 oprs = itemp->operands;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001807 break;
1808 case IF_SD:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001809 asize = BITS32;
1810 oprs = itemp->operands;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001811 break;
1812 case IF_SQ:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001813 asize = BITS64;
1814 oprs = itemp->operands;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001815 break;
H. Peter Anvin41c9f6f2007-09-18 13:01:32 -07001816 case IF_SO:
1817 asize = BITS128;
1818 oprs = itemp->operands;
1819 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001820 default:
1821 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001822 }
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001823 for (i = 0; i < MAX_OPERANDS; i++)
1824 size[i] = asize;
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001825 }
H. Peter Anvin70653092007-10-19 14:42:29 -07001826
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001827 if (itemp->flags & (IF_SM | IF_SM2)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001828 oprs = (itemp->flags & IF_SM2 ? 2 : itemp->operands);
1829 asize = 0;
1830 for (i = 0; i < oprs; i++) {
1831 if ((asize = itemp->opd[i] & SIZE_MASK) != 0) {
1832 int j;
1833 for (j = 0; j < oprs; j++)
1834 size[j] = asize;
1835 break;
1836 }
1837 }
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001838 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001839 oprs = itemp->operands;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001840 }
1841
Keith Kaniosb7a89542007-04-12 02:40:54 +00001842 for (i = 0; i < itemp->operands; i++) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001843 if (!(itemp->opd[i] & SIZE_MASK) &&
1844 (instruction->oprs[i].type & SIZE_MASK & ~size[i]))
H. Peter Anvine2c80182005-01-15 22:15:51 +00001845 return 2;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001846 }
1847
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001848 /*
1849 * Check template is okay at the set cpu level
1850 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00001851 if (((itemp->flags & IF_PLEVEL) > cpu))
H. Peter Anvine2c80182005-01-15 22:15:51 +00001852 return 3;
H. Peter Anvin70653092007-10-19 14:42:29 -07001853
Keith Kaniosb7a89542007-04-12 02:40:54 +00001854 /*
1855 * Check if instruction is available in long mode
1856 */
1857 if ((itemp->flags & IF_NOLONG) && (bits == 64))
1858 return 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001859
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001860 /*
1861 * Check if special handling needed for Jumps
1862 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00001863 if ((uint8_t)(itemp->code[0]) >= 0370)
H. Peter Anvine2c80182005-01-15 22:15:51 +00001864 return 99;
1865
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001866 return ret;
1867}
1868
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001869static ea *process_ea(operand * input, ea * output, int bits,
1870 int addrbits, int rfield, int32_t rflags, int forw_ref)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001871{
H. Peter Anvin6867acc2007-10-10 14:58:45 -07001872 output->rip = false;
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00001873
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001874 /* REX flags for the rfield operand */
1875 output->rex |= rexflags(rfield, rflags, REX_R|REX_P|REX_W|REX_H);
1876
Keith Kaniosb7a89542007-04-12 02:40:54 +00001877 if (!(REGISTER & ~input->type)) { /* register direct */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001878 int i;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001879 int32_t f;
1880
1881 if (input->basereg < EXPR_REG_START /* Verify as Register */
Keith Kaniosb7a89542007-04-12 02:40:54 +00001882 || input->basereg >= REG_ENUM_LIMIT)
H. Peter Anvine2c80182005-01-15 22:15:51 +00001883 return NULL;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001884 f = regflag(input);
Keith Kaniosb7a89542007-04-12 02:40:54 +00001885 i = regvals[input->basereg];
Keith Kaniosb7a89542007-04-12 02:40:54 +00001886
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001887 if (REG_EA & ~f)
1888 return NULL; /* Invalid EA register */
H. Peter Anvin70653092007-10-19 14:42:29 -07001889
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001890 output->rex |= op_rexflags(input, REX_B|REX_P|REX_W|REX_H);
1891
H. Peter Anvin6867acc2007-10-10 14:58:45 -07001892 output->sib_present = false; /* no SIB necessary */
Keith Kaniosb7a89542007-04-12 02:40:54 +00001893 output->bytes = 0; /* no offset necessary either */
1894 output->modrm = 0xC0 | ((rfield & 7) << 3) | (i & 7);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001895 } else { /* it's a memory reference */
1896 if (input->basereg == -1
1897 && (input->indexreg == -1 || input->scale == 0)) {
1898 /* it's a pure offset */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001899 if (bits == 64 && (~input->type & IP_REL)) {
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00001900 int scale, index, base;
H. Peter Anvin6867acc2007-10-10 14:58:45 -07001901 output->sib_present = true;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00001902 scale = 0;
1903 index = 4;
1904 base = 5;
1905 output->sib = (scale << 6) | (index << 3) | base;
1906 output->bytes = 4;
1907 output->modrm = 4 | ((rfield & 7) << 3);
H. Peter Anvin6867acc2007-10-10 14:58:45 -07001908 output->rip = false;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00001909 } else {
H. Peter Anvin6867acc2007-10-10 14:58:45 -07001910 output->sib_present = false;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00001911 output->bytes = (addrbits != 16 ? 4 : 2);
1912 output->modrm = (addrbits != 16 ? 5 : 6) | ((rfield & 7) << 3);
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001913 output->rip = bits == 64;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00001914 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001915 } else { /* it's an indirection */
1916 int i = input->indexreg, b = input->basereg, s = input->scale;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001917 int32_t o = input->offset, seg = input->segment;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001918 int hb = input->hintbase, ht = input->hinttype;
1919 int t;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001920 int it, bt;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001921 int32_t ix, bx; /* register flags */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001922
H. Peter Anvine2c80182005-01-15 22:15:51 +00001923 if (s == 0)
1924 i = -1; /* make this easy, at least */
H. Peter Anvin70653092007-10-19 14:42:29 -07001925
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001926 if (i >= EXPR_REG_START && i < REG_ENUM_LIMIT) {
Keith Kaniosb7a89542007-04-12 02:40:54 +00001927 it = regvals[i];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001928 ix = reg_flags[i];
1929 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00001930 it = -1;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001931 ix = 0;
1932 }
H. Peter Anvin70653092007-10-19 14:42:29 -07001933
H. Peter Anvinb0c54622007-10-28 23:21:46 -07001934 if (b >= EXPR_REG_START && b < REG_ENUM_LIMIT) {
Keith Kaniosb7a89542007-04-12 02:40:54 +00001935 bt = regvals[b];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001936 bx = reg_flags[b];
1937 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00001938 bt = -1;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001939 bx = 0;
1940 }
H. Peter Anvin70653092007-10-19 14:42:29 -07001941
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001942 /* check for a 32/64-bit memory reference... */
1943 if ((ix|bx) & (BITS32|BITS64)) {
Keith Kaniosb7a89542007-04-12 02:40:54 +00001944 /* it must be a 32/64-bit memory reference. Firstly we have
1945 * to check that all registers involved are type E/Rxx. */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001946 int32_t sok = BITS32|BITS64;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001947
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001948 if (it != -1) {
1949 if (!(REG64 & ~ix) || !(REG32 & ~ix))
1950 sok &= ix;
1951 else
1952 return NULL;
1953 }
1954
1955 if (bt != -1) {
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00001956 if (REG_GPR & ~bx)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001957 return NULL; /* Invalid register */
H. Peter Anvina57e8d42007-05-30 03:44:02 +00001958 if (~sok & bx & SIZE_MASK)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001959 return NULL; /* Invalid size */
H. Peter Anvinb0c54622007-10-28 23:21:46 -07001960 sok &= bx;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001961 }
H. Peter Anvin70653092007-10-19 14:42:29 -07001962
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001963 /* While we're here, ensure the user didn't specify
1964 WORD or QWORD. */
1965 if (input->disp_size == 16 || input->disp_size == 64)
1966 return NULL;
1967
1968 if (addrbits == 16 ||
1969 (addrbits == 32 && !(sok & BITS32)) ||
1970 (addrbits == 64 && !(sok & BITS64)))
1971 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001972
Keith Kaniosb7a89542007-04-12 02:40:54 +00001973 /* now reorganize base/index */
1974 if (s == 1 && bt != it && bt != -1 && it != -1 &&
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001975 ((hb == b && ht == EAH_NOTBASE)
1976 || (hb == i && ht == EAH_MAKEBASE))) {
1977 /* swap if hints say so */
1978 t = bt, bt = it, it = t;
1979 t = bx, bx = ix, ix = t;
1980 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00001981 if (bt == it) /* convert EAX+2*EAX to 3*EAX */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001982 bt = -1, bx = 0, s++;
1983 if (bt == -1 && s == 1 && !(hb == it && ht == EAH_NOTBASE)) {
1984 /* make single reg base, unless hint */
1985 bt = it, bx = ix, it = -1, ix = 0;
1986 }
H. Peter Anvinf5843c62007-09-10 18:59:26 +00001987 if (((s == 2 && it != REG_NUM_ESP
H. Peter Anvine2c80182005-01-15 22:15:51 +00001988 && !(input->eaflags & EAF_TIMESTWO)) || s == 3
Keith Kaniosb7a89542007-04-12 02:40:54 +00001989 || s == 5 || s == 9) && bt == -1)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001990 bt = it, bx = ix, s--; /* convert 3*EAX to EAX+2*EAX */
Keith Kanios48af1772007-08-17 07:37:52 +00001991 if (it == -1 && (bt & 7) != REG_NUM_ESP
H. Peter Anvine2c80182005-01-15 22:15:51 +00001992 && (input->eaflags & EAF_TIMESTWO))
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001993 it = bt, ix = bx, bt = -1, bx = 0, s = 1;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001994 /* convert [NOSPLIT EAX] to sib format with 0x0 displacement */
Keith Kanios48af1772007-08-17 07:37:52 +00001995 if (s == 1 && it == REG_NUM_ESP) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001996 /* swap ESP into base if scale is 1 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00001997 t = it, it = bt, bt = t;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001998 t = ix, ix = bx, bx = t;
1999 }
Keith Kanios48af1772007-08-17 07:37:52 +00002000 if (it == REG_NUM_ESP
Keith Kaniosb7a89542007-04-12 02:40:54 +00002001 || (s != 1 && s != 2 && s != 4 && s != 8 && it != -1))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002002 return NULL; /* wrong, for various reasons */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002003
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002004 output->rex |= rexflags(it, ix, REX_X);
2005 output->rex |= rexflags(bt, bx, REX_B);
Keith Kaniosb7a89542007-04-12 02:40:54 +00002006
Keith Kanios48af1772007-08-17 07:37:52 +00002007 if (it == -1 && (bt & 7) != REG_NUM_ESP) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002008 /* no SIB needed */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002009 int mod, rm;
H. Peter Anvin70653092007-10-19 14:42:29 -07002010
Keith Kaniosb7a89542007-04-12 02:40:54 +00002011 if (bt == -1) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002012 rm = 5;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002013 mod = 0;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002014 } else {
2015 rm = (bt & 7);
Keith Kanios48af1772007-08-17 07:37:52 +00002016 if (rm != REG_NUM_EBP && o == 0 &&
Keith Kaniosb7a89542007-04-12 02:40:54 +00002017 seg == NO_SEG && !forw_ref &&
2018 !(input->eaflags &
2019 (EAF_BYTEOFFS | EAF_WORDOFFS)))
2020 mod = 0;
2021 else if (input->eaflags & EAF_BYTEOFFS ||
2022 (o >= -128 && o <= 127 && seg == NO_SEG
2023 && !forw_ref
2024 && !(input->eaflags & EAF_WORDOFFS)))
2025 mod = 1;
2026 else
2027 mod = 2;
2028 }
H. Peter Anvinea838272002-04-30 20:51:53 +00002029
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002030 output->sib_present = false;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002031 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2032 output->modrm = (mod << 6) | ((rfield & 7) << 3) | rm;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002033 } else {
2034 /* we need a SIB */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002035 int mod, scale, index, base;
H. Peter Anvin70653092007-10-19 14:42:29 -07002036
Keith Kaniosb7a89542007-04-12 02:40:54 +00002037 if (it == -1)
2038 index = 4, s = 1;
2039 else
2040 index = (it & 7);
H. Peter Anvin70653092007-10-19 14:42:29 -07002041
H. Peter Anvine2c80182005-01-15 22:15:51 +00002042 switch (s) {
2043 case 1:
2044 scale = 0;
2045 break;
2046 case 2:
2047 scale = 1;
2048 break;
2049 case 4:
2050 scale = 2;
2051 break;
2052 case 8:
2053 scale = 3;
2054 break;
2055 default: /* then what the smeg is it? */
2056 return NULL; /* panic */
2057 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002058
Keith Kaniosb7a89542007-04-12 02:40:54 +00002059 if (bt == -1) {
2060 base = 5;
2061 mod = 0;
2062 } else {
2063 base = (bt & 7);
Keith Kanios48af1772007-08-17 07:37:52 +00002064 if (base != REG_NUM_EBP && o == 0 &&
H. Peter Anvine2c80182005-01-15 22:15:51 +00002065 seg == NO_SEG && !forw_ref &&
2066 !(input->eaflags &
Keith Kaniosb7a89542007-04-12 02:40:54 +00002067 (EAF_BYTEOFFS | EAF_WORDOFFS)))
2068 mod = 0;
2069 else if (input->eaflags & EAF_BYTEOFFS ||
2070 (o >= -128 && o <= 127 && seg == NO_SEG
2071 && !forw_ref
2072 && !(input->eaflags & EAF_WORDOFFS)))
2073 mod = 1;
2074 else
2075 mod = 2;
2076 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002077
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002078 output->sib_present = true;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002079 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2080 output->modrm = (mod << 6) | ((rfield & 7) << 3) | 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002081 output->sib = (scale << 6) | (index << 3) | base;
2082 }
2083 } else { /* it's 16-bit */
2084 int mod, rm;
H. Peter Anvin70653092007-10-19 14:42:29 -07002085
Keith Kaniosb7a89542007-04-12 02:40:54 +00002086 /* check for 64-bit long mode */
2087 if (addrbits == 64)
2088 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002089
H. Peter Anvine2c80182005-01-15 22:15:51 +00002090 /* check all registers are BX, BP, SI or DI */
2091 if ((b != -1 && b != R_BP && b != R_BX && b != R_SI
2092 && b != R_DI) || (i != -1 && i != R_BP && i != R_BX
2093 && i != R_SI && i != R_DI))
2094 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002095
Keith Kaniosb7a89542007-04-12 02:40:54 +00002096 /* ensure the user didn't specify DWORD/QWORD */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002097 if (input->disp_size == 32 || input->disp_size == 64)
H. Peter Anvine2c80182005-01-15 22:15:51 +00002098 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002099
H. Peter Anvine2c80182005-01-15 22:15:51 +00002100 if (s != 1 && i != -1)
2101 return NULL; /* no can do, in 16-bit EA */
2102 if (b == -1 && i != -1) {
2103 int tmp = b;
2104 b = i;
2105 i = tmp;
2106 } /* swap */
2107 if ((b == R_SI || b == R_DI) && i != -1) {
2108 int tmp = b;
2109 b = i;
2110 i = tmp;
2111 }
2112 /* have BX/BP as base, SI/DI index */
2113 if (b == i)
2114 return NULL; /* shouldn't ever happen, in theory */
2115 if (i != -1 && b != -1 &&
2116 (i == R_BP || i == R_BX || b == R_SI || b == R_DI))
2117 return NULL; /* invalid combinations */
2118 if (b == -1) /* pure offset: handled above */
2119 return NULL; /* so if it gets to here, panic! */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002120
H. Peter Anvine2c80182005-01-15 22:15:51 +00002121 rm = -1;
2122 if (i != -1)
2123 switch (i * 256 + b) {
2124 case R_SI * 256 + R_BX:
2125 rm = 0;
2126 break;
2127 case R_DI * 256 + R_BX:
2128 rm = 1;
2129 break;
2130 case R_SI * 256 + R_BP:
2131 rm = 2;
2132 break;
2133 case R_DI * 256 + R_BP:
2134 rm = 3;
2135 break;
2136 } else
2137 switch (b) {
2138 case R_SI:
2139 rm = 4;
2140 break;
2141 case R_DI:
2142 rm = 5;
2143 break;
2144 case R_BP:
2145 rm = 6;
2146 break;
2147 case R_BX:
2148 rm = 7;
2149 break;
2150 }
2151 if (rm == -1) /* can't happen, in theory */
2152 return NULL; /* so panic if it does */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002153
H. Peter Anvine2c80182005-01-15 22:15:51 +00002154 if (o == 0 && seg == NO_SEG && !forw_ref && rm != 6 &&
2155 !(input->eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS)))
2156 mod = 0;
2157 else if (input->eaflags & EAF_BYTEOFFS ||
2158 (o >= -128 && o <= 127 && seg == NO_SEG
2159 && !forw_ref
2160 && !(input->eaflags & EAF_WORDOFFS)))
2161 mod = 1;
2162 else
2163 mod = 2;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002164
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002165 output->sib_present = false; /* no SIB - it's 16-bit */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002166 output->bytes = mod; /* bytes of offset needed */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002167 output->modrm = (mod << 6) | ((rfield & 7) << 3) | rm;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002168 }
2169 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002170 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002171
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002172 output->size = 1 + output->sib_present + output->bytes;
2173 return output;
2174}
2175
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002176static void add_asp(insn *ins, int addrbits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002177{
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002178 int j, valid;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002179 int defdisp;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002180
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002181 valid = (addrbits == 64) ? 64|32 : 32|16;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002182
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002183 switch (ins->prefixes[PPS_ASIZE]) {
2184 case P_A16:
2185 valid &= 16;
2186 break;
2187 case P_A32:
2188 valid &= 32;
2189 break;
2190 case P_A64:
2191 valid &= 64;
2192 break;
2193 case P_ASP:
2194 valid &= (addrbits == 32) ? 16 : 32;
2195 break;
2196 default:
2197 break;
2198 }
2199
2200 for (j = 0; j < ins->operands; j++) {
2201 if (!(MEMORY & ~ins->oprs[j].type)) {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002202 int32_t i, b;
H. Peter Anvin70653092007-10-19 14:42:29 -07002203
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002204 /* Verify as Register */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002205 if (ins->oprs[j].indexreg < EXPR_REG_START
2206 || ins->oprs[j].indexreg >= REG_ENUM_LIMIT)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002207 i = 0;
2208 else
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002209 i = reg_flags[ins->oprs[j].indexreg];
H. Peter Anvin70653092007-10-19 14:42:29 -07002210
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002211 /* Verify as Register */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002212 if (ins->oprs[j].basereg < EXPR_REG_START
2213 || ins->oprs[j].basereg >= REG_ENUM_LIMIT)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002214 b = 0;
2215 else
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002216 b = reg_flags[ins->oprs[j].basereg];
H. Peter Anvin70653092007-10-19 14:42:29 -07002217
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002218 if (ins->oprs[j].scale == 0)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002219 i = 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002220
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002221 if (!i && !b) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002222 int ds = ins->oprs[j].disp_size;
2223 if ((addrbits != 64 && ds > 8) ||
2224 (addrbits == 64 && ds == 16))
2225 valid &= ds;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002226 } else {
2227 if (!(REG16 & ~b))
2228 valid &= 16;
2229 if (!(REG32 & ~b))
2230 valid &= 32;
2231 if (!(REG64 & ~b))
2232 valid &= 64;
H. Peter Anvin70653092007-10-19 14:42:29 -07002233
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002234 if (!(REG16 & ~i))
2235 valid &= 16;
2236 if (!(REG32 & ~i))
2237 valid &= 32;
2238 if (!(REG64 & ~i))
2239 valid &= 64;
2240 }
2241 }
2242 }
2243
2244 if (valid & addrbits) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002245 ins->addr_size = addrbits;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002246 } else if (valid & ((addrbits == 32) ? 16 : 32)) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002247 /* Add an address size prefix */
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002248 enum prefixes pref = (addrbits == 32) ? P_A16 : P_A32;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002249 ins->prefixes[PPS_ASIZE] = pref;
2250 ins->addr_size = (addrbits == 32) ? 16 : 32;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002251 } else {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002252 /* Impossible... */
2253 errfunc(ERR_NONFATAL, "impossible combination of address sizes");
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002254 ins->addr_size = addrbits; /* Error recovery */
2255 }
2256
2257 defdisp = ins->addr_size == 16 ? 16 : 32;
2258
2259 for (j = 0; j < ins->operands; j++) {
2260 if (!(MEM_OFFS & ~ins->oprs[j].type) &&
2261 (ins->oprs[j].disp_size ? ins->oprs[j].disp_size : defdisp)
2262 != ins->addr_size) {
2263 /* mem_offs sizes must match the address size; if not,
2264 strip the MEM_OFFS bit and match only EA instructions */
2265 ins->oprs[j].type &= ~(MEM_OFFS & ~MEMORY);
2266 }
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002267 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002268}