blob: 0c3f5f1b8b3b9e8142d651ce782c7680904b30a7 [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
Beroset095e6a22007-12-29 09:44:23 -05005 * redistributable under the license given in the file "LICENSE"
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00006 * 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
H. Peter Anvina30cc072007-11-18 21:55:26 -080036 * \144..\147 - or 2 (s-field) into opcode byte if operand 0..3
37 * is a signed byte rather than a word. Opcode byte follows.
H. Peter Anvin7eb4a382007-09-17 15:49:30 -070038 * \150..\153 - an immediate dword or signed byte for operand 0..3
H. Peter Anvina30cc072007-11-18 21:55:26 -080039 * \154..\157 - or 2 (s-field) into opcode byte if operand 0..3
H. Peter Anvin32cd4c22008-04-04 13:34:53 -070040 * is a signed byte rather than a dword. Opcode byte follows.
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 Anvind85d2502008-05-04 17:53:31 -070051 * \172\ab - the register number from operand a in bits 7..4, with
52 * the 4-bit immediate from operand b in bits 0..3.
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000053 * \2ab - a ModRM, calculated on EA in operand a, with the spare
54 * field equal to digit b.
H. Peter Anvin32cd4c22008-04-04 13:34:53 -070055 * \250..\253 - same as \150..\153, except warn if the 64-bit operand
56 * is not equal to the truncated and sign-extended 32-bit
57 * operand; used for 32-bit immediates in 64-bit mode.
H. Peter Anvind85d2502008-05-04 17:53:31 -070058 * \260..\263 - this instruction uses VEX rather than REX, with the
59 * V field taken from operand 0..3.
60 * \270 - this instruction uses VEX rather than REX, with the
61 * V field set to 1111b.
62 *
63 * VEX prefixes are followed by the sequence:
64 * \1mm\1wp where mm is the M field; and wp is:
65 * 01 0ww lpp
66 * ww = 0 for W = 0
67 * ww = 1 for W = 1
68 * ww = 2 for W used as REX.W
69 *
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000070 * \310 - indicates fixed 16-bit address size, i.e. optional 0x67.
71 * \311 - indicates fixed 32-bit address size, i.e. optional 0x67.
Keith Kanios48af1772007-08-17 07:37:52 +000072 * \312 - (disassembler only) marker on LOOP, LOOPxx instructions.
H. Peter Anvince2b3972007-05-30 22:21:11 +000073 * \313 - indicates fixed 64-bit address size, 0x67 invalid.
H. Peter Anvin23440102007-11-12 21:02:33 -080074 * \314 - (disassembler only) invalid with REX.B
75 * \315 - (disassembler only) invalid with REX.X
76 * \316 - (disassembler only) invalid with REX.R
77 * \317 - (disassembler only) invalid with REX.W
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000078 * \320 - indicates fixed 16-bit operand size, i.e. optional 0x66.
79 * \321 - indicates fixed 32-bit operand size, i.e. optional 0x66.
80 * \322 - indicates that this instruction is only valid when the
81 * operand size is the default (instruction to disassembler,
82 * generates no code in the assembler)
H. Peter Anvince2b3972007-05-30 22:21:11 +000083 * \323 - indicates fixed 64-bit operand size, REX on extensions only.
Keith Kaniosb7a89542007-04-12 02:40:54 +000084 * \324 - indicates 64-bit operand size requiring REX prefix.
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000085 * \330 - a literal byte follows in the code stream, to be added
86 * to the condition code value of the instruction.
Keith Kanios48af1772007-08-17 07:37:52 +000087 * \331 - instruction not valid with REP prefix. Hint for
H. Peter Anvinef7468f2002-04-30 20:57:59 +000088 * disassembler only; for SSE instructions.
H. Peter Anvincb9b6902007-09-12 21:58:51 -070089 * \332 - REP prefix (0xF2 byte) used as opcode extension.
90 * \333 - REP prefix (0xF3 byte) used as opcode extension.
Keith Kanios48af1772007-08-17 07:37:52 +000091 * \334 - LOCK prefix used instead of REX.R
H. Peter Anvincb9b6902007-09-12 21:58:51 -070092 * \335 - disassemble a rep (0xF3 byte) prefix as repe not rep.
Keith Kaniosb7a89542007-04-12 02:40:54 +000093 * \340 - reserve <operand 0> bytes of uninitialized storage.
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000094 * Operand 0 had better be a segmentless constant.
H. Peter Anvin62cb6062007-09-11 22:44:03 +000095 * \364 - operand-size prefix (0x66) not permitted
96 * \365 - address-size prefix (0x67) not permitted
97 * \366 - operand-size prefix (0x66) used as opcode extension
98 * \367 - address-size prefix (0x67) used as opcode extension
H. Peter Anvin788e6c12002-04-30 21:02:01 +000099 * \370,\371,\372 - match only if operand 0 meets byte jump criteria.
100 * 370 is used for Jcc, 371 is used for JMP.
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000101 * \373 - assemble 0x03 if bits==16, 0x05 if bits==32;
102 * used for conditional jump over longer jump
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000103 */
104
H. Peter Anvinfe501952007-10-02 21:53:51 -0700105#include "compiler.h"
106
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000107#include <stdio.h>
108#include <string.h>
Keith Kaniosb7a89542007-04-12 02:40:54 +0000109#include <inttypes.h>
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000110
111#include "nasm.h"
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000112#include "nasmlib.h"
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000113#include "assemble.h"
114#include "insns.h"
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000115#include "preproc.h"
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000116#include "regflags.c"
Keith Kaniosb7a89542007-04-12 02:40:54 +0000117#include "regvals.c"
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000118
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000119typedef struct {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000120 int sib_present; /* is a SIB byte necessary? */
121 int bytes; /* # of bytes of offset needed */
122 int size; /* lazy - this is sib+bytes+1 */
123 uint8_t modrm, sib, rex, rip; /* the bytes themselves */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000124} ea;
125
Keith Kaniosb7a89542007-04-12 02:40:54 +0000126static uint32_t cpu; /* cpu level received from nasm.c */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000127static efunc errfunc;
128static struct ofmt *outfmt;
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000129static ListGen *list;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000130
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800131static int64_t calcsize(int32_t, int64_t, int, insn *, const char *);
132static void gencode(int32_t, int64_t, int, insn *, const char *, int64_t);
H. Peter Anvin3360d792007-09-11 04:16:57 +0000133static int matches(const struct itemplate *, insn *, int bits);
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000134static int32_t regflag(const operand *);
135static int32_t regval(const operand *);
136static int rexflags(int, int32_t, int);
137static int op_rexflags(const operand *, int);
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700138static ea *process_ea(operand *, ea *, int, int, int, int32_t, int);
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700139static void add_asp(insn *, int);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000140
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700141static int has_prefix(insn * ins, enum prefix_pos pos, enum prefixes prefix)
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000142{
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700143 return ins->prefixes[pos] == prefix;
144}
145
146static void assert_no_prefix(insn * ins, enum prefix_pos pos)
147{
148 if (ins->prefixes[pos])
149 errfunc(ERR_NONFATAL, "invalid %s prefix",
150 prefix_name(ins->prefixes[pos]));
151}
152
153static const char *size_name(int size)
154{
155 switch (size) {
156 case 1:
157 return "byte";
158 case 2:
159 return "word";
160 case 4:
161 return "dword";
162 case 8:
163 return "qword";
164 case 10:
165 return "tword";
166 case 16:
167 return "oword";
168 default:
169 return "???";
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000170 }
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700171}
172
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700173static void warn_overflow(int size, int64_t data)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700174{
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700175 if (size < 8) {
Charles Craynedd462c82007-11-04 15:28:30 -0800176 int64_t lim = ((int64_t)1 << (size*8))-1;
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000177
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700178 if (data < ~lim || data > lim)
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700179 errfunc(ERR_WARNING | ERR_WARN_NOV,
180 "%s data exceeds bounds", size_name(size));
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700181 }
182}
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000183/*
184 * This routine wrappers the real output format's output routine,
185 * in order to pass a copy of the data off to the listing file
186 * generator at the same time.
187 */
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800188static void out(int64_t offset, int32_t segto, const void *data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800189 enum out_type type, uint64_t size,
190 int32_t segment, int32_t wrt)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000191{
Keith Kaniosb7a89542007-04-12 02:40:54 +0000192 static int32_t lineno = 0; /* static!!! */
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000193 static char *lnfname = NULL;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800194 uint8_t p[8];
H. Peter Anvineba20a72002-04-30 20:53:55 +0000195
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800196 if (type == OUT_ADDRESS && segment == NO_SEG && wrt == NO_SEG) {
197 /*
198 * This is a non-relocated address, and we're going to
199 * convert it into RAWDATA format.
200 */
201 uint8_t *q = p;
H. Peter Anvind1fb15c2007-11-13 09:37:59 -0800202
203 if (size > 8) {
204 errfunc(ERR_PANIC, "OUT_ADDRESS with size > 8");
205 return;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800206 }
H. Peter Anvind85d2502008-05-04 17:53:31 -0700207
H. Peter Anvind1fb15c2007-11-13 09:37:59 -0800208 WRITEADDR(q, *(int64_t *)data, size);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800209 data = p;
210 type = OUT_RAWDATA;
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000211 }
212
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800213 list->output(offset, data, type, size);
214
Frank Kotlerabebb082003-09-06 04:45:37 +0000215 /*
216 * this call to src_get determines when we call the
217 * debug-format-specific "linenum" function
218 * it updates lineno and lnfname to the current values
219 * returning 0 if "same as last time", -2 if lnfname
220 * changed, and the amount by which lineno changed,
221 * if it did. thus, these variables must be static
222 */
223
H. Peter Anvine2c80182005-01-15 22:15:51 +0000224 if (src_get(&lineno, &lnfname)) {
225 outfmt->current_dfmt->linenum(lnfname, lineno, segto);
H. Peter Anvince616072002-04-30 21:02:23 +0000226 }
H. Peter Anvineba20a72002-04-30 20:53:55 +0000227
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800228 outfmt->output(segto, data, type, size, segment, wrt);
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000229}
230
Charles Crayne5fbbc8c2007-11-07 19:03:46 -0800231static int jmp_match(int32_t segment, int64_t offset, int bits,
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000232 insn * ins, const char *code)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000233{
Charles Crayne5fbbc8c2007-11-07 19:03:46 -0800234 int64_t isize;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000235 uint8_t c = code[0];
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000236
H. Peter Anvine2c80182005-01-15 22:15:51 +0000237 if (c != 0370 && c != 0371)
238 return 0;
H. Peter Anvin788e6c12002-04-30 21:02:01 +0000239 if (ins->oprs[0].opflags & OPFLAG_FORWARD) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000240 if ((optimizing < 0 || (ins->oprs[0].type & STRICT))
241 && c == 0370)
242 return 1;
243 else
244 return (pass0 == 0); /* match a forward reference */
H. Peter Anvin788e6c12002-04-30 21:02:01 +0000245 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000246 isize = calcsize(segment, offset, bits, ins, code);
247 if (ins->oprs[0].segment != segment)
248 return 0;
249 isize = ins->oprs[0].offset - offset - isize; /* isize is now the delta */
250 if (isize >= -128L && isize <= 127L)
251 return 1; /* it is byte size */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000252
253 return 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000254}
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000255
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800256int64_t assemble(int32_t segment, int64_t offset, int bits, uint32_t cp,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000257 insn * instruction, struct ofmt *output, efunc error,
258 ListGen * listgen)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000259{
H. Peter Anvin3360d792007-09-11 04:16:57 +0000260 const struct itemplate *temp;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000261 int j;
262 int size_prob;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800263 int64_t insn_end;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000264 int32_t itimes;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800265 int64_t start = offset;
266 int64_t wsize = 0; /* size for DB etc. */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000267
H. Peter Anvine2c80182005-01-15 22:15:51 +0000268 errfunc = error; /* to pass to other functions */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000269 cpu = cp;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000270 outfmt = output; /* likewise */
271 list = listgen; /* and again */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000272
H. Peter Anvine2c80182005-01-15 22:15:51 +0000273 switch (instruction->opcode) {
274 case -1:
275 return 0;
276 case I_DB:
277 wsize = 1;
278 break;
279 case I_DW:
280 wsize = 2;
281 break;
282 case I_DD:
283 wsize = 4;
284 break;
285 case I_DQ:
286 wsize = 8;
287 break;
288 case I_DT:
289 wsize = 10;
290 break;
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700291 case I_DO:
292 wsize = 16;
293 break;
H. Peter Anvin16b0a332007-09-12 20:27:41 -0700294 default:
295 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000296 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000297
H. Peter Anvineba20a72002-04-30 20:53:55 +0000298 if (wsize) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000299 extop *e;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000300 int32_t t = instruction->times;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000301 if (t < 0)
302 errfunc(ERR_PANIC,
303 "instruction->times < 0 (%ld) in assemble()", t);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000304
H. Peter Anvine2c80182005-01-15 22:15:51 +0000305 while (t--) { /* repeat TIMES times */
306 for (e = instruction->eops; e; e = e->next) {
307 if (e->type == EOT_DB_NUMBER) {
308 if (wsize == 1) {
309 if (e->segment != NO_SEG)
310 errfunc(ERR_NONFATAL,
311 "one-byte relocation attempted");
312 else {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000313 uint8_t out_byte = e->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000314 out(offset, segment, &out_byte,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800315 OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000316 }
Keith Kanios61ff53c2007-04-14 18:54:52 +0000317 } else if (wsize > 8) {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700318 errfunc(ERR_NONFATAL, "integer supplied to a DT or DO"
Keith Kanios61ff53c2007-04-14 18:54:52 +0000319 " instruction");
H. Peter Anvine2c80182005-01-15 22:15:51 +0000320 } else
321 out(offset, segment, &e->offset,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800322 OUT_ADDRESS, wsize, e->segment, e->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000323 offset += wsize;
324 } else if (e->type == EOT_DB_STRING) {
325 int align;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000326
H. Peter Anvine2c80182005-01-15 22:15:51 +0000327 out(offset, segment, e->stringval,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800328 OUT_RAWDATA, e->stringlen, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000329 align = e->stringlen % wsize;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000330
H. Peter Anvine2c80182005-01-15 22:15:51 +0000331 if (align) {
332 align = wsize - align;
H. Peter Anvind387b8c2008-01-27 16:39:26 -0800333 out(offset, segment,
334 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0",
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800335 OUT_RAWDATA, align, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000336 }
337 offset += e->stringlen + align;
338 }
339 }
340 if (t > 0 && t == instruction->times - 1) {
341 /*
342 * Dummy call to list->output to give the offset to the
343 * listing module.
344 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800345 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000346 list->uplevel(LIST_TIMES);
347 }
348 }
349 if (instruction->times > 1)
350 list->downlevel(LIST_TIMES);
351 return offset - start;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000352 }
353
H. Peter Anvine2c80182005-01-15 22:15:51 +0000354 if (instruction->opcode == I_INCBIN) {
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000355 static char fname[FILENAME_MAX];
H. Peter Anvine2c80182005-01-15 22:15:51 +0000356 FILE *fp;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000357 int32_t len;
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000358 char *prefix = "", *combine;
359 char **pPrevPath = NULL;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000360
H. Peter Anvine2c80182005-01-15 22:15:51 +0000361 len = FILENAME_MAX - 1;
362 if (len > instruction->eops->stringlen)
363 len = instruction->eops->stringlen;
364 strncpy(fname, instruction->eops->stringval, len);
365 fname[len] = '\0';
H. Peter Anvineba20a72002-04-30 20:53:55 +0000366
Keith Kaniosb7a89542007-04-12 02:40:54 +0000367 while (1) { /* added by alexfru: 'incbin' uses include paths */
H. Peter Anvine2c80182005-01-15 22:15:51 +0000368 combine = nasm_malloc(strlen(prefix) + len + 1);
369 strcpy(combine, prefix);
370 strcat(combine, fname);
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000371
H. Peter Anvine2c80182005-01-15 22:15:51 +0000372 if ((fp = fopen(combine, "rb")) != NULL) {
373 nasm_free(combine);
374 break;
375 }
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000376
H. Peter Anvine2c80182005-01-15 22:15:51 +0000377 nasm_free(combine);
378 pPrevPath = pp_get_include_path_ptr(pPrevPath);
379 if (pPrevPath == NULL)
380 break;
381 prefix = *pPrevPath;
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000382 }
383
384 if (fp == NULL)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000385 error(ERR_NONFATAL, "`incbin': unable to open file `%s'",
386 fname);
387 else if (fseek(fp, 0L, SEEK_END) < 0)
388 error(ERR_NONFATAL, "`incbin': unable to seek on file `%s'",
389 fname);
390 else {
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000391 static char buf[2048];
Keith Kaniosb7a89542007-04-12 02:40:54 +0000392 int32_t t = instruction->times;
393 int32_t base = 0;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000394
H. Peter Anvine2c80182005-01-15 22:15:51 +0000395 len = ftell(fp);
396 if (instruction->eops->next) {
397 base = instruction->eops->next->offset;
398 len -= base;
399 if (instruction->eops->next->next &&
400 len > instruction->eops->next->next->offset)
401 len = instruction->eops->next->next->offset;
402 }
403 /*
404 * Dummy call to list->output to give the offset to the
405 * listing module.
406 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800407 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000408 list->uplevel(LIST_INCBIN);
409 while (t--) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000410 int32_t l;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000411
H. Peter Anvine2c80182005-01-15 22:15:51 +0000412 fseek(fp, base, SEEK_SET);
413 l = len;
414 while (l > 0) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000415 int32_t m =
Charles Crayne192d5b52007-10-18 19:02:42 -0700416 fread(buf, 1, (l > (int32_t) sizeof(buf) ? (int32_t) sizeof(buf) : l),
H. Peter Anvine2c80182005-01-15 22:15:51 +0000417 fp);
418 if (!m) {
419 /*
420 * This shouldn't happen unless the file
421 * actually changes while we are reading
422 * it.
423 */
424 error(ERR_NONFATAL,
425 "`incbin': unexpected EOF while"
426 " reading file `%s'", fname);
427 t = 0; /* Try to exit cleanly */
428 break;
429 }
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800430 out(offset, segment, buf, OUT_RAWDATA, m,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000431 NO_SEG, NO_SEG);
432 l -= m;
433 }
434 }
435 list->downlevel(LIST_INCBIN);
436 if (instruction->times > 1) {
437 /*
438 * Dummy call to list->output to give the offset to the
439 * listing module.
440 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800441 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000442 list->uplevel(LIST_TIMES);
443 list->downlevel(LIST_TIMES);
444 }
445 fclose(fp);
446 return instruction->times * len;
447 }
448 return 0; /* if we're here, there's an error */
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000449 }
450
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700451 /* Check to see if we need an address-size prefix */
452 add_asp(instruction, bits);
453
H. Peter Anvin6867acc2007-10-10 14:58:45 -0700454 size_prob = false;
H. Peter Anvin70653092007-10-19 14:42:29 -0700455
456 for (temp = nasm_instructions[instruction->opcode]; temp->opcode != -1; temp++){
Keith Kaniosb7a89542007-04-12 02:40:54 +0000457 int m = matches(temp, instruction, bits);
H. Peter Anvin70653092007-10-19 14:42:29 -0700458
H. Peter Anvine2c80182005-01-15 22:15:51 +0000459 if (m == 99)
460 m += jmp_match(segment, offset, bits, instruction, temp->code);
H. Peter Anvineba20a72002-04-30 20:53:55 +0000461
H. Peter Anvine2c80182005-01-15 22:15:51 +0000462 if (m == 100) { /* matches! */
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000463 const char *codes = temp->code;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800464 int64_t insn_size = calcsize(segment, offset, bits,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000465 instruction, codes);
466 itimes = instruction->times;
467 if (insn_size < 0) /* shouldn't be, on pass two */
468 error(ERR_PANIC, "errors made it through from pass one");
469 else
470 while (itimes--) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700471 for (j = 0; j < MAXPREFIX; j++) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000472 uint8_t c = 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000473 switch (instruction->prefixes[j]) {
474 case P_LOCK:
475 c = 0xF0;
476 break;
477 case P_REPNE:
478 case P_REPNZ:
479 c = 0xF2;
480 break;
481 case P_REPE:
482 case P_REPZ:
483 case P_REP:
484 c = 0xF3;
485 break;
486 case R_CS:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000487 if (bits == 64) {
488 error(ERR_WARNING,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800489 "cs segment base generated, but will be ignored in 64-bit mode");
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000490 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000491 c = 0x2E;
492 break;
493 case R_DS:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000494 if (bits == 64) {
495 error(ERR_WARNING,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800496 "ds segment base generated, but will be ignored in 64-bit mode");
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000497 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000498 c = 0x3E;
499 break;
500 case R_ES:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000501 if (bits == 64) {
502 error(ERR_WARNING,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800503 "es segment base generated, but will be ignored in 64-bit mode");
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000504 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000505 c = 0x26;
506 break;
507 case R_FS:
508 c = 0x64;
509 break;
510 case R_GS:
511 c = 0x65;
512 break;
513 case R_SS:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000514 if (bits == 64) {
515 error(ERR_WARNING,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800516 "ss segment base generated, but will be ignored in 64-bit mode");
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000517 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000518 c = 0x36;
519 break;
520 case R_SEGR6:
521 case R_SEGR7:
522 error(ERR_NONFATAL,
523 "segr6 and segr7 cannot be used as prefixes");
524 break;
525 case P_A16:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000526 if (bits == 64) {
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000527 error(ERR_NONFATAL,
528 "16-bit addressing is not supported "
529 "in 64-bit mode");
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700530 } else if (bits != 16)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000531 c = 0x67;
532 break;
533 case P_A32:
534 if (bits != 32)
535 c = 0x67;
536 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700537 case P_A64:
538 if (bits != 64) {
539 error(ERR_NONFATAL,
540 "64-bit addressing is only supported "
541 "in 64-bit mode");
542 }
543 break;
544 case P_ASP:
545 c = 0x67;
546 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000547 case P_O16:
548 if (bits != 16)
549 c = 0x66;
550 break;
551 case P_O32:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000552 if (bits == 16)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000553 c = 0x66;
554 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700555 case P_O64:
556 /* REX.W */
557 break;
558 case P_OSP:
559 c = 0x66;
560 break;
561 case P_none:
562 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000563 default:
564 error(ERR_PANIC, "invalid instruction prefix");
565 }
566 if (c != 0) {
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800567 out(offset, segment, &c, OUT_RAWDATA, 1,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000568 NO_SEG, NO_SEG);
569 offset++;
570 }
H. Peter Anvin70653092007-10-19 14:42:29 -0700571 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000572 insn_end = offset + insn_size;
573 gencode(segment, offset, bits, instruction, codes,
574 insn_end);
575 offset += insn_size;
576 if (itimes > 0 && itimes == instruction->times - 1) {
577 /*
578 * Dummy call to list->output to give the offset to the
579 * listing module.
580 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800581 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000582 list->uplevel(LIST_TIMES);
583 }
584 }
585 if (instruction->times > 1)
586 list->downlevel(LIST_TIMES);
587 return offset - start;
588 } else if (m > 0 && m > size_prob) {
589 size_prob = m;
590 }
Keith Kaniosb7a89542007-04-12 02:40:54 +0000591// temp++;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000592 }
H. Peter Anvineba20a72002-04-30 20:53:55 +0000593
H. Peter Anvine2c80182005-01-15 22:15:51 +0000594 if (temp->opcode == -1) { /* didn't match any instruction */
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000595 switch (size_prob) {
596 case 1:
597 error(ERR_NONFATAL, "operation size not specified");
598 break;
599 case 2:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000600 error(ERR_NONFATAL, "mismatch in operand sizes");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000601 break;
602 case 3:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000603 error(ERR_NONFATAL, "no instruction for this cpu level");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000604 break;
605 case 4:
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000606 error(ERR_NONFATAL, "instruction not supported in 64-bit mode");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000607 break;
608 default:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000609 error(ERR_NONFATAL,
610 "invalid combination of opcode and operands");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000611 break;
612 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000613 }
614 return 0;
615}
616
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800617int64_t insn_size(int32_t segment, int64_t offset, int bits, uint32_t cp,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000618 insn * instruction, efunc error)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000619{
H. Peter Anvin3360d792007-09-11 04:16:57 +0000620 const struct itemplate *temp;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000621
H. Peter Anvine2c80182005-01-15 22:15:51 +0000622 errfunc = error; /* to pass to other functions */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000623 cpu = cp;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000624
625 if (instruction->opcode == -1)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000626 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000627
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700628 if (instruction->opcode == I_DB || instruction->opcode == I_DW ||
629 instruction->opcode == I_DD || instruction->opcode == I_DQ ||
630 instruction->opcode == I_DT || instruction->opcode == I_DO) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000631 extop *e;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000632 int32_t isize, osize, wsize = 0; /* placate gcc */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000633
H. Peter Anvine2c80182005-01-15 22:15:51 +0000634 isize = 0;
635 switch (instruction->opcode) {
636 case I_DB:
637 wsize = 1;
638 break;
639 case I_DW:
640 wsize = 2;
641 break;
642 case I_DD:
643 wsize = 4;
644 break;
645 case I_DQ:
646 wsize = 8;
647 break;
648 case I_DT:
649 wsize = 10;
650 break;
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700651 case I_DO:
652 wsize = 16;
653 break;
H. Peter Anvin16b0a332007-09-12 20:27:41 -0700654 default:
655 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000656 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000657
H. Peter Anvine2c80182005-01-15 22:15:51 +0000658 for (e = instruction->eops; e; e = e->next) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000659 int32_t align;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000660
H. Peter Anvine2c80182005-01-15 22:15:51 +0000661 osize = 0;
662 if (e->type == EOT_DB_NUMBER)
663 osize = 1;
664 else if (e->type == EOT_DB_STRING)
665 osize = e->stringlen;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000666
H. Peter Anvine2c80182005-01-15 22:15:51 +0000667 align = (-osize) % wsize;
668 if (align < 0)
669 align += wsize;
670 isize += osize + align;
671 }
672 return isize * instruction->times;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000673 }
674
H. Peter Anvine2c80182005-01-15 22:15:51 +0000675 if (instruction->opcode == I_INCBIN) {
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000676 char fname[FILENAME_MAX];
H. Peter Anvine2c80182005-01-15 22:15:51 +0000677 FILE *fp;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000678 int32_t len;
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000679 char *prefix = "", *combine;
680 char **pPrevPath = NULL;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000681
H. Peter Anvine2c80182005-01-15 22:15:51 +0000682 len = FILENAME_MAX - 1;
683 if (len > instruction->eops->stringlen)
684 len = instruction->eops->stringlen;
685 strncpy(fname, instruction->eops->stringval, len);
686 fname[len] = '\0';
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000687
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700688 /* added by alexfru: 'incbin' uses include paths */
689 while (1) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000690 combine = nasm_malloc(strlen(prefix) + len + 1);
691 strcpy(combine, prefix);
692 strcat(combine, fname);
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000693
H. Peter Anvine2c80182005-01-15 22:15:51 +0000694 if ((fp = fopen(combine, "rb")) != NULL) {
695 nasm_free(combine);
696 break;
697 }
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000698
H. Peter Anvine2c80182005-01-15 22:15:51 +0000699 nasm_free(combine);
700 pPrevPath = pp_get_include_path_ptr(pPrevPath);
701 if (pPrevPath == NULL)
702 break;
703 prefix = *pPrevPath;
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000704 }
705
706 if (fp == NULL)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000707 error(ERR_NONFATAL, "`incbin': unable to open file `%s'",
708 fname);
709 else if (fseek(fp, 0L, SEEK_END) < 0)
710 error(ERR_NONFATAL, "`incbin': unable to seek on file `%s'",
711 fname);
712 else {
713 len = ftell(fp);
714 fclose(fp);
715 if (instruction->eops->next) {
716 len -= instruction->eops->next->offset;
717 if (instruction->eops->next->next &&
718 len > instruction->eops->next->next->offset) {
719 len = instruction->eops->next->next->offset;
720 }
721 }
722 return instruction->times * len;
723 }
724 return 0; /* if we're here, there's an error */
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000725 }
726
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700727 /* Check to see if we need an address-size prefix */
728 add_asp(instruction, bits);
729
Keith Kaniosb7a89542007-04-12 02:40:54 +0000730 for (temp = nasm_instructions[instruction->opcode]; temp->opcode != -1; temp++) {
731 int m = matches(temp, instruction, bits);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000732 if (m == 99)
733 m += jmp_match(segment, offset, bits, instruction, temp->code);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000734
H. Peter Anvine2c80182005-01-15 22:15:51 +0000735 if (m == 100) {
736 /* we've matched an instruction. */
Charles Crayne5fbbc8c2007-11-07 19:03:46 -0800737 int64_t isize;
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000738 const char *codes = temp->code;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000739 int j;
740
741 isize = calcsize(segment, offset, bits, instruction, codes);
742 if (isize < 0)
743 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700744 for (j = 0; j < MAXPREFIX; j++) {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700745 switch (instruction->prefixes[j]) {
746 case P_A16:
747 if (bits != 16)
748 isize++;
749 break;
750 case P_A32:
751 if (bits != 32)
752 isize++;
753 break;
754 case P_O16:
755 if (bits != 16)
756 isize++;
757 break;
758 case P_O32:
759 if (bits == 16)
760 isize++;
761 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700762 case P_A64:
763 case P_O64:
764 case P_none:
765 break;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700766 default:
767 isize++;
768 break;
769 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000770 }
771 return isize * instruction->times;
772 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000773 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000774 return -1; /* didn't match any instruction */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000775}
776
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700777static bool possible_sbyte(insn * ins, int op)
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000778{
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700779 return !(ins->forw_ref && ins->oprs[op].opflags) &&
H. Peter Anvine2c80182005-01-15 22:15:51 +0000780 optimizing >= 0 &&
781 !(ins->oprs[op].type & STRICT) &&
782 ins->oprs[op].wrt == NO_SEG && ins->oprs[op].segment == NO_SEG;
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000783}
784
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700785/* check that opn[op] is a signed byte of size 16 or 32 */
786static bool is_sbyte16(insn * ins, int op)
787{
788 int16_t v;
789
790 if (!possible_sbyte(ins, op))
791 return false;
792
793 v = ins->oprs[op].offset;
794 return v >= -128 && v <= 127;
795}
796
797static bool is_sbyte32(insn * ins, int op)
798{
799 int32_t v;
800
801 if (!possible_sbyte(ins, op))
802 return false;
803
804 v = ins->oprs[op].offset;
805 return v >= -128 && v <= 127;
806}
807
808/* check that opn[op] is a signed byte of size 32; warn if this is not
809 the original value when extended to 64 bits */
810static bool is_sbyte64(insn * ins, int op)
811{
812 int64_t v64;
813 int32_t v32;
814
815 /* dead in the water on forward reference or External */
816 if (!possible_sbyte(ins, op))
817 return false;
818
819 v64 = ins->oprs[op].offset;
820 v32 = (int32_t)v64;
821
822 warn_overflow(32, v64);
823
824 return v32 >= -128 && v32 <= 127;
825}
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800826static int64_t calcsize(int32_t segment, int64_t offset, int bits,
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000827 insn * ins, const char *codes)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000828{
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800829 int64_t length = 0;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000830 uint8_t c;
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000831 int rex_mask = ~0;
H. Peter Anvin839eca22007-10-29 23:12:47 -0700832 struct operand *opx;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000833
H. Peter Anvine3917fc2007-11-01 14:53:32 -0700834 ins->rex = 0; /* Ensure REX is reset */
835
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700836 if (ins->prefixes[PPS_OSIZE] == P_O64)
837 ins->rex |= REX_W;
838
H. Peter Anvine2c80182005-01-15 22:15:51 +0000839 (void)segment; /* Don't warn that this parameter is unused */
840 (void)offset; /* Don't warn that this parameter is unused */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000841
H. Peter Anvin839eca22007-10-29 23:12:47 -0700842 while (*codes) {
843 c = *codes++;
844 opx = &ins->oprs[c & 3];
845 switch (c) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000846 case 01:
847 case 02:
848 case 03:
849 codes += c, length += c;
850 break;
851 case 04:
852 case 05:
853 case 06:
854 case 07:
855 length++;
856 break;
857 case 010:
858 case 011:
859 case 012:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700860 case 013:
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000861 ins->rex |=
H. Peter Anvin839eca22007-10-29 23:12:47 -0700862 op_rexflags(opx, REX_B|REX_H|REX_P|REX_W);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000863 codes++, length++;
864 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000865 case 014:
866 case 015:
867 case 016:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700868 case 017:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000869 length++;
870 break;
871 case 020:
872 case 021:
873 case 022:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700874 case 023:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000875 length++;
876 break;
877 case 024:
878 case 025:
879 case 026:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700880 case 027:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000881 length++;
882 break;
883 case 030:
884 case 031:
885 case 032:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700886 case 033:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000887 length += 2;
888 break;
889 case 034:
890 case 035:
891 case 036:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700892 case 037:
H. Peter Anvin839eca22007-10-29 23:12:47 -0700893 if (opx->type & (BITS16 | BITS32 | BITS64))
894 length += (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000895 else
896 length += (bits == 16) ? 2 : 4;
897 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000898 case 040:
899 case 041:
900 case 042:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700901 case 043:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000902 length += 4;
903 break;
904 case 044:
905 case 045:
906 case 046:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700907 case 047:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700908 length += ins->addr_size >> 3;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000909 break;
910 case 050:
911 case 051:
912 case 052:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700913 case 053:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000914 length++;
915 break;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000916 case 054:
917 case 055:
918 case 056:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700919 case 057:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000920 length += 8; /* MOV reg64/imm */
921 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000922 case 060:
923 case 061:
924 case 062:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700925 case 063:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000926 length += 2;
927 break;
928 case 064:
929 case 065:
930 case 066:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700931 case 067:
H. Peter Anvin839eca22007-10-29 23:12:47 -0700932 if (opx->type & (BITS16 | BITS32 | BITS64))
933 length += (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000934 else
935 length += (bits == 16) ? 2 : 4;
936 break;
937 case 070:
938 case 071:
939 case 072:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700940 case 073:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000941 length += 4;
942 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700943 case 074:
944 case 075:
945 case 076:
946 case 077:
947 length += 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000948 break;
949 case 0140:
950 case 0141:
951 case 0142:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700952 case 0143:
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700953 length += is_sbyte16(ins, c & 3) ? 1 : 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000954 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000955 case 0144:
956 case 0145:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700957 case 0146:
958 case 0147:
H. Peter Anvina30cc072007-11-18 21:55:26 -0800959 codes++;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000960 length++;
961 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700962 case 0150:
963 case 0151:
964 case 0152:
965 case 0153:
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700966 length += is_sbyte32(ins, c & 3) ? 1 : 4;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700967 break;
968 case 0154:
969 case 0155:
970 case 0156:
971 case 0157:
H. Peter Anvina30cc072007-11-18 21:55:26 -0800972 codes++;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700973 length++;
974 break;
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700975 case 0160:
976 case 0161:
977 case 0162:
978 case 0163:
979 length++;
980 ins->rex |= REX_D;
H. Peter Anvind85d2502008-05-04 17:53:31 -0700981 ins->drexdst = regval(opx);
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700982 break;
983 case 0164:
984 case 0165:
985 case 0166:
986 case 0167:
987 length++;
988 ins->rex |= REX_D|REX_OC;
H. Peter Anvind85d2502008-05-04 17:53:31 -0700989 ins->drexdst = regval(opx);
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700990 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700991 case 0170:
992 length++;
993 break;
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700994 case 0171:
995 break;
H. Peter Anvind85d2502008-05-04 17:53:31 -0700996 case 0172:
997 codes++;
998 length++;
999 break;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001000 case 0250:
1001 case 0251:
1002 case 0252:
1003 case 0253:
1004 length += is_sbyte64(ins, c & 3) ? 1 : 4;
1005 break;
H. Peter Anvind85d2502008-05-04 17:53:31 -07001006 case 0260:
1007 case 0261:
1008 case 0262:
1009 case 0263:
1010 length += 2;
1011 ins->rex |= REX_V;
1012 ins->drexdst = regval(opx);
1013 ins->vex_m = *codes++;
1014 ins->vex_wlp = *codes++;
1015 break;
1016 case 0270:
1017 length += 2;
1018 ins->rex |= REX_V;
1019 ins->drexdst = 0;
1020 ins->vex_m = *codes++;
1021 ins->vex_wlp = *codes++;
1022 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001023 case 0300:
1024 case 0301:
H. Peter Anvin70653092007-10-19 14:42:29 -07001025 case 0302:
1026 case 0303:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001027 break;
1028 case 0310:
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07001029 if (bits == 64)
1030 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001031 length += (bits != 16) && !has_prefix(ins, PPS_ASIZE, P_A16);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001032 break;
1033 case 0311:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001034 length += (bits != 32) && !has_prefix(ins, PPS_ASIZE, P_A32);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001035 break;
1036 case 0312:
H. Peter Anvin70653092007-10-19 14:42:29 -07001037 break;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001038 case 0313:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001039 if (bits != 64 || has_prefix(ins, PPS_ASIZE, P_A16) ||
1040 has_prefix(ins, PPS_ASIZE, P_A32))
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07001041 return -1;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001042 break;
H. Peter Anvin23440102007-11-12 21:02:33 -08001043 case 0314:
1044 case 0315:
1045 case 0316:
1046 case 0317:
1047 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001048 case 0320:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001049 length += (bits != 16);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001050 break;
1051 case 0321:
1052 length += (bits == 16);
1053 break;
1054 case 0322:
1055 break;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001056 case 0323:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001057 rex_mask &= ~REX_W;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001058 break;
1059 case 0324:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001060 ins->rex |= REX_W;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001061 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001062 case 0330:
1063 codes++, length++;
1064 break;
1065 case 0331:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001066 break;
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001067 case 0332:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001068 case 0333:
1069 length++;
1070 break;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001071 case 0334:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001072 ins->rex |= REX_L;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001073 break;
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001074 case 0335:
1075 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001076 case 0340:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001077 if (ins->oprs[0].segment != NO_SEG)
1078 errfunc(ERR_NONFATAL, "attempt to reserve non-constant"
1079 " quantity of BSS space");
1080 else
H. Peter Anvin428fd672007-11-15 10:25:52 -08001081 length += ins->oprs[0].offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001082 break;
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001083 case 0364:
1084 case 0365:
1085 break;
Keith Kanios48af1772007-08-17 07:37:52 +00001086 case 0366:
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001087 case 0367:
1088 length++;
1089 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001090 case 0370:
1091 case 0371:
1092 case 0372:
1093 break;
1094 case 0373:
1095 length++;
1096 break;
1097 default: /* can't do it by 'case' statements */
1098 if (c >= 0100 && c <= 0277) { /* it's an EA */
1099 ea ea_data;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001100 int rfield;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001101 int32_t rflags;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001102 ea_data.rex = 0; /* Ensure ea.REX is initially 0 */
H. Peter Anvin70653092007-10-19 14:42:29 -07001103
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001104 if (c <= 0177) {
1105 /* pick rfield from operand b */
1106 rflags = regflag(&ins->oprs[c & 7]);
1107 rfield = regvals[ins->oprs[c & 7].basereg];
1108 } else {
1109 rflags = 0;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001110 rfield = c & 7;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001111 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00001112
H. Peter Anvine2c80182005-01-15 22:15:51 +00001113 if (!process_ea
Keith Kaniosb7a89542007-04-12 02:40:54 +00001114 (&ins->oprs[(c >> 3) & 7], &ea_data, bits,
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001115 ins->addr_size, rfield, rflags, ins->forw_ref)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001116 errfunc(ERR_NONFATAL, "invalid effective address");
1117 return -1;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001118 } else {
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001119 ins->rex |= ea_data.rex;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001120 length += ea_data.size;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001121 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001122 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001123 errfunc(ERR_PANIC, "internal instruction table corrupt"
1124 ": instruction code 0x%02X given", c);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001125 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001126 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001127 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001128
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001129 ins->rex &= rex_mask;
H. Peter Anvin70653092007-10-19 14:42:29 -07001130
H. Peter Anvind85d2502008-05-04 17:53:31 -07001131 if (ins->rex & REX_V) {
1132 int bad32 = REX_R|REX_W|REX_X|REX_B;
1133
1134 if (ins->rex & REX_H) {
1135 errfunc(ERR_NONFATAL, "cannot use high register in vex instruction");
1136 return -1;
1137 }
1138 switch (ins->vex_wlp & 030) {
1139 case 000:
1140 ins->rex &= ~REX_W;
1141 break;
1142 case 010:
1143 ins->rex |= REX_W;
1144 bad32 &= ~REX_W;
1145 break;
1146 default:
1147 /* Follow REX_W */
1148 break;
1149 }
1150
1151 if (bits != 64 && ((ins->rex & bad32) || ins->drexdst > 7)) {
1152 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1153 return -1;
1154 }
1155 if (ins->vex_m != 1 || (ins->rex & (REX_W|REX_R|REX_B)))
1156 length += 3;
1157 else
1158 length += 2;
1159 } else if (ins->rex & REX_D) {
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001160 if (ins->rex & REX_H) {
1161 errfunc(ERR_NONFATAL, "cannot use high register in drex instruction");
1162 return -1;
1163 }
H. Peter Anvind85d2502008-05-04 17:53:31 -07001164 if (bits != 64 && ((ins->rex & (REX_R|REX_W|REX_X|REX_B)) ||
H. Peter Anvincf5180a2007-09-17 17:25:27 -07001165 ins->drexdst > 7)) {
1166 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1167 return -1;
1168 }
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001169 length++;
1170 } else if (ins->rex & REX_REAL) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001171 if (ins->rex & REX_H) {
1172 errfunc(ERR_NONFATAL, "cannot use high register in rex instruction");
1173 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001174 } else if (bits == 64) {
1175 length++;
1176 } else if ((ins->rex & REX_L) &&
1177 !(ins->rex & (REX_P|REX_W|REX_X|REX_B)) &&
1178 cpu >= IF_X86_64) {
1179 /* LOCK-as-REX.R */
1180 assert_no_prefix(ins, PPS_LREP);
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001181 length++;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001182 } else {
H. Peter Anvincf5180a2007-09-17 17:25:27 -07001183 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1184 return -1;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001185 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00001186 }
1187
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001188 return length;
1189}
Keith Kaniosb7a89542007-04-12 02:40:54 +00001190
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001191#define EMIT_REX() \
H. Peter Anvind85d2502008-05-04 17:53:31 -07001192 if (!(ins->rex & (REX_D|REX_V)) && (ins->rex & REX_REAL) && (bits == 64)) { \
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001193 ins->rex = (ins->rex & REX_REAL)|REX_P; \
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001194 out(offset, segment, &ins->rex, OUT_RAWDATA, 1, NO_SEG, NO_SEG); \
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001195 ins->rex = 0; \
1196 offset += 1; \
1197 }
1198
Charles Crayne1f8bc4c2007-11-06 18:27:23 -08001199static void gencode(int32_t segment, int64_t offset, int bits,
1200 insn * ins, const char *codes, int64_t insn_end)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001201{
Keith Kaniosa6dfa782007-04-13 16:47:53 +00001202 static char condval[] = { /* conditional opcodes */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001203 0x7, 0x3, 0x2, 0x6, 0x2, 0x4, 0xF, 0xD, 0xC, 0xE, 0x6, 0x2,
1204 0x3, 0x7, 0x3, 0x5, 0xE, 0xC, 0xD, 0xF, 0x1, 0xB, 0x9, 0x5,
1205 0x0, 0xA, 0xA, 0xB, 0x8, 0x4
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001206 };
Keith Kaniosb7a89542007-04-12 02:40:54 +00001207 uint8_t c;
1208 uint8_t bytes[4];
Charles Crayne1f8bc4c2007-11-06 18:27:23 -08001209 int64_t size;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001210 int64_t data;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001211 struct operand *opx;
H. Peter Anvin70653092007-10-19 14:42:29 -07001212
H. Peter Anvin839eca22007-10-29 23:12:47 -07001213 while (*codes) {
1214 c = *codes++;
1215 opx = &ins->oprs[c & 3];
1216 switch (c) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001217 case 01:
1218 case 02:
1219 case 03:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001220 EMIT_REX();
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001221 out(offset, segment, codes, OUT_RAWDATA, c, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001222 codes += c;
1223 offset += c;
1224 break;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001225
H. Peter Anvine2c80182005-01-15 22:15:51 +00001226 case 04:
1227 case 06:
1228 switch (ins->oprs[0].basereg) {
1229 case R_CS:
1230 bytes[0] = 0x0E + (c == 0x04 ? 1 : 0);
1231 break;
1232 case R_DS:
1233 bytes[0] = 0x1E + (c == 0x04 ? 1 : 0);
1234 break;
1235 case R_ES:
1236 bytes[0] = 0x06 + (c == 0x04 ? 1 : 0);
1237 break;
1238 case R_SS:
1239 bytes[0] = 0x16 + (c == 0x04 ? 1 : 0);
1240 break;
1241 default:
1242 errfunc(ERR_PANIC,
1243 "bizarre 8086 segment register received");
1244 }
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001245 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001246 offset++;
1247 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001248
H. Peter Anvine2c80182005-01-15 22:15:51 +00001249 case 05:
1250 case 07:
1251 switch (ins->oprs[0].basereg) {
1252 case R_FS:
1253 bytes[0] = 0xA0 + (c == 0x05 ? 1 : 0);
1254 break;
1255 case R_GS:
1256 bytes[0] = 0xA8 + (c == 0x05 ? 1 : 0);
1257 break;
1258 default:
1259 errfunc(ERR_PANIC,
1260 "bizarre 386 segment register received");
1261 }
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001262 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001263 offset++;
1264 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001265
H. Peter Anvine2c80182005-01-15 22:15:51 +00001266 case 010:
1267 case 011:
1268 case 012:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001269 case 013:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001270 EMIT_REX();
H. Peter Anvin839eca22007-10-29 23:12:47 -07001271 bytes[0] = *codes++ + ((regval(opx)) & 7);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001272 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001273 offset += 1;
1274 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001275
H. Peter Anvine2c80182005-01-15 22:15:51 +00001276 case 014:
1277 case 015:
1278 case 016:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001279 case 017:
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001280 /* XXX: warns for legitimate optimizer actions */
H. Peter Anvin839eca22007-10-29 23:12:47 -07001281 if (opx->offset < -128 || opx->offset > 127) {
H. Peter Anvin72c64372008-01-08 22:13:48 -08001282 errfunc(ERR_WARNING | ERR_WARN_NOV,
1283 "signed byte value exceeds bounds");
H. Peter Anvine2c80182005-01-15 22:15:51 +00001284 }
H. Peter Anvineba20a72002-04-30 20:53:55 +00001285
H. Peter Anvin839eca22007-10-29 23:12:47 -07001286 if (opx->segment != NO_SEG) {
1287 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001288 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001289 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001290 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001291 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001292 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001293 NO_SEG);
1294 }
1295 offset += 1;
1296 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001297
H. Peter Anvine2c80182005-01-15 22:15:51 +00001298 case 020:
1299 case 021:
1300 case 022:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001301 case 023:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001302 if (opx->offset < -256 || opx->offset > 255) {
H. Peter Anvin72c64372008-01-08 22:13:48 -08001303 errfunc(ERR_WARNING | ERR_WARN_NOV,
1304 "byte value exceeds bounds");
H. Peter Anvine2c80182005-01-15 22:15:51 +00001305 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001306 if (opx->segment != NO_SEG) {
1307 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001308 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001309 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001310 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001311 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001312 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001313 NO_SEG);
1314 }
1315 offset += 1;
1316 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001317
H. Peter Anvine2c80182005-01-15 22:15:51 +00001318 case 024:
1319 case 025:
1320 case 026:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001321 case 027:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001322 if (opx->offset < 0 || opx->offset > 255)
H. Peter Anvin72c64372008-01-08 22:13:48 -08001323 errfunc(ERR_WARNING | ERR_WARN_NOV,
1324 "unsigned byte value exceeds bounds");
H. Peter Anvin839eca22007-10-29 23:12:47 -07001325 if (opx->segment != NO_SEG) {
1326 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001327 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001328 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001329 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001330 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001331 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001332 NO_SEG);
1333 }
1334 offset += 1;
1335 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001336
H. Peter Anvine2c80182005-01-15 22:15:51 +00001337 case 030:
1338 case 031:
1339 case 032:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001340 case 033:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001341 data = opx->offset;
1342 if (opx->segment == NO_SEG && opx->wrt == NO_SEG)
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001343 warn_overflow(2, data);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001344 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001345 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001346 offset += 2;
1347 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001348
H. Peter Anvine2c80182005-01-15 22:15:51 +00001349 case 034:
1350 case 035:
1351 case 036:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001352 case 037:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001353 if (opx->type & (BITS16 | BITS32))
1354 size = (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001355 else
1356 size = (bits == 16) ? 2 : 4;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001357 data = opx->offset;
1358 if (opx->segment == NO_SEG && opx->wrt == NO_SEG)
H. Peter Anvin10e27272007-10-29 22:56:08 -07001359 warn_overflow(size, data);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001360 out(offset, segment, &data, OUT_ADDRESS, size,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001361 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001362 offset += size;
1363 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001364
H. Peter Anvine2c80182005-01-15 22:15:51 +00001365 case 040:
1366 case 041:
1367 case 042:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001368 case 043:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001369 data = opx->offset;
H. Peter Anvin72c64372008-01-08 22:13:48 -08001370 if (opx->segment == NO_SEG && opx->wrt == NO_SEG)
1371 warn_overflow(4, data);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001372 out(offset, segment, &data, OUT_ADDRESS, 4,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001373 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001374 offset += 4;
1375 break;
H. Peter Anvin3ba46772002-05-27 23:19:35 +00001376
H. Peter Anvine2c80182005-01-15 22:15:51 +00001377 case 044:
1378 case 045:
1379 case 046:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001380 case 047:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001381 data = opx->offset;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001382 size = ins->addr_size >> 3;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001383 if (opx->segment == NO_SEG &&
1384 opx->wrt == NO_SEG)
H. Peter Anvin10e27272007-10-29 22:56:08 -07001385 warn_overflow(size, data);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001386 out(offset, segment, &data, OUT_ADDRESS, size,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001387 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001388 offset += size;
1389 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001390
H. Peter Anvine2c80182005-01-15 22:15:51 +00001391 case 050:
1392 case 051:
1393 case 052:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001394 case 053:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001395 if (opx->segment != segment)
H. Peter Anvine2c80182005-01-15 22:15:51 +00001396 errfunc(ERR_NONFATAL,
1397 "short relative jump outside segment");
H. Peter Anvin839eca22007-10-29 23:12:47 -07001398 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001399 if (data > 127 || data < -128)
1400 errfunc(ERR_NONFATAL, "short jump is out of range");
1401 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001402 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001403 offset += 1;
1404 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001405
Keith Kaniosb7a89542007-04-12 02:40:54 +00001406 case 054:
1407 case 055:
1408 case 056:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001409 case 057:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001410 data = (int64_t)opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001411 out(offset, segment, &data, OUT_ADDRESS, 8,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001412 opx->segment, opx->wrt);
Keith Kaniosb7a89542007-04-12 02:40:54 +00001413 offset += 8;
1414 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001415
H. Peter Anvine2c80182005-01-15 22:15:51 +00001416 case 060:
1417 case 061:
1418 case 062:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001419 case 063:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001420 if (opx->segment != segment) {
1421 data = opx->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001422 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001423 OUT_REL2ADR, insn_end - offset,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001424 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001425 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001426 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001427 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001428 OUT_ADDRESS, 2, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001429 }
1430 offset += 2;
1431 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001432
H. Peter Anvine2c80182005-01-15 22:15:51 +00001433 case 064:
1434 case 065:
1435 case 066:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001436 case 067:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001437 if (opx->type & (BITS16 | BITS32 | BITS64))
1438 size = (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001439 else
1440 size = (bits == 16) ? 2 : 4;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001441 if (opx->segment != segment) {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001442 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001443 out(offset, segment, &data,
1444 size == 2 ? OUT_REL2ADR : OUT_REL4ADR,
1445 insn_end - offset, opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001446 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001447 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001448 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001449 OUT_ADDRESS, size, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001450 }
1451 offset += size;
1452 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001453
H. Peter Anvine2c80182005-01-15 22:15:51 +00001454 case 070:
1455 case 071:
1456 case 072:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001457 case 073:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001458 if (opx->segment != segment) {
1459 data = opx->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001460 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001461 OUT_REL4ADR, insn_end - offset,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001462 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001463 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001464 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001465 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001466 OUT_ADDRESS, 4, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001467 }
1468 offset += 4;
1469 break;
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001470
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001471 case 074:
1472 case 075:
1473 case 076:
1474 case 077:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001475 if (opx->segment == NO_SEG)
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001476 errfunc(ERR_NONFATAL, "value referenced by FAR is not"
1477 " relocatable");
1478 data = 0L;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001479 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001480 outfmt->segbase(1 + opx->segment),
1481 opx->wrt);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001482 offset += 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001483 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001484
H. Peter Anvine2c80182005-01-15 22:15:51 +00001485 case 0140:
1486 case 0141:
1487 case 0142:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001488 case 0143:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001489 data = opx->offset;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001490 if (is_sbyte16(ins, c & 3)) {
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001491 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001492 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001493 NO_SEG);
1494 offset++;
1495 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001496 if (opx->segment == NO_SEG &&
1497 opx->wrt == NO_SEG)
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001498 warn_overflow(2, data);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001499 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001500 opx->segment, opx->wrt);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001501 offset += 2;
1502 }
1503 break;
1504
1505 case 0144:
1506 case 0145:
1507 case 0146:
1508 case 0147:
1509 EMIT_REX();
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001510 bytes[0] = *codes++;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001511 if (is_sbyte16(ins, c & 3))
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001512 bytes[0] |= 2; /* s-bit */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001513 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001514 offset++;
1515 break;
1516
1517 case 0150:
1518 case 0151:
1519 case 0152:
1520 case 0153:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001521 data = opx->offset;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001522 if (is_sbyte32(ins, c & 3)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001523 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001524 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001525 NO_SEG);
1526 offset++;
1527 } else {
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001528 out(offset, segment, &data, OUT_ADDRESS, 4,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001529 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001530 offset += 4;
1531 }
1532 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001533
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001534 case 0154:
1535 case 0155:
1536 case 0156:
1537 case 0157:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001538 EMIT_REX();
H. Peter Anvine2c80182005-01-15 22:15:51 +00001539 bytes[0] = *codes++;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001540 if (is_sbyte32(ins, c & 3))
H. Peter Anvine2c80182005-01-15 22:15:51 +00001541 bytes[0] |= 2; /* s-bit */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001542 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001543 offset++;
1544 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001545
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001546 case 0160:
1547 case 0161:
1548 case 0162:
1549 case 0163:
1550 case 0164:
1551 case 0165:
1552 case 0166:
1553 case 0167:
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001554 break;
1555
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001556 case 0170:
H. Peter Anvinc189b442007-10-05 17:04:32 -07001557 EMIT_REX();
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001558 bytes[0] = 0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001559 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001560 offset += 1;
1561 break;
1562
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001563 case 0171:
1564 bytes[0] =
1565 (ins->drexdst << 4) |
1566 (ins->rex & REX_OC ? 0x08 : 0) |
1567 (ins->rex & (REX_R|REX_X|REX_B));
1568 ins->rex = 0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001569 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001570 offset++;
1571 break;
1572
H. Peter Anvind85d2502008-05-04 17:53:31 -07001573 case 0172:
1574 c = *codes++;
1575 opx = &ins->oprs[c >> 3];
1576 bytes[0] = regvals[opx->basereg] << 4;
1577 opx = &ins->oprs[c & 7];
1578 if (opx->segment != NO_SEG || opx->wrt != NO_SEG) {
1579 errfunc(ERR_NONFATAL,
1580 "non-absolute expression not permitted as argument %d",
1581 c & 7);
1582 } else {
1583 if (opx->offset & ~15) {
1584 errfunc(ERR_WARNING | ERR_WARN_NOV,
1585 "four-bit argument exceeds bounds");
1586 }
1587 bytes[0] |= opx->offset & 15;
1588 }
1589 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1590 offset++;
1591 break;
1592
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001593 case 0250:
1594 case 0251:
1595 case 0252:
1596 case 0253:
1597 data = opx->offset;
1598 /* is_sbyte32() is right here, we have already warned */
1599 if (is_sbyte32(ins, c & 3)) {
1600 bytes[0] = data;
1601 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
1602 NO_SEG);
1603 offset++;
1604 } else {
1605 out(offset, segment, &data, OUT_ADDRESS, 4,
1606 opx->segment, opx->wrt);
1607 offset += 4;
1608 }
1609 break;
1610
H. Peter Anvind85d2502008-05-04 17:53:31 -07001611 case 0260:
1612 case 0261:
1613 case 0262:
1614 case 0263:
1615 case 0270:
1616 codes += 2;
1617 if (ins->vex_m != 1 || (ins->rex & (REX_W|REX_X|REX_B))) {
1618 bytes[0] = 0xc4;
1619 bytes[1] = ins->vex_m | ((ins->rex & 7) << 5);
1620 bytes[2] = ((ins->rex & REX_W) << (7-3)) |
1621 (ins->drexdst << 3) | (ins->vex_wlp & 07);
1622 out(offset, segment, &bytes, OUT_RAWDATA, 3, NO_SEG, NO_SEG);
1623 offset += 3;
1624 } else {
1625 bytes[0] = 0xc5;
1626 bytes[1] = ((ins->rex & REX_R) << (7-2)) |
1627 (ins->drexdst << 3) | (ins->vex_wlp & 07);
1628 out(offset, segment, &bytes, OUT_RAWDATA, 2, NO_SEG, NO_SEG);
1629 offset += 2;
1630 }
1631 break;
1632
H. Peter Anvine2c80182005-01-15 22:15:51 +00001633 case 0300:
1634 case 0301:
1635 case 0302:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001636 case 0303:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001637 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001638
H. Peter Anvine2c80182005-01-15 22:15:51 +00001639 case 0310:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001640 if (bits == 32 && !has_prefix(ins, PPS_ASIZE, P_A16)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001641 *bytes = 0x67;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001642 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001643 offset += 1;
1644 } else
1645 offset += 0;
1646 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001647
H. Peter Anvine2c80182005-01-15 22:15:51 +00001648 case 0311:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001649 if (bits != 32 && !has_prefix(ins, PPS_ASIZE, P_A32)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001650 *bytes = 0x67;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001651 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001652 offset += 1;
1653 } else
1654 offset += 0;
1655 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001656
H. Peter Anvine2c80182005-01-15 22:15:51 +00001657 case 0312:
1658 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001659
Keith Kaniosb7a89542007-04-12 02:40:54 +00001660 case 0313:
1661 ins->rex = 0;
1662 break;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07001663
H. Peter Anvin23440102007-11-12 21:02:33 -08001664 case 0314:
1665 case 0315:
1666 case 0316:
1667 case 0317:
1668 break;
1669
H. Peter Anvine2c80182005-01-15 22:15:51 +00001670 case 0320:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001671 if (bits != 16) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001672 *bytes = 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001673 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001674 offset += 1;
1675 } else
1676 offset += 0;
1677 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001678
H. Peter Anvine2c80182005-01-15 22:15:51 +00001679 case 0321:
1680 if (bits == 16) {
1681 *bytes = 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001682 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001683 offset += 1;
1684 } else
1685 offset += 0;
1686 break;
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001687
H. Peter Anvine2c80182005-01-15 22:15:51 +00001688 case 0322:
H. Peter Anvin70653092007-10-19 14:42:29 -07001689 case 0323:
1690 break;
1691
Keith Kaniosb7a89542007-04-12 02:40:54 +00001692 case 0324:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001693 ins->rex |= REX_W;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001694 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001695
H. Peter Anvine2c80182005-01-15 22:15:51 +00001696 case 0330:
1697 *bytes = *codes++ ^ condval[ins->condition];
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001698 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001699 offset += 1;
1700 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001701
H. Peter Anvine2c80182005-01-15 22:15:51 +00001702 case 0331:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001703 break;
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001704
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001705 case 0332:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001706 case 0333:
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001707 *bytes = c - 0332 + 0xF2;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001708 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001709 offset += 1;
1710 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001711
Keith Kanios48af1772007-08-17 07:37:52 +00001712 case 0334:
1713 if (ins->rex & REX_R) {
1714 *bytes = 0xF0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001715 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
Keith Kanios48af1772007-08-17 07:37:52 +00001716 offset += 1;
1717 }
1718 ins->rex &= ~(REX_L|REX_R);
1719 break;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001720
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001721 case 0335:
1722 break;
1723
H. Peter Anvine2c80182005-01-15 22:15:51 +00001724 case 0340:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001725 if (ins->oprs[0].segment != NO_SEG)
1726 errfunc(ERR_PANIC, "non-constant BSS size in pass two");
1727 else {
H. Peter Anvin428fd672007-11-15 10:25:52 -08001728 int64_t size = ins->oprs[0].offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001729 if (size > 0)
1730 out(offset, segment, NULL,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001731 OUT_RESERVE, size, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001732 offset += size;
1733 }
1734 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001735
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001736 case 0364:
1737 case 0365:
1738 break;
1739
Keith Kanios48af1772007-08-17 07:37:52 +00001740 case 0366:
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001741 case 0367:
1742 *bytes = c - 0366 + 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001743 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
Keith Kanios48af1772007-08-17 07:37:52 +00001744 offset += 1;
1745 break;
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001746
H. Peter Anvine2c80182005-01-15 22:15:51 +00001747 case 0370:
1748 case 0371:
1749 case 0372:
1750 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001751
H. Peter Anvine2c80182005-01-15 22:15:51 +00001752 case 0373:
1753 *bytes = bits == 16 ? 3 : 5;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001754 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001755 offset += 1;
1756 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001757
H. Peter Anvine2c80182005-01-15 22:15:51 +00001758 default: /* can't do it by 'case' statements */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001759 if (c >= 0100 && c <= 0277) { /* it's an EA */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001760 ea ea_data;
1761 int rfield;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001762 int32_t rflags;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001763 uint8_t *p;
1764 int32_t s;
H. Peter Anvin70653092007-10-19 14:42:29 -07001765
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001766 if (c <= 0177) {
1767 /* pick rfield from operand b */
1768 rflags = regflag(&ins->oprs[c & 7]);
1769 rfield = regvals[ins->oprs[c & 7].basereg];
1770 } else {
1771 /* rfield is constant */
1772 rflags = 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001773 rfield = c & 7;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001774 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001775
1776 if (!process_ea
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001777 (&ins->oprs[(c >> 3) & 7], &ea_data, bits,
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001778 ins->addr_size, rfield, rflags, ins->forw_ref)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001779 errfunc(ERR_NONFATAL, "invalid effective address");
1780 }
H. Peter Anvin70653092007-10-19 14:42:29 -07001781
Charles Crayne7e975552007-11-03 22:06:13 -07001782
H. Peter Anvine2c80182005-01-15 22:15:51 +00001783 p = bytes;
1784 *p++ = ea_data.modrm;
1785 if (ea_data.sib_present)
1786 *p++ = ea_data.sib;
1787
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001788 /* DREX suffixes come between the SIB and the displacement */
1789 if (ins->rex & REX_D) {
1790 *p++ =
1791 (ins->drexdst << 4) |
1792 (ins->rex & REX_OC ? 0x08 : 0) |
1793 (ins->rex & (REX_R|REX_X|REX_B));
1794 ins->rex = 0;
1795 }
1796
H. Peter Anvine2c80182005-01-15 22:15:51 +00001797 s = p - bytes;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001798 out(offset, segment, bytes, OUT_RAWDATA, s, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001799
1800 switch (ea_data.bytes) {
1801 case 0:
1802 break;
1803 case 1:
1804 if (ins->oprs[(c >> 3) & 7].segment != NO_SEG) {
1805 data = ins->oprs[(c >> 3) & 7].offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001806 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001807 ins->oprs[(c >> 3) & 7].segment,
1808 ins->oprs[(c >> 3) & 7].wrt);
1809 } else {
1810 *bytes = ins->oprs[(c >> 3) & 7].offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001811 out(offset, segment, bytes, OUT_RAWDATA, 1,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001812 NO_SEG, NO_SEG);
1813 }
1814 s++;
1815 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001816 case 8:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001817 case 2:
1818 case 4:
1819 data = ins->oprs[(c >> 3) & 7].offset;
Charles Crayne7e975552007-11-03 22:06:13 -07001820 warn_overflow(ea_data.bytes, data);
H. Peter Anvind0b0d282007-09-28 17:17:20 -07001821 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001822 ea_data.rip ? OUT_REL4ADR : OUT_ADDRESS,
1823 ea_data.bytes,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001824 ins->oprs[(c >> 3) & 7].segment,
1825 ins->oprs[(c >> 3) & 7].wrt);
1826 s += ea_data.bytes;
1827 break;
1828 }
1829 offset += s;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001830 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001831 errfunc(ERR_PANIC, "internal instruction table corrupt"
1832 ": instruction code 0x%02X given", c);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001833 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001834 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001835 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001836}
1837
H. Peter Anvin0ec60e62007-07-07 01:59:52 +00001838static int32_t regflag(const operand * o)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001839{
1840 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1841 errfunc(ERR_PANIC, "invalid operand passed to regflag()");
1842 }
1843 return reg_flags[o->basereg];
1844}
1845
H. Peter Anvin5b0e3ec2007-07-07 02:01:08 +00001846static int32_t regval(const operand * o)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001847{
H. Peter Anvine2c80182005-01-15 22:15:51 +00001848 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1849 errfunc(ERR_PANIC, "invalid operand passed to regval()");
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001850 }
H. Peter Anvin232badb2002-06-06 02:41:20 +00001851 return regvals[o->basereg];
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001852}
1853
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001854static int op_rexflags(const operand * o, int mask)
1855{
1856 int32_t flags;
1857 int val;
1858
1859 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1860 errfunc(ERR_PANIC, "invalid operand passed to op_rexflags()");
1861 }
1862
1863 flags = reg_flags[o->basereg];
1864 val = regvals[o->basereg];
1865
1866 return rexflags(val, flags, mask);
1867}
1868
1869static int rexflags(int val, int32_t flags, int mask)
1870{
1871 int rex = 0;
1872
1873 if (val >= 8)
1874 rex |= REX_B|REX_X|REX_R;
1875 if (flags & BITS64)
1876 rex |= REX_W;
1877 if (!(REG_HIGH & ~flags)) /* AH, CH, DH, BH */
1878 rex |= REX_H;
1879 else if (!(REG8 & ~flags) && val >= 4) /* SPL, BPL, SIL, DIL */
1880 rex |= REX_P;
1881
1882 return rex & mask;
1883}
1884
H. Peter Anvin3360d792007-09-11 04:16:57 +00001885static int matches(const struct itemplate *itemp, insn * instruction, int bits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001886{
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001887 int i, size[MAX_OPERANDS], asize, oprs, ret;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001888
1889 ret = 100;
1890
1891 /*
1892 * Check the opcode
1893 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001894 if (itemp->opcode != instruction->opcode)
1895 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001896
1897 /*
1898 * Count the operands
1899 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001900 if (itemp->operands != instruction->operands)
1901 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001902
1903 /*
1904 * Check that no spurious colons or TOs are present
1905 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001906 for (i = 0; i < itemp->operands; i++)
1907 if (instruction->oprs[i].type & ~itemp->opd[i] & (COLON | TO))
1908 return 0;
H. Peter Anvin70653092007-10-19 14:42:29 -07001909
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001910 /*
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001911 * Process size flags
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001912 */
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001913 if (itemp->flags & IF_ARMASK) {
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001914 memset(size, 0, sizeof size);
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001915
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001916 i = ((itemp->flags & IF_ARMASK) >> IF_ARSHFT) - 1;
1917
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001918 switch (itemp->flags & IF_SMASK) {
1919 case IF_SB:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001920 size[i] = BITS8;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001921 break;
1922 case IF_SW:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001923 size[i] = BITS16;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001924 break;
1925 case IF_SD:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001926 size[i] = BITS32;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001927 break;
1928 case IF_SQ:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001929 size[i] = BITS64;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001930 break;
H. Peter Anvin41c9f6f2007-09-18 13:01:32 -07001931 case IF_SO:
1932 size[i] = BITS128;
1933 break;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001934 case IF_SZ:
1935 switch (bits) {
1936 case 16:
1937 size[i] = BITS16;
1938 break;
1939 case 32:
1940 size[i] = BITS32;
1941 break;
1942 case 64:
1943 size[i] = BITS64;
1944 break;
1945 }
1946 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001947 default:
1948 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001949 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001950 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001951 asize = 0;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001952 switch (itemp->flags & IF_SMASK) {
1953 case IF_SB:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001954 asize = BITS8;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001955 break;
1956 case IF_SW:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001957 asize = BITS16;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001958 break;
1959 case IF_SD:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001960 asize = BITS32;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001961 break;
1962 case IF_SQ:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001963 asize = BITS64;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001964 break;
H. Peter Anvin41c9f6f2007-09-18 13:01:32 -07001965 case IF_SO:
1966 asize = BITS128;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001967 break;
1968 case IF_SZ:
1969 switch (bits) {
1970 case 16:
1971 asize = BITS16;
1972 break;
1973 case 32:
1974 asize = BITS32;
1975 break;
1976 case 64:
1977 asize = BITS64;
1978 break;
1979 }
H. Peter Anvin41c9f6f2007-09-18 13:01:32 -07001980 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001981 default:
1982 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001983 }
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001984 for (i = 0; i < MAX_OPERANDS; i++)
1985 size[i] = asize;
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001986 }
H. Peter Anvin70653092007-10-19 14:42:29 -07001987
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001988 /*
1989 * Check that the operand flags all match up
1990 */
1991 for (i = 0; i < itemp->operands; i++) {
1992 int32_t type = instruction->oprs[i].type;
1993 if (!(type & SIZE_MASK))
1994 type |= size[i];
H. Peter Anvind85d2502008-05-04 17:53:31 -07001995
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001996 if (itemp->opd[i] & SAME_AS) {
1997 int j = itemp->opd[i] & ~SAME_AS;
1998 if (type != instruction->oprs[j].type ||
1999 instruction->oprs[i].basereg != instruction->oprs[j].basereg)
2000 return 0;
2001 } else if (itemp->opd[i] & ~type ||
2002 ((itemp->opd[i] & SIZE_MASK) &&
2003 ((itemp->opd[i] ^ type) & SIZE_MASK))) {
2004 if ((itemp->opd[i] & ~type & ~SIZE_MASK) ||
2005 (type & SIZE_MASK))
2006 return 0;
2007 else
2008 return 1;
2009 }
2010 }
2011
2012 /*
2013 * Check operand sizes
2014 */
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002015 if (itemp->flags & (IF_SM | IF_SM2)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002016 oprs = (itemp->flags & IF_SM2 ? 2 : itemp->operands);
2017 asize = 0;
2018 for (i = 0; i < oprs; i++) {
2019 if ((asize = itemp->opd[i] & SIZE_MASK) != 0) {
2020 int j;
2021 for (j = 0; j < oprs; j++)
2022 size[j] = asize;
2023 break;
2024 }
2025 }
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002026 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002027 oprs = itemp->operands;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002028 }
2029
Keith Kaniosb7a89542007-04-12 02:40:54 +00002030 for (i = 0; i < itemp->operands; i++) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002031 if (!(itemp->opd[i] & SIZE_MASK) &&
2032 (instruction->oprs[i].type & SIZE_MASK & ~size[i]))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002033 return 2;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002034 }
2035
H. Peter Anvinaf535c12002-04-30 20:59:21 +00002036 /*
2037 * Check template is okay at the set cpu level
2038 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002039 if (((itemp->flags & IF_PLEVEL) > cpu))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002040 return 3;
H. Peter Anvin70653092007-10-19 14:42:29 -07002041
Keith Kaniosb7a89542007-04-12 02:40:54 +00002042 /*
2043 * Check if instruction is available in long mode
2044 */
2045 if ((itemp->flags & IF_NOLONG) && (bits == 64))
2046 return 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002047
H. Peter Anvinaf535c12002-04-30 20:59:21 +00002048 /*
2049 * Check if special handling needed for Jumps
2050 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002051 if ((uint8_t)(itemp->code[0]) >= 0370)
H. Peter Anvine2c80182005-01-15 22:15:51 +00002052 return 99;
2053
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002054 return ret;
2055}
2056
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002057static ea *process_ea(operand * input, ea * output, int bits,
2058 int addrbits, int rfield, int32_t rflags, int forw_ref)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002059{
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002060 output->rip = false;
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00002061
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002062 /* REX flags for the rfield operand */
2063 output->rex |= rexflags(rfield, rflags, REX_R|REX_P|REX_W|REX_H);
2064
Keith Kaniosb7a89542007-04-12 02:40:54 +00002065 if (!(REGISTER & ~input->type)) { /* register direct */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002066 int i;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002067 int32_t f;
2068
2069 if (input->basereg < EXPR_REG_START /* Verify as Register */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002070 || input->basereg >= REG_ENUM_LIMIT)
H. Peter Anvine2c80182005-01-15 22:15:51 +00002071 return NULL;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002072 f = regflag(input);
Keith Kaniosb7a89542007-04-12 02:40:54 +00002073 i = regvals[input->basereg];
Keith Kaniosb7a89542007-04-12 02:40:54 +00002074
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002075 if (REG_EA & ~f)
2076 return NULL; /* Invalid EA register */
H. Peter Anvin70653092007-10-19 14:42:29 -07002077
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002078 output->rex |= op_rexflags(input, REX_B|REX_P|REX_W|REX_H);
2079
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002080 output->sib_present = false; /* no SIB necessary */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002081 output->bytes = 0; /* no offset necessary either */
2082 output->modrm = 0xC0 | ((rfield & 7) << 3) | (i & 7);
H. Peter Anvine2c80182005-01-15 22:15:51 +00002083 } else { /* it's a memory reference */
2084 if (input->basereg == -1
2085 && (input->indexreg == -1 || input->scale == 0)) {
2086 /* it's a pure offset */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002087 if (bits == 64 && (~input->type & IP_REL)) {
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002088 int scale, index, base;
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002089 output->sib_present = true;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002090 scale = 0;
2091 index = 4;
2092 base = 5;
2093 output->sib = (scale << 6) | (index << 3) | base;
2094 output->bytes = 4;
2095 output->modrm = 4 | ((rfield & 7) << 3);
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002096 output->rip = false;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002097 } else {
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002098 output->sib_present = false;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002099 output->bytes = (addrbits != 16 ? 4 : 2);
2100 output->modrm = (addrbits != 16 ? 5 : 6) | ((rfield & 7) << 3);
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002101 output->rip = bits == 64;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002102 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00002103 } else { /* it's an indirection */
2104 int i = input->indexreg, b = input->basereg, s = input->scale;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002105 int32_t o = input->offset, seg = input->segment;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002106 int hb = input->hintbase, ht = input->hinttype;
2107 int t;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002108 int it, bt;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002109 int32_t ix, bx; /* register flags */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002110
H. Peter Anvine2c80182005-01-15 22:15:51 +00002111 if (s == 0)
2112 i = -1; /* make this easy, at least */
H. Peter Anvin70653092007-10-19 14:42:29 -07002113
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002114 if (i >= EXPR_REG_START && i < REG_ENUM_LIMIT) {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002115 it = regvals[i];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002116 ix = reg_flags[i];
2117 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002118 it = -1;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002119 ix = 0;
2120 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002121
H. Peter Anvinb0c54622007-10-28 23:21:46 -07002122 if (b >= EXPR_REG_START && b < REG_ENUM_LIMIT) {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002123 bt = regvals[b];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002124 bx = reg_flags[b];
2125 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002126 bt = -1;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002127 bx = 0;
2128 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002129
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002130 /* check for a 32/64-bit memory reference... */
2131 if ((ix|bx) & (BITS32|BITS64)) {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002132 /* it must be a 32/64-bit memory reference. Firstly we have
2133 * to check that all registers involved are type E/Rxx. */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002134 int32_t sok = BITS32|BITS64;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002135
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002136 if (it != -1) {
2137 if (!(REG64 & ~ix) || !(REG32 & ~ix))
2138 sok &= ix;
2139 else
2140 return NULL;
2141 }
2142
2143 if (bt != -1) {
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00002144 if (REG_GPR & ~bx)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002145 return NULL; /* Invalid register */
H. Peter Anvina57e8d42007-05-30 03:44:02 +00002146 if (~sok & bx & SIZE_MASK)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002147 return NULL; /* Invalid size */
H. Peter Anvinb0c54622007-10-28 23:21:46 -07002148 sok &= bx;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002149 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002150
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002151 /* While we're here, ensure the user didn't specify
2152 WORD or QWORD. */
2153 if (input->disp_size == 16 || input->disp_size == 64)
2154 return NULL;
2155
2156 if (addrbits == 16 ||
2157 (addrbits == 32 && !(sok & BITS32)) ||
2158 (addrbits == 64 && !(sok & BITS64)))
2159 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002160
Keith Kaniosb7a89542007-04-12 02:40:54 +00002161 /* now reorganize base/index */
2162 if (s == 1 && bt != it && bt != -1 && it != -1 &&
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002163 ((hb == b && ht == EAH_NOTBASE)
2164 || (hb == i && ht == EAH_MAKEBASE))) {
2165 /* swap if hints say so */
2166 t = bt, bt = it, it = t;
2167 t = bx, bx = ix, ix = t;
2168 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00002169 if (bt == it) /* convert EAX+2*EAX to 3*EAX */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002170 bt = -1, bx = 0, s++;
2171 if (bt == -1 && s == 1 && !(hb == it && ht == EAH_NOTBASE)) {
2172 /* make single reg base, unless hint */
2173 bt = it, bx = ix, it = -1, ix = 0;
2174 }
H. Peter Anvinf5843c62007-09-10 18:59:26 +00002175 if (((s == 2 && it != REG_NUM_ESP
H. Peter Anvine2c80182005-01-15 22:15:51 +00002176 && !(input->eaflags & EAF_TIMESTWO)) || s == 3
Keith Kaniosb7a89542007-04-12 02:40:54 +00002177 || s == 5 || s == 9) && bt == -1)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002178 bt = it, bx = ix, s--; /* convert 3*EAX to EAX+2*EAX */
Keith Kanios48af1772007-08-17 07:37:52 +00002179 if (it == -1 && (bt & 7) != REG_NUM_ESP
H. Peter Anvine2c80182005-01-15 22:15:51 +00002180 && (input->eaflags & EAF_TIMESTWO))
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002181 it = bt, ix = bx, bt = -1, bx = 0, s = 1;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002182 /* convert [NOSPLIT EAX] to sib format with 0x0 displacement */
Keith Kanios48af1772007-08-17 07:37:52 +00002183 if (s == 1 && it == REG_NUM_ESP) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002184 /* swap ESP into base if scale is 1 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002185 t = it, it = bt, bt = t;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002186 t = ix, ix = bx, bx = t;
2187 }
Keith Kanios48af1772007-08-17 07:37:52 +00002188 if (it == REG_NUM_ESP
Keith Kaniosb7a89542007-04-12 02:40:54 +00002189 || (s != 1 && s != 2 && s != 4 && s != 8 && it != -1))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002190 return NULL; /* wrong, for various reasons */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002191
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002192 output->rex |= rexflags(it, ix, REX_X);
2193 output->rex |= rexflags(bt, bx, REX_B);
Keith Kaniosb7a89542007-04-12 02:40:54 +00002194
Keith Kanios48af1772007-08-17 07:37:52 +00002195 if (it == -1 && (bt & 7) != REG_NUM_ESP) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002196 /* no SIB needed */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002197 int mod, rm;
H. Peter Anvin70653092007-10-19 14:42:29 -07002198
Keith Kaniosb7a89542007-04-12 02:40:54 +00002199 if (bt == -1) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002200 rm = 5;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002201 mod = 0;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002202 } else {
2203 rm = (bt & 7);
Keith Kanios48af1772007-08-17 07:37:52 +00002204 if (rm != REG_NUM_EBP && o == 0 &&
Keith Kaniosb7a89542007-04-12 02:40:54 +00002205 seg == NO_SEG && !forw_ref &&
2206 !(input->eaflags &
2207 (EAF_BYTEOFFS | EAF_WORDOFFS)))
2208 mod = 0;
2209 else if (input->eaflags & EAF_BYTEOFFS ||
2210 (o >= -128 && o <= 127 && seg == NO_SEG
2211 && !forw_ref
2212 && !(input->eaflags & EAF_WORDOFFS)))
2213 mod = 1;
2214 else
2215 mod = 2;
2216 }
H. Peter Anvinea838272002-04-30 20:51:53 +00002217
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002218 output->sib_present = false;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002219 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2220 output->modrm = (mod << 6) | ((rfield & 7) << 3) | rm;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002221 } else {
2222 /* we need a SIB */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002223 int mod, scale, index, base;
H. Peter Anvin70653092007-10-19 14:42:29 -07002224
Keith Kaniosb7a89542007-04-12 02:40:54 +00002225 if (it == -1)
2226 index = 4, s = 1;
2227 else
2228 index = (it & 7);
H. Peter Anvin70653092007-10-19 14:42:29 -07002229
H. Peter Anvine2c80182005-01-15 22:15:51 +00002230 switch (s) {
2231 case 1:
2232 scale = 0;
2233 break;
2234 case 2:
2235 scale = 1;
2236 break;
2237 case 4:
2238 scale = 2;
2239 break;
2240 case 8:
2241 scale = 3;
2242 break;
2243 default: /* then what the smeg is it? */
2244 return NULL; /* panic */
2245 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002246
Keith Kaniosb7a89542007-04-12 02:40:54 +00002247 if (bt == -1) {
2248 base = 5;
2249 mod = 0;
2250 } else {
2251 base = (bt & 7);
Keith Kanios48af1772007-08-17 07:37:52 +00002252 if (base != REG_NUM_EBP && o == 0 &&
H. Peter Anvine2c80182005-01-15 22:15:51 +00002253 seg == NO_SEG && !forw_ref &&
2254 !(input->eaflags &
Keith Kaniosb7a89542007-04-12 02:40:54 +00002255 (EAF_BYTEOFFS | EAF_WORDOFFS)))
2256 mod = 0;
2257 else if (input->eaflags & EAF_BYTEOFFS ||
2258 (o >= -128 && o <= 127 && seg == NO_SEG
2259 && !forw_ref
2260 && !(input->eaflags & EAF_WORDOFFS)))
2261 mod = 1;
2262 else
2263 mod = 2;
2264 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002265
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002266 output->sib_present = true;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002267 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2268 output->modrm = (mod << 6) | ((rfield & 7) << 3) | 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002269 output->sib = (scale << 6) | (index << 3) | base;
2270 }
2271 } else { /* it's 16-bit */
2272 int mod, rm;
H. Peter Anvin70653092007-10-19 14:42:29 -07002273
Keith Kaniosb7a89542007-04-12 02:40:54 +00002274 /* check for 64-bit long mode */
2275 if (addrbits == 64)
2276 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002277
H. Peter Anvine2c80182005-01-15 22:15:51 +00002278 /* check all registers are BX, BP, SI or DI */
2279 if ((b != -1 && b != R_BP && b != R_BX && b != R_SI
2280 && b != R_DI) || (i != -1 && i != R_BP && i != R_BX
2281 && i != R_SI && i != R_DI))
2282 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002283
Keith Kaniosb7a89542007-04-12 02:40:54 +00002284 /* ensure the user didn't specify DWORD/QWORD */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002285 if (input->disp_size == 32 || input->disp_size == 64)
H. Peter Anvine2c80182005-01-15 22:15:51 +00002286 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002287
H. Peter Anvine2c80182005-01-15 22:15:51 +00002288 if (s != 1 && i != -1)
2289 return NULL; /* no can do, in 16-bit EA */
2290 if (b == -1 && i != -1) {
2291 int tmp = b;
2292 b = i;
2293 i = tmp;
2294 } /* swap */
2295 if ((b == R_SI || b == R_DI) && i != -1) {
2296 int tmp = b;
2297 b = i;
2298 i = tmp;
2299 }
2300 /* have BX/BP as base, SI/DI index */
2301 if (b == i)
2302 return NULL; /* shouldn't ever happen, in theory */
2303 if (i != -1 && b != -1 &&
2304 (i == R_BP || i == R_BX || b == R_SI || b == R_DI))
2305 return NULL; /* invalid combinations */
2306 if (b == -1) /* pure offset: handled above */
2307 return NULL; /* so if it gets to here, panic! */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002308
H. Peter Anvine2c80182005-01-15 22:15:51 +00002309 rm = -1;
2310 if (i != -1)
2311 switch (i * 256 + b) {
2312 case R_SI * 256 + R_BX:
2313 rm = 0;
2314 break;
2315 case R_DI * 256 + R_BX:
2316 rm = 1;
2317 break;
2318 case R_SI * 256 + R_BP:
2319 rm = 2;
2320 break;
2321 case R_DI * 256 + R_BP:
2322 rm = 3;
2323 break;
2324 } else
2325 switch (b) {
2326 case R_SI:
2327 rm = 4;
2328 break;
2329 case R_DI:
2330 rm = 5;
2331 break;
2332 case R_BP:
2333 rm = 6;
2334 break;
2335 case R_BX:
2336 rm = 7;
2337 break;
2338 }
2339 if (rm == -1) /* can't happen, in theory */
2340 return NULL; /* so panic if it does */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002341
H. Peter Anvine2c80182005-01-15 22:15:51 +00002342 if (o == 0 && seg == NO_SEG && !forw_ref && rm != 6 &&
2343 !(input->eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS)))
2344 mod = 0;
2345 else if (input->eaflags & EAF_BYTEOFFS ||
2346 (o >= -128 && o <= 127 && seg == NO_SEG
2347 && !forw_ref
2348 && !(input->eaflags & EAF_WORDOFFS)))
2349 mod = 1;
2350 else
2351 mod = 2;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002352
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002353 output->sib_present = false; /* no SIB - it's 16-bit */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002354 output->bytes = mod; /* bytes of offset needed */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002355 output->modrm = (mod << 6) | ((rfield & 7) << 3) | rm;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002356 }
2357 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002358 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002359
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002360 output->size = 1 + output->sib_present + output->bytes;
2361 return output;
2362}
2363
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002364static void add_asp(insn *ins, int addrbits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002365{
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002366 int j, valid;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002367 int defdisp;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002368
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002369 valid = (addrbits == 64) ? 64|32 : 32|16;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002370
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002371 switch (ins->prefixes[PPS_ASIZE]) {
2372 case P_A16:
2373 valid &= 16;
2374 break;
2375 case P_A32:
2376 valid &= 32;
2377 break;
2378 case P_A64:
2379 valid &= 64;
2380 break;
2381 case P_ASP:
2382 valid &= (addrbits == 32) ? 16 : 32;
2383 break;
2384 default:
2385 break;
2386 }
2387
2388 for (j = 0; j < ins->operands; j++) {
2389 if (!(MEMORY & ~ins->oprs[j].type)) {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002390 int32_t i, b;
H. Peter Anvin70653092007-10-19 14:42:29 -07002391
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002392 /* Verify as Register */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002393 if (ins->oprs[j].indexreg < EXPR_REG_START
2394 || ins->oprs[j].indexreg >= REG_ENUM_LIMIT)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002395 i = 0;
2396 else
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002397 i = reg_flags[ins->oprs[j].indexreg];
H. Peter Anvin70653092007-10-19 14:42:29 -07002398
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002399 /* Verify as Register */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002400 if (ins->oprs[j].basereg < EXPR_REG_START
2401 || ins->oprs[j].basereg >= REG_ENUM_LIMIT)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002402 b = 0;
2403 else
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002404 b = reg_flags[ins->oprs[j].basereg];
H. Peter Anvin70653092007-10-19 14:42:29 -07002405
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002406 if (ins->oprs[j].scale == 0)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002407 i = 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002408
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002409 if (!i && !b) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002410 int ds = ins->oprs[j].disp_size;
2411 if ((addrbits != 64 && ds > 8) ||
2412 (addrbits == 64 && ds == 16))
2413 valid &= ds;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002414 } else {
2415 if (!(REG16 & ~b))
2416 valid &= 16;
2417 if (!(REG32 & ~b))
2418 valid &= 32;
2419 if (!(REG64 & ~b))
2420 valid &= 64;
H. Peter Anvin70653092007-10-19 14:42:29 -07002421
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002422 if (!(REG16 & ~i))
2423 valid &= 16;
2424 if (!(REG32 & ~i))
2425 valid &= 32;
2426 if (!(REG64 & ~i))
2427 valid &= 64;
2428 }
2429 }
2430 }
2431
2432 if (valid & addrbits) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002433 ins->addr_size = addrbits;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002434 } else if (valid & ((addrbits == 32) ? 16 : 32)) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002435 /* Add an address size prefix */
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002436 enum prefixes pref = (addrbits == 32) ? P_A16 : P_A32;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002437 ins->prefixes[PPS_ASIZE] = pref;
2438 ins->addr_size = (addrbits == 32) ? 16 : 32;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002439 } else {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002440 /* Impossible... */
2441 errfunc(ERR_NONFATAL, "impossible combination of address sizes");
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002442 ins->addr_size = addrbits; /* Error recovery */
2443 }
2444
2445 defdisp = ins->addr_size == 16 ? 16 : 32;
2446
2447 for (j = 0; j < ins->operands; j++) {
2448 if (!(MEM_OFFS & ~ins->oprs[j].type) &&
2449 (ins->oprs[j].disp_size ? ins->oprs[j].disp_size : defdisp)
2450 != ins->addr_size) {
2451 /* mem_offs sizes must match the address size; if not,
2452 strip the MEM_OFFS bit and match only EA instructions */
2453 ins->oprs[j].type &= ~(MEM_OFFS & ~MEMORY);
2454 }
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002455 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002456}