blob: 31955e5d7346331a41dbf67ec9cf91096f66ba7a [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 Anvin401c07e2007-09-17 16:55:04 -070047 * \171 - placement of DREX suffix in the absence of an EA
H. Peter Anvind85d2502008-05-04 17:53:31 -070048 * \172\ab - the register number from operand a in bits 7..4, with
H. Peter Anvin52dc3532008-05-20 19:29:04 -070049 * the 4-bit immediate from operand b in bits 3..0.
H. Peter Anvind58656f2008-05-06 20:11:14 -070050 * \173\xab - the register number from operand a in bits 7..4, with
H. Peter Anvin52dc3532008-05-20 19:29:04 -070051 * the value b in bits 3..0.
52 * \174\a - the register number from operand a in bits 7..4, and
53 * an arbitrary value in bits 3..0 (assembled as zero.)
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000054 * \2ab - a ModRM, calculated on EA in operand a, with the spare
55 * field equal to digit b.
H. Peter Anvin32cd4c22008-04-04 13:34:53 -070056 * \250..\253 - same as \150..\153, except warn if the 64-bit operand
57 * is not equal to the truncated and sign-extended 32-bit
58 * operand; used for 32-bit immediates in 64-bit mode.
H. Peter Anvind85d2502008-05-04 17:53:31 -070059 * \260..\263 - this instruction uses VEX rather than REX, with the
60 * V field taken from operand 0..3.
61 * \270 - this instruction uses VEX rather than REX, with the
62 * V field set to 1111b.
63 *
64 * VEX prefixes are followed by the sequence:
H. Peter Anvinaaa088f2008-05-12 11:13:41 -070065 * \mm\wlp where mm is the M field; and wlp is:
66 * 00 0ww lpp
H. Peter Anvinbd420c72008-05-22 11:24:35 -070067 * [w0] ww = 0 for W = 0
68 * [w1] ww = 1 for W = 1
69 * [wx] ww = 2 for W don't care (always assembled as 0)
70 * [ww] ww = 3 for W used as REX.W
71 *
H. Peter Anvind85d2502008-05-04 17:53:31 -070072 *
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000073 * \310 - indicates fixed 16-bit address size, i.e. optional 0x67.
74 * \311 - indicates fixed 32-bit address size, i.e. optional 0x67.
Keith Kanios48af1772007-08-17 07:37:52 +000075 * \312 - (disassembler only) marker on LOOP, LOOPxx instructions.
H. Peter Anvince2b3972007-05-30 22:21:11 +000076 * \313 - indicates fixed 64-bit address size, 0x67 invalid.
H. Peter Anvin23440102007-11-12 21:02:33 -080077 * \314 - (disassembler only) invalid with REX.B
78 * \315 - (disassembler only) invalid with REX.X
79 * \316 - (disassembler only) invalid with REX.R
80 * \317 - (disassembler only) invalid with REX.W
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000081 * \320 - indicates fixed 16-bit operand size, i.e. optional 0x66.
82 * \321 - indicates fixed 32-bit operand size, i.e. optional 0x66.
83 * \322 - indicates that this instruction is only valid when the
84 * operand size is the default (instruction to disassembler,
85 * generates no code in the assembler)
H. Peter Anvince2b3972007-05-30 22:21:11 +000086 * \323 - indicates fixed 64-bit operand size, REX on extensions only.
Keith Kaniosb7a89542007-04-12 02:40:54 +000087 * \324 - indicates 64-bit operand size requiring REX prefix.
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000088 * \330 - a literal byte follows in the code stream, to be added
89 * to the condition code value of the instruction.
Keith Kanios48af1772007-08-17 07:37:52 +000090 * \331 - instruction not valid with REP prefix. Hint for
H. Peter Anvinef7468f2002-04-30 20:57:59 +000091 * disassembler only; for SSE instructions.
H. Peter Anvincb9b6902007-09-12 21:58:51 -070092 * \332 - REP prefix (0xF2 byte) used as opcode extension.
93 * \333 - REP prefix (0xF3 byte) used as opcode extension.
Keith Kanios48af1772007-08-17 07:37:52 +000094 * \334 - LOCK prefix used instead of REX.R
H. Peter Anvincb9b6902007-09-12 21:58:51 -070095 * \335 - disassemble a rep (0xF3 byte) prefix as repe not rep.
Keith Kaniosb7a89542007-04-12 02:40:54 +000096 * \340 - reserve <operand 0> bytes of uninitialized storage.
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000097 * Operand 0 had better be a segmentless constant.
H. Peter Anvinfff5a472008-05-20 09:46:24 -070098 * \360 - no SSE prefix (== \364\331)
99 * \361 - 66 SSE prefix (== \366\331)
100 * \362 - F2 SSE prefix (== \364\332)
101 * \363 - F3 SSE prefix (== \364\333)
H. Peter Anvin62cb6062007-09-11 22:44:03 +0000102 * \364 - operand-size prefix (0x66) not permitted
103 * \365 - address-size prefix (0x67) not permitted
104 * \366 - operand-size prefix (0x66) used as opcode extension
105 * \367 - address-size prefix (0x67) used as opcode extension
H. Peter Anvin788e6c12002-04-30 21:02:01 +0000106 * \370,\371,\372 - match only if operand 0 meets byte jump criteria.
107 * 370 is used for Jcc, 371 is used for JMP.
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000108 * \373 - assemble 0x03 if bits==16, 0x05 if bits==32;
109 * used for conditional jump over longer jump
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000110 */
111
H. Peter Anvinfe501952007-10-02 21:53:51 -0700112#include "compiler.h"
113
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000114#include <stdio.h>
115#include <string.h>
Keith Kaniosb7a89542007-04-12 02:40:54 +0000116#include <inttypes.h>
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000117
118#include "nasm.h"
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000119#include "nasmlib.h"
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000120#include "assemble.h"
121#include "insns.h"
H. Peter Anvina4835d42008-05-20 14:21:29 -0700122#include "tables.h"
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000123
H. Peter Anvindfb91802008-05-20 11:43:53 -0700124/* Initialized to zero by the C standard */
125static const uint8_t const_zero_buf[256];
126
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000127typedef struct {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000128 int sib_present; /* is a SIB byte necessary? */
129 int bytes; /* # of bytes of offset needed */
130 int size; /* lazy - this is sib+bytes+1 */
131 uint8_t modrm, sib, rex, rip; /* the bytes themselves */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000132} ea;
133
Keith Kaniosb7a89542007-04-12 02:40:54 +0000134static uint32_t cpu; /* cpu level received from nasm.c */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000135static efunc errfunc;
136static struct ofmt *outfmt;
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000137static ListGen *list;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000138
H. Peter Anvin3720f7b2008-05-12 11:00:50 -0700139static int64_t calcsize(int32_t, int64_t, int, insn *, const uint8_t *);
140static void gencode(int32_t, int64_t, int, insn *, const uint8_t *, int64_t);
H. Peter Anvin3360d792007-09-11 04:16:57 +0000141static int matches(const struct itemplate *, insn *, int bits);
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000142static int32_t regflag(const operand *);
143static int32_t regval(const operand *);
144static int rexflags(int, int32_t, int);
145static int op_rexflags(const operand *, int);
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700146static ea *process_ea(operand *, ea *, int, int, int, int32_t, int);
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700147static void add_asp(insn *, int);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000148
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700149static int has_prefix(insn * ins, enum prefix_pos pos, enum prefixes prefix)
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000150{
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700151 return ins->prefixes[pos] == prefix;
152}
153
154static void assert_no_prefix(insn * ins, enum prefix_pos pos)
155{
156 if (ins->prefixes[pos])
157 errfunc(ERR_NONFATAL, "invalid %s prefix",
158 prefix_name(ins->prefixes[pos]));
159}
160
161static const char *size_name(int size)
162{
163 switch (size) {
164 case 1:
165 return "byte";
166 case 2:
167 return "word";
168 case 4:
169 return "dword";
170 case 8:
171 return "qword";
172 case 10:
173 return "tword";
174 case 16:
175 return "oword";
H. Peter Anvindfb91802008-05-20 11:43:53 -0700176 case 32:
177 return "yword";
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700178 default:
179 return "???";
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000180 }
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700181}
182
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700183static void warn_overflow(int size, int64_t data)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700184{
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700185 if (size < 8) {
Charles Craynedd462c82007-11-04 15:28:30 -0800186 int64_t lim = ((int64_t)1 << (size*8))-1;
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000187
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700188 if (data < ~lim || data > lim)
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700189 errfunc(ERR_WARNING | ERR_WARN_NOV,
190 "%s data exceeds bounds", size_name(size));
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700191 }
192}
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000193/*
194 * This routine wrappers the real output format's output routine,
195 * in order to pass a copy of the data off to the listing file
196 * generator at the same time.
197 */
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800198static void out(int64_t offset, int32_t segto, const void *data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800199 enum out_type type, uint64_t size,
200 int32_t segment, int32_t wrt)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000201{
Keith Kaniosb7a89542007-04-12 02:40:54 +0000202 static int32_t lineno = 0; /* static!!! */
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000203 static char *lnfname = NULL;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800204 uint8_t p[8];
H. Peter Anvineba20a72002-04-30 20:53:55 +0000205
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800206 if (type == OUT_ADDRESS && segment == NO_SEG && wrt == NO_SEG) {
207 /*
208 * This is a non-relocated address, and we're going to
209 * convert it into RAWDATA format.
210 */
211 uint8_t *q = p;
H. Peter Anvind1fb15c2007-11-13 09:37:59 -0800212
213 if (size > 8) {
214 errfunc(ERR_PANIC, "OUT_ADDRESS with size > 8");
215 return;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800216 }
H. Peter Anvind85d2502008-05-04 17:53:31 -0700217
H. Peter Anvind1fb15c2007-11-13 09:37:59 -0800218 WRITEADDR(q, *(int64_t *)data, size);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800219 data = p;
220 type = OUT_RAWDATA;
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000221 }
222
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800223 list->output(offset, data, type, size);
224
Frank Kotlerabebb082003-09-06 04:45:37 +0000225 /*
226 * this call to src_get determines when we call the
227 * debug-format-specific "linenum" function
228 * it updates lineno and lnfname to the current values
229 * returning 0 if "same as last time", -2 if lnfname
230 * changed, and the amount by which lineno changed,
231 * if it did. thus, these variables must be static
232 */
233
H. Peter Anvine2c80182005-01-15 22:15:51 +0000234 if (src_get(&lineno, &lnfname)) {
235 outfmt->current_dfmt->linenum(lnfname, lineno, segto);
H. Peter Anvince616072002-04-30 21:02:23 +0000236 }
H. Peter Anvineba20a72002-04-30 20:53:55 +0000237
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800238 outfmt->output(segto, data, type, size, segment, wrt);
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000239}
240
Charles Crayne5fbbc8c2007-11-07 19:03:46 -0800241static int jmp_match(int32_t segment, int64_t offset, int bits,
H. Peter Anvin3720f7b2008-05-12 11:00:50 -0700242 insn * ins, const uint8_t *code)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000243{
Charles Crayne5fbbc8c2007-11-07 19:03:46 -0800244 int64_t isize;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000245 uint8_t c = code[0];
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000246
H. Peter Anvine2c80182005-01-15 22:15:51 +0000247 if (c != 0370 && c != 0371)
248 return 0;
H. Peter Anvin788e6c12002-04-30 21:02:01 +0000249 if (ins->oprs[0].opflags & OPFLAG_FORWARD) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000250 if ((optimizing < 0 || (ins->oprs[0].type & STRICT))
251 && c == 0370)
252 return 1;
253 else
254 return (pass0 == 0); /* match a forward reference */
H. Peter Anvin788e6c12002-04-30 21:02:01 +0000255 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000256 isize = calcsize(segment, offset, bits, ins, code);
257 if (ins->oprs[0].segment != segment)
258 return 0;
259 isize = ins->oprs[0].offset - offset - isize; /* isize is now the delta */
260 if (isize >= -128L && isize <= 127L)
261 return 1; /* it is byte size */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000262
263 return 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000264}
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000265
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800266int64_t assemble(int32_t segment, int64_t offset, int bits, uint32_t cp,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000267 insn * instruction, struct ofmt *output, efunc error,
268 ListGen * listgen)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000269{
H. Peter Anvin3360d792007-09-11 04:16:57 +0000270 const struct itemplate *temp;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000271 int j;
272 int size_prob;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800273 int64_t insn_end;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000274 int32_t itimes;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800275 int64_t start = offset;
276 int64_t wsize = 0; /* size for DB etc. */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000277
H. Peter Anvine2c80182005-01-15 22:15:51 +0000278 errfunc = error; /* to pass to other functions */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000279 cpu = cp;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000280 outfmt = output; /* likewise */
281 list = listgen; /* and again */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000282
H. Peter Anvine2c80182005-01-15 22:15:51 +0000283 switch (instruction->opcode) {
284 case -1:
285 return 0;
286 case I_DB:
287 wsize = 1;
288 break;
289 case I_DW:
290 wsize = 2;
291 break;
292 case I_DD:
293 wsize = 4;
294 break;
295 case I_DQ:
296 wsize = 8;
297 break;
298 case I_DT:
299 wsize = 10;
300 break;
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700301 case I_DO:
302 wsize = 16;
303 break;
H. Peter Anvindfb91802008-05-20 11:43:53 -0700304 case I_DY:
305 wsize = 32;
306 break;
H. Peter Anvin16b0a332007-09-12 20:27:41 -0700307 default:
308 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000309 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000310
H. Peter Anvineba20a72002-04-30 20:53:55 +0000311 if (wsize) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000312 extop *e;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000313 int32_t t = instruction->times;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000314 if (t < 0)
315 errfunc(ERR_PANIC,
316 "instruction->times < 0 (%ld) in assemble()", t);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000317
H. Peter Anvine2c80182005-01-15 22:15:51 +0000318 while (t--) { /* repeat TIMES times */
319 for (e = instruction->eops; e; e = e->next) {
320 if (e->type == EOT_DB_NUMBER) {
321 if (wsize == 1) {
322 if (e->segment != NO_SEG)
323 errfunc(ERR_NONFATAL,
324 "one-byte relocation attempted");
325 else {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000326 uint8_t out_byte = e->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000327 out(offset, segment, &out_byte,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800328 OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000329 }
Keith Kanios61ff53c2007-04-14 18:54:52 +0000330 } else if (wsize > 8) {
H. Peter Anvin3be5d852008-05-20 14:49:32 -0700331 errfunc(ERR_NONFATAL,
332 "integer supplied to a DT, DO or DY"
Keith Kanios61ff53c2007-04-14 18:54:52 +0000333 " instruction");
H. Peter Anvine2c80182005-01-15 22:15:51 +0000334 } else
335 out(offset, segment, &e->offset,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800336 OUT_ADDRESS, wsize, e->segment, e->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000337 offset += wsize;
H. Peter Anvin518df302008-06-14 16:53:48 -0700338 } else if (e->type == EOT_DB_STRING ||
339 e->type == EOT_DB_STRING_FREE) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000340 int align;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000341
H. Peter Anvine2c80182005-01-15 22:15:51 +0000342 out(offset, segment, e->stringval,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800343 OUT_RAWDATA, e->stringlen, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000344 align = e->stringlen % wsize;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000345
H. Peter Anvine2c80182005-01-15 22:15:51 +0000346 if (align) {
347 align = wsize - align;
H. Peter Anvindfb91802008-05-20 11:43:53 -0700348 out(offset, segment, const_zero_buf,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800349 OUT_RAWDATA, align, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000350 }
351 offset += e->stringlen + align;
352 }
353 }
354 if (t > 0 && t == instruction->times - 1) {
355 /*
356 * Dummy call to list->output to give the offset to the
357 * listing module.
358 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800359 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000360 list->uplevel(LIST_TIMES);
361 }
362 }
363 if (instruction->times > 1)
364 list->downlevel(LIST_TIMES);
365 return offset - start;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000366 }
367
H. Peter Anvine2c80182005-01-15 22:15:51 +0000368 if (instruction->opcode == I_INCBIN) {
H. Peter Anvin518df302008-06-14 16:53:48 -0700369 const char *fname = instruction->eops->stringval;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000370 FILE *fp;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000371
H. Peter Anvin418ca702008-05-30 10:42:30 -0700372 fp = fopen(fname, "rb");
373 if (!fp) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000374 error(ERR_NONFATAL, "`incbin': unable to open file `%s'",
375 fname);
H. Peter Anvin418ca702008-05-30 10:42:30 -0700376 } else if (fseek(fp, 0L, SEEK_END) < 0) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000377 error(ERR_NONFATAL, "`incbin': unable to seek on file `%s'",
378 fname);
H. Peter Anvin418ca702008-05-30 10:42:30 -0700379 } else {
H. Peter Anvin518df302008-06-14 16:53:48 -0700380 static char buf[4096];
381 size_t t = instruction->times;
382 size_t base = 0;
383 size_t len;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000384
H. Peter Anvine2c80182005-01-15 22:15:51 +0000385 len = ftell(fp);
386 if (instruction->eops->next) {
387 base = instruction->eops->next->offset;
388 len -= base;
389 if (instruction->eops->next->next &&
H. Peter Anvin518df302008-06-14 16:53:48 -0700390 len > (size_t)instruction->eops->next->next->offset)
391 len = (size_t)instruction->eops->next->next->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000392 }
393 /*
394 * Dummy call to list->output to give the offset to the
395 * listing module.
396 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800397 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000398 list->uplevel(LIST_INCBIN);
399 while (t--) {
H. Peter Anvin518df302008-06-14 16:53:48 -0700400 size_t l;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000401
H. Peter Anvine2c80182005-01-15 22:15:51 +0000402 fseek(fp, base, SEEK_SET);
403 l = len;
404 while (l > 0) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000405 int32_t m =
Charles Crayne192d5b52007-10-18 19:02:42 -0700406 fread(buf, 1, (l > (int32_t) sizeof(buf) ? (int32_t) sizeof(buf) : l),
H. Peter Anvine2c80182005-01-15 22:15:51 +0000407 fp);
408 if (!m) {
409 /*
410 * This shouldn't happen unless the file
411 * actually changes while we are reading
412 * it.
413 */
414 error(ERR_NONFATAL,
415 "`incbin': unexpected EOF while"
416 " reading file `%s'", fname);
417 t = 0; /* Try to exit cleanly */
418 break;
419 }
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800420 out(offset, segment, buf, OUT_RAWDATA, m,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000421 NO_SEG, NO_SEG);
422 l -= m;
423 }
424 }
425 list->downlevel(LIST_INCBIN);
426 if (instruction->times > 1) {
427 /*
428 * Dummy call to list->output to give the offset to the
429 * listing module.
430 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800431 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000432 list->uplevel(LIST_TIMES);
433 list->downlevel(LIST_TIMES);
434 }
435 fclose(fp);
436 return instruction->times * len;
437 }
438 return 0; /* if we're here, there's an error */
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000439 }
440
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700441 /* Check to see if we need an address-size prefix */
442 add_asp(instruction, bits);
443
H. Peter Anvin6867acc2007-10-10 14:58:45 -0700444 size_prob = false;
H. Peter Anvin70653092007-10-19 14:42:29 -0700445
446 for (temp = nasm_instructions[instruction->opcode]; temp->opcode != -1; temp++){
Keith Kaniosb7a89542007-04-12 02:40:54 +0000447 int m = matches(temp, instruction, bits);
H. Peter Anvin70653092007-10-19 14:42:29 -0700448
H. Peter Anvine2c80182005-01-15 22:15:51 +0000449 if (m == 99)
450 m += jmp_match(segment, offset, bits, instruction, temp->code);
H. Peter Anvineba20a72002-04-30 20:53:55 +0000451
H. Peter Anvine2c80182005-01-15 22:15:51 +0000452 if (m == 100) { /* matches! */
H. Peter Anvin3720f7b2008-05-12 11:00:50 -0700453 const uint8_t *codes = temp->code;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800454 int64_t insn_size = calcsize(segment, offset, bits,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000455 instruction, codes);
456 itimes = instruction->times;
457 if (insn_size < 0) /* shouldn't be, on pass two */
458 error(ERR_PANIC, "errors made it through from pass one");
459 else
460 while (itimes--) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700461 for (j = 0; j < MAXPREFIX; j++) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000462 uint8_t c = 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000463 switch (instruction->prefixes[j]) {
464 case P_LOCK:
465 c = 0xF0;
466 break;
467 case P_REPNE:
468 case P_REPNZ:
469 c = 0xF2;
470 break;
471 case P_REPE:
472 case P_REPZ:
473 case P_REP:
474 c = 0xF3;
475 break;
476 case R_CS:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000477 if (bits == 64) {
478 error(ERR_WARNING,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800479 "cs segment base generated, but will be ignored in 64-bit mode");
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000480 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000481 c = 0x2E;
482 break;
483 case R_DS:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000484 if (bits == 64) {
485 error(ERR_WARNING,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800486 "ds segment base generated, but will be ignored in 64-bit mode");
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000487 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000488 c = 0x3E;
489 break;
490 case R_ES:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000491 if (bits == 64) {
492 error(ERR_WARNING,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800493 "es segment base generated, but will be ignored in 64-bit mode");
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000494 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000495 c = 0x26;
496 break;
497 case R_FS:
498 c = 0x64;
499 break;
500 case R_GS:
501 c = 0x65;
502 break;
503 case R_SS:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000504 if (bits == 64) {
505 error(ERR_WARNING,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800506 "ss segment base generated, but will be ignored in 64-bit mode");
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000507 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000508 c = 0x36;
509 break;
510 case R_SEGR6:
511 case R_SEGR7:
512 error(ERR_NONFATAL,
513 "segr6 and segr7 cannot be used as prefixes");
514 break;
515 case P_A16:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000516 if (bits == 64) {
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000517 error(ERR_NONFATAL,
518 "16-bit addressing is not supported "
519 "in 64-bit mode");
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700520 } else if (bits != 16)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000521 c = 0x67;
522 break;
523 case P_A32:
524 if (bits != 32)
525 c = 0x67;
526 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700527 case P_A64:
528 if (bits != 64) {
529 error(ERR_NONFATAL,
530 "64-bit addressing is only supported "
531 "in 64-bit mode");
532 }
533 break;
534 case P_ASP:
535 c = 0x67;
536 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000537 case P_O16:
538 if (bits != 16)
539 c = 0x66;
540 break;
541 case P_O32:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000542 if (bits == 16)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000543 c = 0x66;
544 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700545 case P_O64:
546 /* REX.W */
547 break;
548 case P_OSP:
549 c = 0x66;
550 break;
551 case P_none:
552 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000553 default:
554 error(ERR_PANIC, "invalid instruction prefix");
555 }
556 if (c != 0) {
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800557 out(offset, segment, &c, OUT_RAWDATA, 1,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000558 NO_SEG, NO_SEG);
559 offset++;
560 }
H. Peter Anvin70653092007-10-19 14:42:29 -0700561 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000562 insn_end = offset + insn_size;
563 gencode(segment, offset, bits, instruction, codes,
564 insn_end);
565 offset += insn_size;
566 if (itimes > 0 && itimes == instruction->times - 1) {
567 /*
568 * Dummy call to list->output to give the offset to the
569 * listing module.
570 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800571 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000572 list->uplevel(LIST_TIMES);
573 }
574 }
575 if (instruction->times > 1)
576 list->downlevel(LIST_TIMES);
577 return offset - start;
578 } else if (m > 0 && m > size_prob) {
579 size_prob = m;
580 }
Keith Kaniosb7a89542007-04-12 02:40:54 +0000581// temp++;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000582 }
H. Peter Anvineba20a72002-04-30 20:53:55 +0000583
H. Peter Anvine2c80182005-01-15 22:15:51 +0000584 if (temp->opcode == -1) { /* didn't match any instruction */
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000585 switch (size_prob) {
586 case 1:
587 error(ERR_NONFATAL, "operation size not specified");
588 break;
589 case 2:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000590 error(ERR_NONFATAL, "mismatch in operand sizes");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000591 break;
592 case 3:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000593 error(ERR_NONFATAL, "no instruction for this cpu level");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000594 break;
595 case 4:
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000596 error(ERR_NONFATAL, "instruction not supported in 64-bit mode");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000597 break;
598 default:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000599 error(ERR_NONFATAL,
600 "invalid combination of opcode and operands");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000601 break;
602 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000603 }
604 return 0;
605}
606
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800607int64_t insn_size(int32_t segment, int64_t offset, int bits, uint32_t cp,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000608 insn * instruction, efunc error)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000609{
H. Peter Anvin3360d792007-09-11 04:16:57 +0000610 const struct itemplate *temp;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000611
H. Peter Anvine2c80182005-01-15 22:15:51 +0000612 errfunc = error; /* to pass to other functions */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000613 cpu = cp;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000614
615 if (instruction->opcode == -1)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000616 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000617
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700618 if (instruction->opcode == I_DB || instruction->opcode == I_DW ||
619 instruction->opcode == I_DD || instruction->opcode == I_DQ ||
H. Peter Anvindfb91802008-05-20 11:43:53 -0700620 instruction->opcode == I_DT || instruction->opcode == I_DO ||
621 instruction->opcode == I_DY) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000622 extop *e;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000623 int32_t isize, osize, wsize = 0; /* placate gcc */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000624
H. Peter Anvine2c80182005-01-15 22:15:51 +0000625 isize = 0;
626 switch (instruction->opcode) {
627 case I_DB:
628 wsize = 1;
629 break;
630 case I_DW:
631 wsize = 2;
632 break;
633 case I_DD:
634 wsize = 4;
635 break;
636 case I_DQ:
637 wsize = 8;
638 break;
639 case I_DT:
640 wsize = 10;
641 break;
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700642 case I_DO:
643 wsize = 16;
644 break;
H. Peter Anvindfb91802008-05-20 11:43:53 -0700645 case I_DY:
646 wsize = 32;
647 break;
H. Peter Anvin16b0a332007-09-12 20:27:41 -0700648 default:
649 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000650 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000651
H. Peter Anvine2c80182005-01-15 22:15:51 +0000652 for (e = instruction->eops; e; e = e->next) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000653 int32_t align;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000654
H. Peter Anvine2c80182005-01-15 22:15:51 +0000655 osize = 0;
656 if (e->type == EOT_DB_NUMBER)
657 osize = 1;
H. Peter Anvin518df302008-06-14 16:53:48 -0700658 else if (e->type == EOT_DB_STRING ||
659 e->type == EOT_DB_STRING_FREE)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000660 osize = e->stringlen;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000661
H. Peter Anvine2c80182005-01-15 22:15:51 +0000662 align = (-osize) % wsize;
663 if (align < 0)
664 align += wsize;
665 isize += osize + align;
666 }
667 return isize * instruction->times;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000668 }
669
H. Peter Anvine2c80182005-01-15 22:15:51 +0000670 if (instruction->opcode == I_INCBIN) {
H. Peter Anvin518df302008-06-14 16:53:48 -0700671 const char *fname = instruction->eops->stringval;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000672 FILE *fp;
H. Peter Anvin518df302008-06-14 16:53:48 -0700673 size_t len;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000674
H. Peter Anvin418ca702008-05-30 10:42:30 -0700675 fp = fopen(fname, "rb");
676 if (!fp)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000677 error(ERR_NONFATAL, "`incbin': unable to open file `%s'",
678 fname);
679 else if (fseek(fp, 0L, SEEK_END) < 0)
680 error(ERR_NONFATAL, "`incbin': unable to seek on file `%s'",
681 fname);
682 else {
683 len = ftell(fp);
684 fclose(fp);
685 if (instruction->eops->next) {
686 len -= instruction->eops->next->offset;
687 if (instruction->eops->next->next &&
H. Peter Anvin518df302008-06-14 16:53:48 -0700688 len > (size_t)instruction->eops->next->next->offset) {
689 len = (size_t)instruction->eops->next->next->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000690 }
691 }
692 return instruction->times * len;
693 }
694 return 0; /* if we're here, there's an error */
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000695 }
696
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700697 /* Check to see if we need an address-size prefix */
698 add_asp(instruction, bits);
699
Keith Kaniosb7a89542007-04-12 02:40:54 +0000700 for (temp = nasm_instructions[instruction->opcode]; temp->opcode != -1; temp++) {
701 int m = matches(temp, instruction, bits);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000702 if (m == 99)
703 m += jmp_match(segment, offset, bits, instruction, temp->code);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000704
H. Peter Anvine2c80182005-01-15 22:15:51 +0000705 if (m == 100) {
706 /* we've matched an instruction. */
Charles Crayne5fbbc8c2007-11-07 19:03:46 -0800707 int64_t isize;
H. Peter Anvin3720f7b2008-05-12 11:00:50 -0700708 const uint8_t *codes = temp->code;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000709 int j;
710
711 isize = calcsize(segment, offset, bits, instruction, codes);
712 if (isize < 0)
713 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700714 for (j = 0; j < MAXPREFIX; j++) {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700715 switch (instruction->prefixes[j]) {
716 case P_A16:
717 if (bits != 16)
718 isize++;
719 break;
720 case P_A32:
721 if (bits != 32)
722 isize++;
723 break;
724 case P_O16:
725 if (bits != 16)
726 isize++;
727 break;
728 case P_O32:
729 if (bits == 16)
730 isize++;
731 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700732 case P_A64:
733 case P_O64:
734 case P_none:
735 break;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700736 default:
737 isize++;
738 break;
739 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000740 }
741 return isize * instruction->times;
742 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000743 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000744 return -1; /* didn't match any instruction */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000745}
746
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700747static bool possible_sbyte(insn * ins, int op)
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000748{
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700749 return !(ins->forw_ref && ins->oprs[op].opflags) &&
H. Peter Anvine2c80182005-01-15 22:15:51 +0000750 optimizing >= 0 &&
751 !(ins->oprs[op].type & STRICT) &&
752 ins->oprs[op].wrt == NO_SEG && ins->oprs[op].segment == NO_SEG;
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000753}
754
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700755/* check that opn[op] is a signed byte of size 16 or 32 */
756static bool is_sbyte16(insn * ins, int op)
757{
758 int16_t v;
759
760 if (!possible_sbyte(ins, op))
761 return false;
762
763 v = ins->oprs[op].offset;
764 return v >= -128 && v <= 127;
765}
766
767static bool is_sbyte32(insn * ins, int op)
768{
769 int32_t v;
770
771 if (!possible_sbyte(ins, op))
772 return false;
773
774 v = ins->oprs[op].offset;
775 return v >= -128 && v <= 127;
776}
777
778/* check that opn[op] is a signed byte of size 32; warn if this is not
779 the original value when extended to 64 bits */
780static bool is_sbyte64(insn * ins, int op)
781{
782 int64_t v64;
783 int32_t v32;
784
785 /* dead in the water on forward reference or External */
786 if (!possible_sbyte(ins, op))
787 return false;
788
789 v64 = ins->oprs[op].offset;
790 v32 = (int32_t)v64;
791
792 warn_overflow(32, v64);
793
794 return v32 >= -128 && v32 <= 127;
795}
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800796static int64_t calcsize(int32_t segment, int64_t offset, int bits,
H. Peter Anvin3720f7b2008-05-12 11:00:50 -0700797 insn * ins, const uint8_t *codes)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000798{
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800799 int64_t length = 0;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000800 uint8_t c;
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000801 int rex_mask = ~0;
H. Peter Anvin839eca22007-10-29 23:12:47 -0700802 struct operand *opx;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000803
H. Peter Anvine3917fc2007-11-01 14:53:32 -0700804 ins->rex = 0; /* Ensure REX is reset */
805
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700806 if (ins->prefixes[PPS_OSIZE] == P_O64)
807 ins->rex |= REX_W;
808
H. Peter Anvine2c80182005-01-15 22:15:51 +0000809 (void)segment; /* Don't warn that this parameter is unused */
810 (void)offset; /* Don't warn that this parameter is unused */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000811
H. Peter Anvin839eca22007-10-29 23:12:47 -0700812 while (*codes) {
813 c = *codes++;
814 opx = &ins->oprs[c & 3];
815 switch (c) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000816 case 01:
817 case 02:
818 case 03:
819 codes += c, length += c;
820 break;
821 case 04:
822 case 05:
823 case 06:
824 case 07:
825 length++;
826 break;
827 case 010:
828 case 011:
829 case 012:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700830 case 013:
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000831 ins->rex |=
H. Peter Anvin839eca22007-10-29 23:12:47 -0700832 op_rexflags(opx, REX_B|REX_H|REX_P|REX_W);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000833 codes++, length++;
834 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000835 case 014:
836 case 015:
837 case 016:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700838 case 017:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000839 length++;
840 break;
841 case 020:
842 case 021:
843 case 022:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700844 case 023:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000845 length++;
846 break;
847 case 024:
848 case 025:
849 case 026:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700850 case 027:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000851 length++;
852 break;
853 case 030:
854 case 031:
855 case 032:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700856 case 033:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000857 length += 2;
858 break;
859 case 034:
860 case 035:
861 case 036:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700862 case 037:
H. Peter Anvin839eca22007-10-29 23:12:47 -0700863 if (opx->type & (BITS16 | BITS32 | BITS64))
864 length += (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000865 else
866 length += (bits == 16) ? 2 : 4;
867 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000868 case 040:
869 case 041:
870 case 042:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700871 case 043:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000872 length += 4;
873 break;
874 case 044:
875 case 045:
876 case 046:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700877 case 047:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700878 length += ins->addr_size >> 3;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000879 break;
880 case 050:
881 case 051:
882 case 052:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700883 case 053:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000884 length++;
885 break;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000886 case 054:
887 case 055:
888 case 056:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700889 case 057:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000890 length += 8; /* MOV reg64/imm */
891 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000892 case 060:
893 case 061:
894 case 062:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700895 case 063:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000896 length += 2;
897 break;
898 case 064:
899 case 065:
900 case 066:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700901 case 067:
H. Peter Anvin839eca22007-10-29 23:12:47 -0700902 if (opx->type & (BITS16 | BITS32 | BITS64))
903 length += (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000904 else
905 length += (bits == 16) ? 2 : 4;
906 break;
907 case 070:
908 case 071:
909 case 072:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700910 case 073:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000911 length += 4;
912 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700913 case 074:
914 case 075:
915 case 076:
916 case 077:
917 length += 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000918 break;
919 case 0140:
920 case 0141:
921 case 0142:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700922 case 0143:
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700923 length += is_sbyte16(ins, c & 3) ? 1 : 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000924 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000925 case 0144:
926 case 0145:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700927 case 0146:
928 case 0147:
H. Peter Anvina30cc072007-11-18 21:55:26 -0800929 codes++;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000930 length++;
931 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700932 case 0150:
933 case 0151:
934 case 0152:
935 case 0153:
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700936 length += is_sbyte32(ins, c & 3) ? 1 : 4;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700937 break;
938 case 0154:
939 case 0155:
940 case 0156:
941 case 0157:
H. Peter Anvina30cc072007-11-18 21:55:26 -0800942 codes++;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700943 length++;
944 break;
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700945 case 0160:
946 case 0161:
947 case 0162:
948 case 0163:
949 length++;
950 ins->rex |= REX_D;
H. Peter Anvind85d2502008-05-04 17:53:31 -0700951 ins->drexdst = regval(opx);
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700952 break;
953 case 0164:
954 case 0165:
955 case 0166:
956 case 0167:
957 length++;
958 ins->rex |= REX_D|REX_OC;
H. Peter Anvind85d2502008-05-04 17:53:31 -0700959 ins->drexdst = regval(opx);
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700960 break;
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700961 case 0171:
962 break;
H. Peter Anvind85d2502008-05-04 17:53:31 -0700963 case 0172:
H. Peter Anvind58656f2008-05-06 20:11:14 -0700964 case 0173:
H. Peter Anvin52dc3532008-05-20 19:29:04 -0700965 case 0174:
H. Peter Anvind85d2502008-05-04 17:53:31 -0700966 codes++;
967 length++;
968 break;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700969 case 0250:
970 case 0251:
971 case 0252:
972 case 0253:
973 length += is_sbyte64(ins, c & 3) ? 1 : 4;
974 break;
H. Peter Anvind85d2502008-05-04 17:53:31 -0700975 case 0260:
976 case 0261:
977 case 0262:
978 case 0263:
979 length += 2;
980 ins->rex |= REX_V;
981 ins->drexdst = regval(opx);
982 ins->vex_m = *codes++;
983 ins->vex_wlp = *codes++;
984 break;
985 case 0270:
986 length += 2;
987 ins->rex |= REX_V;
988 ins->drexdst = 0;
989 ins->vex_m = *codes++;
990 ins->vex_wlp = *codes++;
991 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000992 case 0300:
993 case 0301:
H. Peter Anvin70653092007-10-19 14:42:29 -0700994 case 0302:
995 case 0303:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000996 break;
997 case 0310:
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700998 if (bits == 64)
999 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001000 length += (bits != 16) && !has_prefix(ins, PPS_ASIZE, P_A16);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001001 break;
1002 case 0311:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001003 length += (bits != 32) && !has_prefix(ins, PPS_ASIZE, P_A32);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001004 break;
1005 case 0312:
H. Peter Anvin70653092007-10-19 14:42:29 -07001006 break;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001007 case 0313:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001008 if (bits != 64 || has_prefix(ins, PPS_ASIZE, P_A16) ||
1009 has_prefix(ins, PPS_ASIZE, P_A32))
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07001010 return -1;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001011 break;
H. Peter Anvin23440102007-11-12 21:02:33 -08001012 case 0314:
1013 case 0315:
1014 case 0316:
1015 case 0317:
1016 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001017 case 0320:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001018 length += (bits != 16);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001019 break;
1020 case 0321:
1021 length += (bits == 16);
1022 break;
1023 case 0322:
1024 break;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001025 case 0323:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001026 rex_mask &= ~REX_W;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001027 break;
1028 case 0324:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001029 ins->rex |= REX_W;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001030 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001031 case 0330:
1032 codes++, length++;
1033 break;
1034 case 0331:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001035 break;
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001036 case 0332:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001037 case 0333:
1038 length++;
1039 break;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001040 case 0334:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001041 ins->rex |= REX_L;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001042 break;
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001043 case 0335:
1044 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001045 case 0340:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001046 if (ins->oprs[0].segment != NO_SEG)
1047 errfunc(ERR_NONFATAL, "attempt to reserve non-constant"
1048 " quantity of BSS space");
1049 else
H. Peter Anvin428fd672007-11-15 10:25:52 -08001050 length += ins->oprs[0].offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001051 break;
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001052 case 0360:
1053 break;
1054 case 0361:
1055 case 0362:
1056 case 0363:
1057 length++;
1058 break;
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001059 case 0364:
1060 case 0365:
1061 break;
Keith Kanios48af1772007-08-17 07:37:52 +00001062 case 0366:
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001063 case 0367:
1064 length++;
1065 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001066 case 0370:
1067 case 0371:
1068 case 0372:
1069 break;
1070 case 0373:
1071 length++;
1072 break;
1073 default: /* can't do it by 'case' statements */
1074 if (c >= 0100 && c <= 0277) { /* it's an EA */
1075 ea ea_data;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001076 int rfield;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001077 int32_t rflags;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001078 ea_data.rex = 0; /* Ensure ea.REX is initially 0 */
H. Peter Anvin70653092007-10-19 14:42:29 -07001079
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001080 if (c <= 0177) {
1081 /* pick rfield from operand b */
1082 rflags = regflag(&ins->oprs[c & 7]);
H. Peter Anvina4835d42008-05-20 14:21:29 -07001083 rfield = nasm_regvals[ins->oprs[c & 7].basereg];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001084 } else {
1085 rflags = 0;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001086 rfield = c & 7;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001087 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00001088
H. Peter Anvine2c80182005-01-15 22:15:51 +00001089 if (!process_ea
Keith Kaniosb7a89542007-04-12 02:40:54 +00001090 (&ins->oprs[(c >> 3) & 7], &ea_data, bits,
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001091 ins->addr_size, rfield, rflags, ins->forw_ref)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001092 errfunc(ERR_NONFATAL, "invalid effective address");
1093 return -1;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001094 } else {
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001095 ins->rex |= ea_data.rex;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001096 length += ea_data.size;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001097 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001098 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001099 errfunc(ERR_PANIC, "internal instruction table corrupt"
1100 ": instruction code 0x%02X given", c);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001101 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001102 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001103 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001104
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001105 ins->rex &= rex_mask;
H. Peter Anvin70653092007-10-19 14:42:29 -07001106
H. Peter Anvind85d2502008-05-04 17:53:31 -07001107 if (ins->rex & REX_V) {
1108 int bad32 = REX_R|REX_W|REX_X|REX_B;
1109
1110 if (ins->rex & REX_H) {
1111 errfunc(ERR_NONFATAL, "cannot use high register in vex instruction");
1112 return -1;
1113 }
1114 switch (ins->vex_wlp & 030) {
1115 case 000:
H. Peter Anvinbd420c72008-05-22 11:24:35 -07001116 case 020:
H. Peter Anvind85d2502008-05-04 17:53:31 -07001117 ins->rex &= ~REX_W;
1118 break;
1119 case 010:
1120 ins->rex |= REX_W;
1121 bad32 &= ~REX_W;
1122 break;
H. Peter Anvinbd420c72008-05-22 11:24:35 -07001123 case 030:
H. Peter Anvind85d2502008-05-04 17:53:31 -07001124 /* Follow REX_W */
1125 break;
1126 }
1127
1128 if (bits != 64 && ((ins->rex & bad32) || ins->drexdst > 7)) {
1129 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1130 return -1;
1131 }
1132 if (ins->vex_m != 1 || (ins->rex & (REX_W|REX_R|REX_B)))
1133 length += 3;
1134 else
1135 length += 2;
1136 } else if (ins->rex & REX_D) {
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001137 if (ins->rex & REX_H) {
1138 errfunc(ERR_NONFATAL, "cannot use high register in drex instruction");
1139 return -1;
1140 }
H. Peter Anvind85d2502008-05-04 17:53:31 -07001141 if (bits != 64 && ((ins->rex & (REX_R|REX_W|REX_X|REX_B)) ||
H. Peter Anvincf5180a2007-09-17 17:25:27 -07001142 ins->drexdst > 7)) {
1143 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1144 return -1;
1145 }
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001146 length++;
1147 } else if (ins->rex & REX_REAL) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001148 if (ins->rex & REX_H) {
1149 errfunc(ERR_NONFATAL, "cannot use high register in rex instruction");
1150 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001151 } else if (bits == 64) {
1152 length++;
1153 } else if ((ins->rex & REX_L) &&
1154 !(ins->rex & (REX_P|REX_W|REX_X|REX_B)) &&
1155 cpu >= IF_X86_64) {
1156 /* LOCK-as-REX.R */
1157 assert_no_prefix(ins, PPS_LREP);
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001158 length++;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001159 } else {
H. Peter Anvincf5180a2007-09-17 17:25:27 -07001160 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1161 return -1;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001162 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00001163 }
1164
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001165 return length;
1166}
Keith Kaniosb7a89542007-04-12 02:40:54 +00001167
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001168#define EMIT_REX() \
H. Peter Anvind85d2502008-05-04 17:53:31 -07001169 if (!(ins->rex & (REX_D|REX_V)) && (ins->rex & REX_REAL) && (bits == 64)) { \
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001170 ins->rex = (ins->rex & REX_REAL)|REX_P; \
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001171 out(offset, segment, &ins->rex, OUT_RAWDATA, 1, NO_SEG, NO_SEG); \
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001172 ins->rex = 0; \
1173 offset += 1; \
1174 }
1175
Charles Crayne1f8bc4c2007-11-06 18:27:23 -08001176static void gencode(int32_t segment, int64_t offset, int bits,
H. Peter Anvin3720f7b2008-05-12 11:00:50 -07001177 insn * ins, const uint8_t *codes, int64_t insn_end)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001178{
Keith Kaniosa6dfa782007-04-13 16:47:53 +00001179 static char condval[] = { /* conditional opcodes */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001180 0x7, 0x3, 0x2, 0x6, 0x2, 0x4, 0xF, 0xD, 0xC, 0xE, 0x6, 0x2,
1181 0x3, 0x7, 0x3, 0x5, 0xE, 0xC, 0xD, 0xF, 0x1, 0xB, 0x9, 0x5,
1182 0x0, 0xA, 0xA, 0xB, 0x8, 0x4
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001183 };
Keith Kaniosb7a89542007-04-12 02:40:54 +00001184 uint8_t c;
1185 uint8_t bytes[4];
Charles Crayne1f8bc4c2007-11-06 18:27:23 -08001186 int64_t size;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001187 int64_t data;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001188 struct operand *opx;
H. Peter Anvin70653092007-10-19 14:42:29 -07001189
H. Peter Anvin839eca22007-10-29 23:12:47 -07001190 while (*codes) {
1191 c = *codes++;
1192 opx = &ins->oprs[c & 3];
1193 switch (c) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001194 case 01:
1195 case 02:
1196 case 03:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001197 EMIT_REX();
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001198 out(offset, segment, codes, OUT_RAWDATA, c, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001199 codes += c;
1200 offset += c;
1201 break;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001202
H. Peter Anvine2c80182005-01-15 22:15:51 +00001203 case 04:
1204 case 06:
1205 switch (ins->oprs[0].basereg) {
1206 case R_CS:
1207 bytes[0] = 0x0E + (c == 0x04 ? 1 : 0);
1208 break;
1209 case R_DS:
1210 bytes[0] = 0x1E + (c == 0x04 ? 1 : 0);
1211 break;
1212 case R_ES:
1213 bytes[0] = 0x06 + (c == 0x04 ? 1 : 0);
1214 break;
1215 case R_SS:
1216 bytes[0] = 0x16 + (c == 0x04 ? 1 : 0);
1217 break;
1218 default:
1219 errfunc(ERR_PANIC,
1220 "bizarre 8086 segment register received");
1221 }
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001222 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001223 offset++;
1224 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001225
H. Peter Anvine2c80182005-01-15 22:15:51 +00001226 case 05:
1227 case 07:
1228 switch (ins->oprs[0].basereg) {
1229 case R_FS:
1230 bytes[0] = 0xA0 + (c == 0x05 ? 1 : 0);
1231 break;
1232 case R_GS:
1233 bytes[0] = 0xA8 + (c == 0x05 ? 1 : 0);
1234 break;
1235 default:
1236 errfunc(ERR_PANIC,
1237 "bizarre 386 segment register received");
1238 }
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001239 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001240 offset++;
1241 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001242
H. Peter Anvine2c80182005-01-15 22:15:51 +00001243 case 010:
1244 case 011:
1245 case 012:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001246 case 013:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001247 EMIT_REX();
H. Peter Anvin839eca22007-10-29 23:12:47 -07001248 bytes[0] = *codes++ + ((regval(opx)) & 7);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001249 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001250 offset += 1;
1251 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001252
H. Peter Anvine2c80182005-01-15 22:15:51 +00001253 case 014:
1254 case 015:
1255 case 016:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001256 case 017:
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001257 /* XXX: warns for legitimate optimizer actions */
H. Peter Anvin839eca22007-10-29 23:12:47 -07001258 if (opx->offset < -128 || opx->offset > 127) {
H. Peter Anvin72c64372008-01-08 22:13:48 -08001259 errfunc(ERR_WARNING | ERR_WARN_NOV,
1260 "signed byte value exceeds bounds");
H. Peter Anvine2c80182005-01-15 22:15:51 +00001261 }
H. Peter Anvineba20a72002-04-30 20:53:55 +00001262
H. Peter Anvin839eca22007-10-29 23:12:47 -07001263 if (opx->segment != NO_SEG) {
1264 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001265 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001266 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001267 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001268 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001269 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001270 NO_SEG);
1271 }
1272 offset += 1;
1273 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001274
H. Peter Anvine2c80182005-01-15 22:15:51 +00001275 case 020:
1276 case 021:
1277 case 022:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001278 case 023:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001279 if (opx->offset < -256 || opx->offset > 255) {
H. Peter Anvin72c64372008-01-08 22:13:48 -08001280 errfunc(ERR_WARNING | ERR_WARN_NOV,
1281 "byte value exceeds bounds");
H. Peter Anvine2c80182005-01-15 22:15:51 +00001282 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001283 if (opx->segment != NO_SEG) {
1284 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001285 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001286 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001287 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001288 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001289 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001290 NO_SEG);
1291 }
1292 offset += 1;
1293 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001294
H. Peter Anvine2c80182005-01-15 22:15:51 +00001295 case 024:
1296 case 025:
1297 case 026:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001298 case 027:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001299 if (opx->offset < 0 || opx->offset > 255)
H. Peter Anvin72c64372008-01-08 22:13:48 -08001300 errfunc(ERR_WARNING | ERR_WARN_NOV,
1301 "unsigned byte value exceeds bounds");
H. Peter Anvin839eca22007-10-29 23:12:47 -07001302 if (opx->segment != NO_SEG) {
1303 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001304 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001305 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001306 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001307 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001308 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001309 NO_SEG);
1310 }
1311 offset += 1;
1312 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001313
H. Peter Anvine2c80182005-01-15 22:15:51 +00001314 case 030:
1315 case 031:
1316 case 032:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001317 case 033:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001318 data = opx->offset;
1319 if (opx->segment == NO_SEG && opx->wrt == NO_SEG)
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001320 warn_overflow(2, data);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001321 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001322 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001323 offset += 2;
1324 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001325
H. Peter Anvine2c80182005-01-15 22:15:51 +00001326 case 034:
1327 case 035:
1328 case 036:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001329 case 037:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001330 if (opx->type & (BITS16 | BITS32))
1331 size = (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001332 else
1333 size = (bits == 16) ? 2 : 4;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001334 data = opx->offset;
1335 if (opx->segment == NO_SEG && opx->wrt == NO_SEG)
H. Peter Anvin10e27272007-10-29 22:56:08 -07001336 warn_overflow(size, data);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001337 out(offset, segment, &data, OUT_ADDRESS, size,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001338 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001339 offset += size;
1340 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001341
H. Peter Anvine2c80182005-01-15 22:15:51 +00001342 case 040:
1343 case 041:
1344 case 042:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001345 case 043:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001346 data = opx->offset;
H. Peter Anvin72c64372008-01-08 22:13:48 -08001347 if (opx->segment == NO_SEG && opx->wrt == NO_SEG)
1348 warn_overflow(4, data);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001349 out(offset, segment, &data, OUT_ADDRESS, 4,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001350 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001351 offset += 4;
1352 break;
H. Peter Anvin3ba46772002-05-27 23:19:35 +00001353
H. Peter Anvine2c80182005-01-15 22:15:51 +00001354 case 044:
1355 case 045:
1356 case 046:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001357 case 047:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001358 data = opx->offset;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001359 size = ins->addr_size >> 3;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001360 if (opx->segment == NO_SEG &&
1361 opx->wrt == NO_SEG)
H. Peter Anvin10e27272007-10-29 22:56:08 -07001362 warn_overflow(size, data);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001363 out(offset, segment, &data, OUT_ADDRESS, size,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001364 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001365 offset += size;
1366 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001367
H. Peter Anvine2c80182005-01-15 22:15:51 +00001368 case 050:
1369 case 051:
1370 case 052:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001371 case 053:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001372 if (opx->segment != segment)
H. Peter Anvine2c80182005-01-15 22:15:51 +00001373 errfunc(ERR_NONFATAL,
1374 "short relative jump outside segment");
H. Peter Anvin839eca22007-10-29 23:12:47 -07001375 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001376 if (data > 127 || data < -128)
1377 errfunc(ERR_NONFATAL, "short jump is out of range");
1378 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001379 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001380 offset += 1;
1381 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001382
Keith Kaniosb7a89542007-04-12 02:40:54 +00001383 case 054:
1384 case 055:
1385 case 056:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001386 case 057:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001387 data = (int64_t)opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001388 out(offset, segment, &data, OUT_ADDRESS, 8,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001389 opx->segment, opx->wrt);
Keith Kaniosb7a89542007-04-12 02:40:54 +00001390 offset += 8;
1391 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001392
H. Peter Anvine2c80182005-01-15 22:15:51 +00001393 case 060:
1394 case 061:
1395 case 062:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001396 case 063:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001397 if (opx->segment != segment) {
1398 data = opx->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001399 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001400 OUT_REL2ADR, insn_end - offset,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001401 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001402 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001403 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001404 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001405 OUT_ADDRESS, 2, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001406 }
1407 offset += 2;
1408 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001409
H. Peter Anvine2c80182005-01-15 22:15:51 +00001410 case 064:
1411 case 065:
1412 case 066:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001413 case 067:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001414 if (opx->type & (BITS16 | BITS32 | BITS64))
1415 size = (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001416 else
1417 size = (bits == 16) ? 2 : 4;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001418 if (opx->segment != segment) {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001419 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001420 out(offset, segment, &data,
1421 size == 2 ? OUT_REL2ADR : OUT_REL4ADR,
1422 insn_end - offset, opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001423 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001424 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001425 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001426 OUT_ADDRESS, size, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001427 }
1428 offset += size;
1429 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001430
H. Peter Anvine2c80182005-01-15 22:15:51 +00001431 case 070:
1432 case 071:
1433 case 072:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001434 case 073:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001435 if (opx->segment != segment) {
1436 data = opx->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001437 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001438 OUT_REL4ADR, insn_end - offset,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001439 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001440 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001441 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001442 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001443 OUT_ADDRESS, 4, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001444 }
1445 offset += 4;
1446 break;
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001447
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001448 case 074:
1449 case 075:
1450 case 076:
1451 case 077:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001452 if (opx->segment == NO_SEG)
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001453 errfunc(ERR_NONFATAL, "value referenced by FAR is not"
1454 " relocatable");
H. Peter Anvindfb91802008-05-20 11:43:53 -07001455 data = 0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001456 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001457 outfmt->segbase(1 + opx->segment),
1458 opx->wrt);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001459 offset += 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001460 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001461
H. Peter Anvine2c80182005-01-15 22:15:51 +00001462 case 0140:
1463 case 0141:
1464 case 0142:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001465 case 0143:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001466 data = opx->offset;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001467 if (is_sbyte16(ins, c & 3)) {
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001468 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001469 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001470 NO_SEG);
1471 offset++;
1472 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001473 if (opx->segment == NO_SEG &&
1474 opx->wrt == NO_SEG)
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001475 warn_overflow(2, data);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001476 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001477 opx->segment, opx->wrt);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001478 offset += 2;
1479 }
1480 break;
1481
1482 case 0144:
1483 case 0145:
1484 case 0146:
1485 case 0147:
1486 EMIT_REX();
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001487 bytes[0] = *codes++;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001488 if (is_sbyte16(ins, c & 3))
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001489 bytes[0] |= 2; /* s-bit */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001490 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001491 offset++;
1492 break;
1493
1494 case 0150:
1495 case 0151:
1496 case 0152:
1497 case 0153:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001498 data = opx->offset;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001499 if (is_sbyte32(ins, c & 3)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001500 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001501 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001502 NO_SEG);
1503 offset++;
1504 } else {
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001505 out(offset, segment, &data, OUT_ADDRESS, 4,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001506 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001507 offset += 4;
1508 }
1509 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001510
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001511 case 0154:
1512 case 0155:
1513 case 0156:
1514 case 0157:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001515 EMIT_REX();
H. Peter Anvine2c80182005-01-15 22:15:51 +00001516 bytes[0] = *codes++;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001517 if (is_sbyte32(ins, c & 3))
H. Peter Anvine2c80182005-01-15 22:15:51 +00001518 bytes[0] |= 2; /* s-bit */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001519 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001520 offset++;
1521 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001522
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001523 case 0160:
1524 case 0161:
1525 case 0162:
1526 case 0163:
1527 case 0164:
1528 case 0165:
1529 case 0166:
1530 case 0167:
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001531 break;
1532
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001533 case 0171:
1534 bytes[0] =
1535 (ins->drexdst << 4) |
1536 (ins->rex & REX_OC ? 0x08 : 0) |
1537 (ins->rex & (REX_R|REX_X|REX_B));
1538 ins->rex = 0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001539 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001540 offset++;
1541 break;
1542
H. Peter Anvind85d2502008-05-04 17:53:31 -07001543 case 0172:
1544 c = *codes++;
1545 opx = &ins->oprs[c >> 3];
H. Peter Anvina4835d42008-05-20 14:21:29 -07001546 bytes[0] = nasm_regvals[opx->basereg] << 4;
H. Peter Anvind85d2502008-05-04 17:53:31 -07001547 opx = &ins->oprs[c & 7];
1548 if (opx->segment != NO_SEG || opx->wrt != NO_SEG) {
1549 errfunc(ERR_NONFATAL,
1550 "non-absolute expression not permitted as argument %d",
1551 c & 7);
1552 } else {
1553 if (opx->offset & ~15) {
1554 errfunc(ERR_WARNING | ERR_WARN_NOV,
1555 "four-bit argument exceeds bounds");
1556 }
1557 bytes[0] |= opx->offset & 15;
1558 }
1559 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1560 offset++;
1561 break;
1562
H. Peter Anvind58656f2008-05-06 20:11:14 -07001563 case 0173:
1564 c = *codes++;
1565 opx = &ins->oprs[c >> 4];
H. Peter Anvina4835d42008-05-20 14:21:29 -07001566 bytes[0] = nasm_regvals[opx->basereg] << 4;
H. Peter Anvind58656f2008-05-06 20:11:14 -07001567 bytes[0] |= c & 15;
1568 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1569 offset++;
1570 break;
1571
H. Peter Anvin52dc3532008-05-20 19:29:04 -07001572 case 0174:
1573 c = *codes++;
1574 opx = &ins->oprs[c];
1575 bytes[0] = nasm_regvals[opx->basereg] << 4;
1576 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1577 offset++;
1578 break;
1579
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001580 case 0250:
1581 case 0251:
1582 case 0252:
1583 case 0253:
1584 data = opx->offset;
1585 /* is_sbyte32() is right here, we have already warned */
1586 if (is_sbyte32(ins, c & 3)) {
1587 bytes[0] = data;
1588 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
1589 NO_SEG);
1590 offset++;
1591 } else {
1592 out(offset, segment, &data, OUT_ADDRESS, 4,
1593 opx->segment, opx->wrt);
1594 offset += 4;
1595 }
1596 break;
1597
H. Peter Anvind85d2502008-05-04 17:53:31 -07001598 case 0260:
1599 case 0261:
1600 case 0262:
1601 case 0263:
1602 case 0270:
1603 codes += 2;
1604 if (ins->vex_m != 1 || (ins->rex & (REX_W|REX_X|REX_B))) {
1605 bytes[0] = 0xc4;
H. Peter Anvin4d2c38c2008-05-04 23:15:13 -07001606 bytes[1] = ins->vex_m | ((~ins->rex & 7) << 5);
H. Peter Anvind85d2502008-05-04 17:53:31 -07001607 bytes[2] = ((ins->rex & REX_W) << (7-3)) |
H. Peter Anvin4d2c38c2008-05-04 23:15:13 -07001608 ((~ins->drexdst & 15)<< 3) | (ins->vex_wlp & 07);
H. Peter Anvind85d2502008-05-04 17:53:31 -07001609 out(offset, segment, &bytes, OUT_RAWDATA, 3, NO_SEG, NO_SEG);
1610 offset += 3;
1611 } else {
1612 bytes[0] = 0xc5;
H. Peter Anvin4d2c38c2008-05-04 23:15:13 -07001613 bytes[1] = ((~ins->rex & REX_R) << (7-2)) |
1614 ((~ins->drexdst & 15) << 3) | (ins->vex_wlp & 07);
H. Peter Anvind85d2502008-05-04 17:53:31 -07001615 out(offset, segment, &bytes, OUT_RAWDATA, 2, NO_SEG, NO_SEG);
1616 offset += 2;
1617 }
1618 break;
1619
H. Peter Anvine2c80182005-01-15 22:15:51 +00001620 case 0300:
1621 case 0301:
1622 case 0302:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001623 case 0303:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001624 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001625
H. Peter Anvine2c80182005-01-15 22:15:51 +00001626 case 0310:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001627 if (bits == 32 && !has_prefix(ins, PPS_ASIZE, P_A16)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001628 *bytes = 0x67;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001629 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001630 offset += 1;
1631 } else
1632 offset += 0;
1633 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001634
H. Peter Anvine2c80182005-01-15 22:15:51 +00001635 case 0311:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001636 if (bits != 32 && !has_prefix(ins, PPS_ASIZE, P_A32)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001637 *bytes = 0x67;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001638 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001639 offset += 1;
1640 } else
1641 offset += 0;
1642 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001643
H. Peter Anvine2c80182005-01-15 22:15:51 +00001644 case 0312:
1645 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001646
Keith Kaniosb7a89542007-04-12 02:40:54 +00001647 case 0313:
1648 ins->rex = 0;
1649 break;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07001650
H. Peter Anvin23440102007-11-12 21:02:33 -08001651 case 0314:
1652 case 0315:
1653 case 0316:
1654 case 0317:
1655 break;
1656
H. Peter Anvine2c80182005-01-15 22:15:51 +00001657 case 0320:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001658 if (bits != 16) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001659 *bytes = 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001660 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001661 offset += 1;
1662 } else
1663 offset += 0;
1664 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001665
H. Peter Anvine2c80182005-01-15 22:15:51 +00001666 case 0321:
1667 if (bits == 16) {
1668 *bytes = 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001669 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001670 offset += 1;
1671 } else
1672 offset += 0;
1673 break;
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001674
H. Peter Anvine2c80182005-01-15 22:15:51 +00001675 case 0322:
H. Peter Anvin70653092007-10-19 14:42:29 -07001676 case 0323:
1677 break;
1678
Keith Kaniosb7a89542007-04-12 02:40:54 +00001679 case 0324:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001680 ins->rex |= REX_W;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001681 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001682
H. Peter Anvine2c80182005-01-15 22:15:51 +00001683 case 0330:
1684 *bytes = *codes++ ^ condval[ins->condition];
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001685 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001686 offset += 1;
1687 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001688
H. Peter Anvine2c80182005-01-15 22:15:51 +00001689 case 0331:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001690 break;
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001691
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001692 case 0332:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001693 case 0333:
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001694 *bytes = c - 0332 + 0xF2;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001695 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001696 offset += 1;
1697 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001698
Keith Kanios48af1772007-08-17 07:37:52 +00001699 case 0334:
1700 if (ins->rex & REX_R) {
1701 *bytes = 0xF0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001702 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
Keith Kanios48af1772007-08-17 07:37:52 +00001703 offset += 1;
1704 }
1705 ins->rex &= ~(REX_L|REX_R);
1706 break;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001707
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001708 case 0335:
1709 break;
1710
H. Peter Anvine2c80182005-01-15 22:15:51 +00001711 case 0340:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001712 if (ins->oprs[0].segment != NO_SEG)
1713 errfunc(ERR_PANIC, "non-constant BSS size in pass two");
1714 else {
H. Peter Anvin428fd672007-11-15 10:25:52 -08001715 int64_t size = ins->oprs[0].offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001716 if (size > 0)
1717 out(offset, segment, NULL,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001718 OUT_RESERVE, size, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001719 offset += size;
1720 }
1721 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001722
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001723 case 0360:
1724 break;
1725
1726 case 0361:
1727 bytes[0] = 0x66;
1728 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1729 offset += 1;
1730 break;
1731
1732 case 0362:
1733 case 0363:
1734 bytes[0] = c - 0362 + 0xf2;
1735 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1736 offset += 1;
1737 break;
1738
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001739 case 0364:
1740 case 0365:
1741 break;
1742
Keith Kanios48af1772007-08-17 07:37:52 +00001743 case 0366:
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001744 case 0367:
1745 *bytes = c - 0366 + 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001746 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
Keith Kanios48af1772007-08-17 07:37:52 +00001747 offset += 1;
1748 break;
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001749
H. Peter Anvine2c80182005-01-15 22:15:51 +00001750 case 0370:
1751 case 0371:
1752 case 0372:
1753 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001754
H. Peter Anvine2c80182005-01-15 22:15:51 +00001755 case 0373:
1756 *bytes = bits == 16 ? 3 : 5;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001757 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001758 offset += 1;
1759 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001760
H. Peter Anvine2c80182005-01-15 22:15:51 +00001761 default: /* can't do it by 'case' statements */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001762 if (c >= 0100 && c <= 0277) { /* it's an EA */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001763 ea ea_data;
1764 int rfield;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001765 int32_t rflags;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001766 uint8_t *p;
1767 int32_t s;
H. Peter Anvin70653092007-10-19 14:42:29 -07001768
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001769 if (c <= 0177) {
1770 /* pick rfield from operand b */
1771 rflags = regflag(&ins->oprs[c & 7]);
H. Peter Anvina4835d42008-05-20 14:21:29 -07001772 rfield = nasm_regvals[ins->oprs[c & 7].basereg];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001773 } else {
1774 /* rfield is constant */
1775 rflags = 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001776 rfield = c & 7;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001777 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001778
1779 if (!process_ea
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001780 (&ins->oprs[(c >> 3) & 7], &ea_data, bits,
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001781 ins->addr_size, rfield, rflags, ins->forw_ref)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001782 errfunc(ERR_NONFATAL, "invalid effective address");
1783 }
H. Peter Anvin70653092007-10-19 14:42:29 -07001784
Charles Crayne7e975552007-11-03 22:06:13 -07001785
H. Peter Anvine2c80182005-01-15 22:15:51 +00001786 p = bytes;
1787 *p++ = ea_data.modrm;
1788 if (ea_data.sib_present)
1789 *p++ = ea_data.sib;
1790
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001791 /* DREX suffixes come between the SIB and the displacement */
1792 if (ins->rex & REX_D) {
1793 *p++ =
1794 (ins->drexdst << 4) |
1795 (ins->rex & REX_OC ? 0x08 : 0) |
1796 (ins->rex & (REX_R|REX_X|REX_B));
1797 ins->rex = 0;
1798 }
1799
H. Peter Anvine2c80182005-01-15 22:15:51 +00001800 s = p - bytes;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001801 out(offset, segment, bytes, OUT_RAWDATA, s, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001802
1803 switch (ea_data.bytes) {
1804 case 0:
1805 break;
1806 case 1:
1807 if (ins->oprs[(c >> 3) & 7].segment != NO_SEG) {
1808 data = ins->oprs[(c >> 3) & 7].offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001809 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001810 ins->oprs[(c >> 3) & 7].segment,
1811 ins->oprs[(c >> 3) & 7].wrt);
1812 } else {
1813 *bytes = ins->oprs[(c >> 3) & 7].offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001814 out(offset, segment, bytes, OUT_RAWDATA, 1,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001815 NO_SEG, NO_SEG);
1816 }
1817 s++;
1818 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001819 case 8:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001820 case 2:
1821 case 4:
1822 data = ins->oprs[(c >> 3) & 7].offset;
Charles Crayne7e975552007-11-03 22:06:13 -07001823 warn_overflow(ea_data.bytes, data);
H. Peter Anvind0b0d282007-09-28 17:17:20 -07001824 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001825 ea_data.rip ? OUT_REL4ADR : OUT_ADDRESS,
1826 ea_data.bytes,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001827 ins->oprs[(c >> 3) & 7].segment,
1828 ins->oprs[(c >> 3) & 7].wrt);
1829 s += ea_data.bytes;
1830 break;
1831 }
1832 offset += s;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001833 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001834 errfunc(ERR_PANIC, "internal instruction table corrupt"
1835 ": instruction code 0x%02X given", c);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001836 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001837 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001838 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001839}
1840
H. Peter Anvin0ec60e62007-07-07 01:59:52 +00001841static int32_t regflag(const operand * o)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001842{
1843 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1844 errfunc(ERR_PANIC, "invalid operand passed to regflag()");
1845 }
H. Peter Anvina4835d42008-05-20 14:21:29 -07001846 return nasm_reg_flags[o->basereg];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001847}
1848
H. Peter Anvin5b0e3ec2007-07-07 02:01:08 +00001849static int32_t regval(const operand * o)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001850{
H. Peter Anvine2c80182005-01-15 22:15:51 +00001851 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1852 errfunc(ERR_PANIC, "invalid operand passed to regval()");
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001853 }
H. Peter Anvina4835d42008-05-20 14:21:29 -07001854 return nasm_regvals[o->basereg];
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001855}
1856
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001857static int op_rexflags(const operand * o, int mask)
1858{
1859 int32_t flags;
1860 int val;
1861
1862 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1863 errfunc(ERR_PANIC, "invalid operand passed to op_rexflags()");
1864 }
1865
H. Peter Anvina4835d42008-05-20 14:21:29 -07001866 flags = nasm_reg_flags[o->basereg];
1867 val = nasm_regvals[o->basereg];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001868
1869 return rexflags(val, flags, mask);
1870}
1871
1872static int rexflags(int val, int32_t flags, int mask)
1873{
1874 int rex = 0;
1875
1876 if (val >= 8)
1877 rex |= REX_B|REX_X|REX_R;
1878 if (flags & BITS64)
1879 rex |= REX_W;
1880 if (!(REG_HIGH & ~flags)) /* AH, CH, DH, BH */
1881 rex |= REX_H;
1882 else if (!(REG8 & ~flags) && val >= 4) /* SPL, BPL, SIL, DIL */
1883 rex |= REX_P;
1884
1885 return rex & mask;
1886}
1887
H. Peter Anvin3360d792007-09-11 04:16:57 +00001888static int matches(const struct itemplate *itemp, insn * instruction, int bits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001889{
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001890 int i, size[MAX_OPERANDS], asize, oprs, ret;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001891
1892 ret = 100;
1893
1894 /*
1895 * Check the opcode
1896 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001897 if (itemp->opcode != instruction->opcode)
1898 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001899
1900 /*
1901 * Count the operands
1902 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001903 if (itemp->operands != instruction->operands)
1904 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001905
1906 /*
1907 * Check that no spurious colons or TOs are present
1908 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001909 for (i = 0; i < itemp->operands; i++)
1910 if (instruction->oprs[i].type & ~itemp->opd[i] & (COLON | TO))
1911 return 0;
H. Peter Anvin70653092007-10-19 14:42:29 -07001912
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001913 /*
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001914 * Process size flags
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001915 */
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001916 if (itemp->flags & IF_ARMASK) {
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001917 memset(size, 0, sizeof size);
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001918
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001919 i = ((itemp->flags & IF_ARMASK) >> IF_ARSHFT) - 1;
1920
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001921 switch (itemp->flags & IF_SMASK) {
1922 case IF_SB:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001923 size[i] = BITS8;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001924 break;
1925 case IF_SW:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001926 size[i] = BITS16;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001927 break;
1928 case IF_SD:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001929 size[i] = BITS32;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001930 break;
1931 case IF_SQ:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001932 size[i] = BITS64;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001933 break;
H. Peter Anvin41c9f6f2007-09-18 13:01:32 -07001934 case IF_SO:
1935 size[i] = BITS128;
1936 break;
H. Peter Anvindfb91802008-05-20 11:43:53 -07001937 case IF_SY:
1938 size[i] = BITS256;
1939 break;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001940 case IF_SZ:
1941 switch (bits) {
1942 case 16:
1943 size[i] = BITS16;
1944 break;
1945 case 32:
1946 size[i] = BITS32;
1947 break;
1948 case 64:
1949 size[i] = BITS64;
1950 break;
1951 }
1952 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001953 default:
1954 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001955 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001956 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001957 asize = 0;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001958 switch (itemp->flags & IF_SMASK) {
1959 case IF_SB:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001960 asize = BITS8;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001961 break;
1962 case IF_SW:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001963 asize = BITS16;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001964 break;
1965 case IF_SD:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001966 asize = BITS32;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001967 break;
1968 case IF_SQ:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001969 asize = BITS64;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001970 break;
H. Peter Anvin41c9f6f2007-09-18 13:01:32 -07001971 case IF_SO:
1972 asize = BITS128;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001973 break;
H. Peter Anvindfb91802008-05-20 11:43:53 -07001974 case IF_SY:
1975 asize = BITS256;
1976 break;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001977 case IF_SZ:
1978 switch (bits) {
1979 case 16:
1980 asize = BITS16;
1981 break;
1982 case 32:
1983 asize = BITS32;
1984 break;
1985 case 64:
1986 asize = BITS64;
1987 break;
1988 }
H. Peter Anvin41c9f6f2007-09-18 13:01:32 -07001989 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001990 default:
1991 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001992 }
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001993 for (i = 0; i < MAX_OPERANDS; i++)
1994 size[i] = asize;
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001995 }
H. Peter Anvin70653092007-10-19 14:42:29 -07001996
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001997 /*
1998 * Check that the operand flags all match up
1999 */
2000 for (i = 0; i < itemp->operands; i++) {
2001 int32_t type = instruction->oprs[i].type;
2002 if (!(type & SIZE_MASK))
2003 type |= size[i];
H. Peter Anvind85d2502008-05-04 17:53:31 -07002004
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002005 if (itemp->opd[i] & SAME_AS) {
2006 int j = itemp->opd[i] & ~SAME_AS;
2007 if (type != instruction->oprs[j].type ||
2008 instruction->oprs[i].basereg != instruction->oprs[j].basereg)
2009 return 0;
2010 } else if (itemp->opd[i] & ~type ||
2011 ((itemp->opd[i] & SIZE_MASK) &&
2012 ((itemp->opd[i] ^ type) & SIZE_MASK))) {
2013 if ((itemp->opd[i] & ~type & ~SIZE_MASK) ||
2014 (type & SIZE_MASK))
2015 return 0;
2016 else
2017 return 1;
2018 }
2019 }
2020
2021 /*
2022 * Check operand sizes
2023 */
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002024 if (itemp->flags & (IF_SM | IF_SM2)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002025 oprs = (itemp->flags & IF_SM2 ? 2 : itemp->operands);
2026 asize = 0;
2027 for (i = 0; i < oprs; i++) {
2028 if ((asize = itemp->opd[i] & SIZE_MASK) != 0) {
2029 int j;
2030 for (j = 0; j < oprs; j++)
2031 size[j] = asize;
2032 break;
2033 }
2034 }
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002035 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002036 oprs = itemp->operands;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002037 }
2038
Keith Kaniosb7a89542007-04-12 02:40:54 +00002039 for (i = 0; i < itemp->operands; i++) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002040 if (!(itemp->opd[i] & SIZE_MASK) &&
2041 (instruction->oprs[i].type & SIZE_MASK & ~size[i]))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002042 return 2;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002043 }
2044
H. Peter Anvinaf535c12002-04-30 20:59:21 +00002045 /*
2046 * Check template is okay at the set cpu level
2047 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002048 if (((itemp->flags & IF_PLEVEL) > cpu))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002049 return 3;
H. Peter Anvin70653092007-10-19 14:42:29 -07002050
Keith Kaniosb7a89542007-04-12 02:40:54 +00002051 /*
2052 * Check if instruction is available in long mode
2053 */
2054 if ((itemp->flags & IF_NOLONG) && (bits == 64))
2055 return 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002056
H. Peter Anvinaf535c12002-04-30 20:59:21 +00002057 /*
2058 * Check if special handling needed for Jumps
2059 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002060 if ((uint8_t)(itemp->code[0]) >= 0370)
H. Peter Anvine2c80182005-01-15 22:15:51 +00002061 return 99;
2062
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002063 return ret;
2064}
2065
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002066static ea *process_ea(operand * input, ea * output, int bits,
2067 int addrbits, int rfield, int32_t rflags, int forw_ref)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002068{
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002069 output->rip = false;
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00002070
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002071 /* REX flags for the rfield operand */
2072 output->rex |= rexflags(rfield, rflags, REX_R|REX_P|REX_W|REX_H);
2073
Keith Kaniosb7a89542007-04-12 02:40:54 +00002074 if (!(REGISTER & ~input->type)) { /* register direct */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002075 int i;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002076 int32_t f;
2077
2078 if (input->basereg < EXPR_REG_START /* Verify as Register */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002079 || input->basereg >= REG_ENUM_LIMIT)
H. Peter Anvine2c80182005-01-15 22:15:51 +00002080 return NULL;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002081 f = regflag(input);
H. Peter Anvina4835d42008-05-20 14:21:29 -07002082 i = nasm_regvals[input->basereg];
Keith Kaniosb7a89542007-04-12 02:40:54 +00002083
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002084 if (REG_EA & ~f)
2085 return NULL; /* Invalid EA register */
H. Peter Anvin70653092007-10-19 14:42:29 -07002086
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002087 output->rex |= op_rexflags(input, REX_B|REX_P|REX_W|REX_H);
2088
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002089 output->sib_present = false; /* no SIB necessary */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002090 output->bytes = 0; /* no offset necessary either */
2091 output->modrm = 0xC0 | ((rfield & 7) << 3) | (i & 7);
H. Peter Anvine2c80182005-01-15 22:15:51 +00002092 } else { /* it's a memory reference */
2093 if (input->basereg == -1
2094 && (input->indexreg == -1 || input->scale == 0)) {
2095 /* it's a pure offset */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002096 if (bits == 64 && (~input->type & IP_REL)) {
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002097 int scale, index, base;
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002098 output->sib_present = true;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002099 scale = 0;
2100 index = 4;
2101 base = 5;
2102 output->sib = (scale << 6) | (index << 3) | base;
2103 output->bytes = 4;
2104 output->modrm = 4 | ((rfield & 7) << 3);
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002105 output->rip = false;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002106 } else {
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002107 output->sib_present = false;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002108 output->bytes = (addrbits != 16 ? 4 : 2);
2109 output->modrm = (addrbits != 16 ? 5 : 6) | ((rfield & 7) << 3);
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002110 output->rip = bits == 64;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002111 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00002112 } else { /* it's an indirection */
2113 int i = input->indexreg, b = input->basereg, s = input->scale;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002114 int32_t o = input->offset, seg = input->segment;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002115 int hb = input->hintbase, ht = input->hinttype;
2116 int t;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002117 int it, bt;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002118 int32_t ix, bx; /* register flags */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002119
H. Peter Anvine2c80182005-01-15 22:15:51 +00002120 if (s == 0)
2121 i = -1; /* make this easy, at least */
H. Peter Anvin70653092007-10-19 14:42:29 -07002122
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002123 if (i >= EXPR_REG_START && i < REG_ENUM_LIMIT) {
H. Peter Anvina4835d42008-05-20 14:21:29 -07002124 it = nasm_regvals[i];
2125 ix = nasm_reg_flags[i];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002126 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002127 it = -1;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002128 ix = 0;
2129 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002130
H. Peter Anvinb0c54622007-10-28 23:21:46 -07002131 if (b >= EXPR_REG_START && b < REG_ENUM_LIMIT) {
H. Peter Anvina4835d42008-05-20 14:21:29 -07002132 bt = nasm_regvals[b];
2133 bx = nasm_reg_flags[b];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002134 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002135 bt = -1;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002136 bx = 0;
2137 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002138
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002139 /* check for a 32/64-bit memory reference... */
2140 if ((ix|bx) & (BITS32|BITS64)) {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002141 /* it must be a 32/64-bit memory reference. Firstly we have
2142 * to check that all registers involved are type E/Rxx. */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002143 int32_t sok = BITS32|BITS64;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002144
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002145 if (it != -1) {
2146 if (!(REG64 & ~ix) || !(REG32 & ~ix))
2147 sok &= ix;
2148 else
2149 return NULL;
2150 }
2151
2152 if (bt != -1) {
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00002153 if (REG_GPR & ~bx)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002154 return NULL; /* Invalid register */
H. Peter Anvina57e8d42007-05-30 03:44:02 +00002155 if (~sok & bx & SIZE_MASK)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002156 return NULL; /* Invalid size */
H. Peter Anvinb0c54622007-10-28 23:21:46 -07002157 sok &= bx;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002158 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002159
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002160 /* While we're here, ensure the user didn't specify
2161 WORD or QWORD. */
2162 if (input->disp_size == 16 || input->disp_size == 64)
2163 return NULL;
2164
2165 if (addrbits == 16 ||
2166 (addrbits == 32 && !(sok & BITS32)) ||
2167 (addrbits == 64 && !(sok & BITS64)))
2168 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002169
Keith Kaniosb7a89542007-04-12 02:40:54 +00002170 /* now reorganize base/index */
2171 if (s == 1 && bt != it && bt != -1 && it != -1 &&
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002172 ((hb == b && ht == EAH_NOTBASE)
2173 || (hb == i && ht == EAH_MAKEBASE))) {
2174 /* swap if hints say so */
2175 t = bt, bt = it, it = t;
2176 t = bx, bx = ix, ix = t;
2177 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00002178 if (bt == it) /* convert EAX+2*EAX to 3*EAX */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002179 bt = -1, bx = 0, s++;
2180 if (bt == -1 && s == 1 && !(hb == it && ht == EAH_NOTBASE)) {
2181 /* make single reg base, unless hint */
2182 bt = it, bx = ix, it = -1, ix = 0;
2183 }
H. Peter Anvinf5843c62007-09-10 18:59:26 +00002184 if (((s == 2 && it != REG_NUM_ESP
H. Peter Anvine2c80182005-01-15 22:15:51 +00002185 && !(input->eaflags & EAF_TIMESTWO)) || s == 3
Keith Kaniosb7a89542007-04-12 02:40:54 +00002186 || s == 5 || s == 9) && bt == -1)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002187 bt = it, bx = ix, s--; /* convert 3*EAX to EAX+2*EAX */
Keith Kanios48af1772007-08-17 07:37:52 +00002188 if (it == -1 && (bt & 7) != REG_NUM_ESP
H. Peter Anvine2c80182005-01-15 22:15:51 +00002189 && (input->eaflags & EAF_TIMESTWO))
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002190 it = bt, ix = bx, bt = -1, bx = 0, s = 1;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002191 /* convert [NOSPLIT EAX] to sib format with 0x0 displacement */
Keith Kanios48af1772007-08-17 07:37:52 +00002192 if (s == 1 && it == REG_NUM_ESP) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002193 /* swap ESP into base if scale is 1 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002194 t = it, it = bt, bt = t;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002195 t = ix, ix = bx, bx = t;
2196 }
Keith Kanios48af1772007-08-17 07:37:52 +00002197 if (it == REG_NUM_ESP
Keith Kaniosb7a89542007-04-12 02:40:54 +00002198 || (s != 1 && s != 2 && s != 4 && s != 8 && it != -1))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002199 return NULL; /* wrong, for various reasons */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002200
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002201 output->rex |= rexflags(it, ix, REX_X);
2202 output->rex |= rexflags(bt, bx, REX_B);
Keith Kaniosb7a89542007-04-12 02:40:54 +00002203
Keith Kanios48af1772007-08-17 07:37:52 +00002204 if (it == -1 && (bt & 7) != REG_NUM_ESP) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002205 /* no SIB needed */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002206 int mod, rm;
H. Peter Anvin70653092007-10-19 14:42:29 -07002207
Keith Kaniosb7a89542007-04-12 02:40:54 +00002208 if (bt == -1) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002209 rm = 5;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002210 mod = 0;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002211 } else {
2212 rm = (bt & 7);
Keith Kanios48af1772007-08-17 07:37:52 +00002213 if (rm != REG_NUM_EBP && o == 0 &&
Keith Kaniosb7a89542007-04-12 02:40:54 +00002214 seg == NO_SEG && !forw_ref &&
2215 !(input->eaflags &
2216 (EAF_BYTEOFFS | EAF_WORDOFFS)))
2217 mod = 0;
2218 else if (input->eaflags & EAF_BYTEOFFS ||
2219 (o >= -128 && o <= 127 && seg == NO_SEG
2220 && !forw_ref
2221 && !(input->eaflags & EAF_WORDOFFS)))
2222 mod = 1;
2223 else
2224 mod = 2;
2225 }
H. Peter Anvinea838272002-04-30 20:51:53 +00002226
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002227 output->sib_present = false;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002228 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2229 output->modrm = (mod << 6) | ((rfield & 7) << 3) | rm;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002230 } else {
2231 /* we need a SIB */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002232 int mod, scale, index, base;
H. Peter Anvin70653092007-10-19 14:42:29 -07002233
Keith Kaniosb7a89542007-04-12 02:40:54 +00002234 if (it == -1)
2235 index = 4, s = 1;
2236 else
2237 index = (it & 7);
H. Peter Anvin70653092007-10-19 14:42:29 -07002238
H. Peter Anvine2c80182005-01-15 22:15:51 +00002239 switch (s) {
2240 case 1:
2241 scale = 0;
2242 break;
2243 case 2:
2244 scale = 1;
2245 break;
2246 case 4:
2247 scale = 2;
2248 break;
2249 case 8:
2250 scale = 3;
2251 break;
2252 default: /* then what the smeg is it? */
2253 return NULL; /* panic */
2254 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002255
Keith Kaniosb7a89542007-04-12 02:40:54 +00002256 if (bt == -1) {
2257 base = 5;
2258 mod = 0;
2259 } else {
2260 base = (bt & 7);
Keith Kanios48af1772007-08-17 07:37:52 +00002261 if (base != REG_NUM_EBP && o == 0 &&
H. Peter Anvine2c80182005-01-15 22:15:51 +00002262 seg == NO_SEG && !forw_ref &&
2263 !(input->eaflags &
Keith Kaniosb7a89542007-04-12 02:40:54 +00002264 (EAF_BYTEOFFS | EAF_WORDOFFS)))
2265 mod = 0;
2266 else if (input->eaflags & EAF_BYTEOFFS ||
2267 (o >= -128 && o <= 127 && seg == NO_SEG
2268 && !forw_ref
2269 && !(input->eaflags & EAF_WORDOFFS)))
2270 mod = 1;
2271 else
2272 mod = 2;
2273 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002274
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002275 output->sib_present = true;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002276 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2277 output->modrm = (mod << 6) | ((rfield & 7) << 3) | 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002278 output->sib = (scale << 6) | (index << 3) | base;
2279 }
2280 } else { /* it's 16-bit */
2281 int mod, rm;
H. Peter Anvin70653092007-10-19 14:42:29 -07002282
Keith Kaniosb7a89542007-04-12 02:40:54 +00002283 /* check for 64-bit long mode */
2284 if (addrbits == 64)
2285 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002286
H. Peter Anvine2c80182005-01-15 22:15:51 +00002287 /* check all registers are BX, BP, SI or DI */
2288 if ((b != -1 && b != R_BP && b != R_BX && b != R_SI
2289 && b != R_DI) || (i != -1 && i != R_BP && i != R_BX
2290 && i != R_SI && i != R_DI))
2291 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002292
Keith Kaniosb7a89542007-04-12 02:40:54 +00002293 /* ensure the user didn't specify DWORD/QWORD */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002294 if (input->disp_size == 32 || input->disp_size == 64)
H. Peter Anvine2c80182005-01-15 22:15:51 +00002295 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002296
H. Peter Anvine2c80182005-01-15 22:15:51 +00002297 if (s != 1 && i != -1)
2298 return NULL; /* no can do, in 16-bit EA */
2299 if (b == -1 && i != -1) {
2300 int tmp = b;
2301 b = i;
2302 i = tmp;
2303 } /* swap */
2304 if ((b == R_SI || b == R_DI) && i != -1) {
2305 int tmp = b;
2306 b = i;
2307 i = tmp;
2308 }
2309 /* have BX/BP as base, SI/DI index */
2310 if (b == i)
2311 return NULL; /* shouldn't ever happen, in theory */
2312 if (i != -1 && b != -1 &&
2313 (i == R_BP || i == R_BX || b == R_SI || b == R_DI))
2314 return NULL; /* invalid combinations */
2315 if (b == -1) /* pure offset: handled above */
2316 return NULL; /* so if it gets to here, panic! */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002317
H. Peter Anvine2c80182005-01-15 22:15:51 +00002318 rm = -1;
2319 if (i != -1)
2320 switch (i * 256 + b) {
2321 case R_SI * 256 + R_BX:
2322 rm = 0;
2323 break;
2324 case R_DI * 256 + R_BX:
2325 rm = 1;
2326 break;
2327 case R_SI * 256 + R_BP:
2328 rm = 2;
2329 break;
2330 case R_DI * 256 + R_BP:
2331 rm = 3;
2332 break;
2333 } else
2334 switch (b) {
2335 case R_SI:
2336 rm = 4;
2337 break;
2338 case R_DI:
2339 rm = 5;
2340 break;
2341 case R_BP:
2342 rm = 6;
2343 break;
2344 case R_BX:
2345 rm = 7;
2346 break;
2347 }
2348 if (rm == -1) /* can't happen, in theory */
2349 return NULL; /* so panic if it does */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002350
H. Peter Anvine2c80182005-01-15 22:15:51 +00002351 if (o == 0 && seg == NO_SEG && !forw_ref && rm != 6 &&
2352 !(input->eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS)))
2353 mod = 0;
2354 else if (input->eaflags & EAF_BYTEOFFS ||
2355 (o >= -128 && o <= 127 && seg == NO_SEG
2356 && !forw_ref
2357 && !(input->eaflags & EAF_WORDOFFS)))
2358 mod = 1;
2359 else
2360 mod = 2;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002361
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002362 output->sib_present = false; /* no SIB - it's 16-bit */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002363 output->bytes = mod; /* bytes of offset needed */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002364 output->modrm = (mod << 6) | ((rfield & 7) << 3) | rm;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002365 }
2366 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002367 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002368
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002369 output->size = 1 + output->sib_present + output->bytes;
2370 return output;
2371}
2372
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002373static void add_asp(insn *ins, int addrbits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002374{
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002375 int j, valid;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002376 int defdisp;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002377
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002378 valid = (addrbits == 64) ? 64|32 : 32|16;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002379
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002380 switch (ins->prefixes[PPS_ASIZE]) {
2381 case P_A16:
2382 valid &= 16;
2383 break;
2384 case P_A32:
2385 valid &= 32;
2386 break;
2387 case P_A64:
2388 valid &= 64;
2389 break;
2390 case P_ASP:
2391 valid &= (addrbits == 32) ? 16 : 32;
2392 break;
2393 default:
2394 break;
2395 }
2396
2397 for (j = 0; j < ins->operands; j++) {
2398 if (!(MEMORY & ~ins->oprs[j].type)) {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002399 int32_t i, b;
H. Peter Anvin70653092007-10-19 14:42:29 -07002400
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002401 /* Verify as Register */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002402 if (ins->oprs[j].indexreg < EXPR_REG_START
2403 || ins->oprs[j].indexreg >= REG_ENUM_LIMIT)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002404 i = 0;
2405 else
H. Peter Anvina4835d42008-05-20 14:21:29 -07002406 i = nasm_reg_flags[ins->oprs[j].indexreg];
H. Peter Anvin70653092007-10-19 14:42:29 -07002407
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002408 /* Verify as Register */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002409 if (ins->oprs[j].basereg < EXPR_REG_START
2410 || ins->oprs[j].basereg >= REG_ENUM_LIMIT)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002411 b = 0;
2412 else
H. Peter Anvina4835d42008-05-20 14:21:29 -07002413 b = nasm_reg_flags[ins->oprs[j].basereg];
H. Peter Anvin70653092007-10-19 14:42:29 -07002414
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002415 if (ins->oprs[j].scale == 0)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002416 i = 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002417
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002418 if (!i && !b) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002419 int ds = ins->oprs[j].disp_size;
2420 if ((addrbits != 64 && ds > 8) ||
2421 (addrbits == 64 && ds == 16))
2422 valid &= ds;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002423 } else {
2424 if (!(REG16 & ~b))
2425 valid &= 16;
2426 if (!(REG32 & ~b))
2427 valid &= 32;
2428 if (!(REG64 & ~b))
2429 valid &= 64;
H. Peter Anvin70653092007-10-19 14:42:29 -07002430
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002431 if (!(REG16 & ~i))
2432 valid &= 16;
2433 if (!(REG32 & ~i))
2434 valid &= 32;
2435 if (!(REG64 & ~i))
2436 valid &= 64;
2437 }
2438 }
2439 }
2440
2441 if (valid & addrbits) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002442 ins->addr_size = addrbits;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002443 } else if (valid & ((addrbits == 32) ? 16 : 32)) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002444 /* Add an address size prefix */
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002445 enum prefixes pref = (addrbits == 32) ? P_A16 : P_A32;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002446 ins->prefixes[PPS_ASIZE] = pref;
2447 ins->addr_size = (addrbits == 32) ? 16 : 32;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002448 } else {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002449 /* Impossible... */
2450 errfunc(ERR_NONFATAL, "impossible combination of address sizes");
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002451 ins->addr_size = addrbits; /* Error recovery */
2452 }
2453
2454 defdisp = ins->addr_size == 16 ? 16 : 32;
2455
2456 for (j = 0; j < ins->operands; j++) {
2457 if (!(MEM_OFFS & ~ins->oprs[j].type) &&
2458 (ins->oprs[j].disp_size ? ins->oprs[j].disp_size : defdisp)
2459 != ins->addr_size) {
2460 /* mem_offs sizes must match the address size; if not,
2461 strip the MEM_OFFS bit and match only EA instructions */
2462 ins->oprs[j].type &= ~(MEM_OFFS & ~MEMORY);
2463 }
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002464 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002465}