blob: f0253606d8590b54e4c498840a8b54b7ba4b3052 [file] [log] [blame]
H. Peter Anvin9e6747c2009-06-28 17:13:04 -07001/* ----------------------------------------------------------------------- *
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002 *
H. Peter Anvin4ecd5d72012-02-24 21:51:46 -08003 * Copyright 1996-2012 The NASM Authors - All Rights Reserved
H. Peter Anvin9e6747c2009-06-28 17:13:04 -07004 * See the file AUTHORS included with the NASM distribution for
5 * the specific copyright holders.
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00006 *
H. Peter Anvin9e6747c2009-06-28 17:13:04 -07007 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following
9 * conditions are met:
10 *
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
Cyrill Gorcunov1de95002009-11-06 00:08:38 +030017 *
H. Peter Anvin9e6747c2009-06-28 17:13:04 -070018 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
19 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
20 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 * ----------------------------------------------------------------------- */
33
34/*
35 * assemble.c code generation for the Netwide Assembler
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000036 *
37 * the actual codes (C syntax, i.e. octal):
38 * \0 - terminates the code. (Unless it's a literal of course.)
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +040039 * \1..\4 - that many literal bytes follow in the code stream
H. Peter Anvindcffe4b2008-10-10 22:10:31 -070040 * \5 - add 4 to the primary operand number (b, low octdigit)
41 * \6 - add 4 to the secondary operand number (a, middle octdigit)
42 * \7 - add 4 to both the primary and the secondary operand number
H. Peter Anvin7eb4a382007-09-17 15:49:30 -070043 * \10..\13 - a literal byte follows in the code stream, to be added
44 * to the register value of operand 0..3
H. Peter Anvin7eb4a382007-09-17 15:49:30 -070045 * \20..\23 - a byte immediate operand, from operand 0..3
Ben Rudiak-Gould4e8396b2013-03-01 10:28:32 +040046 * \24..\27 - a zero-extended byte immediate operand, from operand 0..3
H. Peter Anvin7eb4a382007-09-17 15:49:30 -070047 * \30..\33 - a word immediate operand, from operand 0..3
48 * \34..\37 - select between \3[0-3] and \4[0-3] depending on 16/32 bit
H. Peter Anvin3ba46772002-05-27 23:19:35 +000049 * assembly mode or the operand-size override on the operand
H. Peter Anvin7eb4a382007-09-17 15:49:30 -070050 * \40..\43 - a long immediate operand, from operand 0..3
51 * \44..\47 - select between \3[0-3], \4[0-3] and \5[4-7]
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +040052 * depending on the address size of the instruction.
H. Peter Anvin7eb4a382007-09-17 15:49:30 -070053 * \50..\53 - a byte relative operand, from operand 0..3
54 * \54..\57 - a qword immediate operand, from operand 0..3
55 * \60..\63 - a word relative operand, from operand 0..3
56 * \64..\67 - select between \6[0-3] and \7[0-3] depending on 16/32 bit
H. Peter Anvin17799b42002-05-21 03:31:21 +000057 * assembly mode or the operand-size override on the operand
H. Peter Anvin7eb4a382007-09-17 15:49:30 -070058 * \70..\73 - a long relative operand, from operand 0..3
H. Peter Anvinc1377e92008-10-06 23:40:31 -070059 * \74..\77 - a word constant, from the _segment_ part of operand 0..3
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000060 * \1ab - a ModRM, calculated on EA in operand a, with the spare
61 * field the register value of operand b.
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +040062 * \172\ab - the register number from operand a in bits 7..4, with
H. Peter Anvin52dc3532008-05-20 19:29:04 -070063 * the 4-bit immediate from operand b in bits 3..0.
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +040064 * \173\xab - the register number from operand a in bits 7..4, with
65 * the value b in bits 3..0.
H. Peter Anvincffe61e2011-07-07 17:21:24 -070066 * \174..\177 - the register number from operand 0..3 in bits 7..4, and
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +040067 * an arbitrary value in bits 3..0 (assembled as zero.)
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000068 * \2ab - a ModRM, calculated on EA in operand a, with the spare
69 * field equal to digit b.
H. Peter Anvin588df782008-10-07 10:05:10 -070070 * \254..\257 - a signed 32-bit operand to be extended to 64 bits.
H. Peter Anvina04019c2009-05-03 21:42:34 -070071 * \260..\263 - this instruction uses VEX/XOP rather than REX, with the
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +040072 * V field taken from operand 0..3.
73 * \270 - this instruction uses VEX/XOP rather than REX, with the
74 * V field set to 1111b.
H. Peter Anvind85d2502008-05-04 17:53:31 -070075 *
H. Peter Anvina04019c2009-05-03 21:42:34 -070076 * VEX/XOP prefixes are followed by the sequence:
77 * \tmm\wlp where mm is the M field; and wlp is:
H. Peter Anvin421059c2010-08-16 14:56:33 -070078 * 00 wwl lpp
79 * [l0] ll = 0 for L = 0 (.128, .lz)
80 * [l1] ll = 1 for L = 1 (.256)
81 * [lig] ll = 2 for L don't care (always assembled as 0)
82 *
H. Peter Anvin978c2172010-08-16 13:48:43 -070083 * [w0] ww = 0 for W = 0
84 * [w1 ] ww = 1 for W = 1
85 * [wig] ww = 2 for W don't care (always assembled as 0)
86 * [ww] ww = 3 for W used as REX.W
H. Peter Anvinbd420c72008-05-22 11:24:35 -070087 *
H. Peter Anvina04019c2009-05-03 21:42:34 -070088 * t = 0 for VEX (C4/C5), t = 1 for XOP (8F).
H. Peter Anvind85d2502008-05-04 17:53:31 -070089 *
H. Peter Anvin574784d2012-02-25 22:33:46 -080090 * \271 - instruction takes XRELEASE (F3) with or without lock
91 * \272 - instruction takes XACQUIRE/XRELEASE with or without lock
92 * \273 - instruction takes XACQUIRE/XRELEASE with lock only
Ben Rudiak-Gould4e8396b2013-03-01 10:28:32 +040093 * \274..\277 - a byte immediate operand, from operand 0..3, sign-extended
94 * to the operand size (if o16/o32/o64 present) or the bit size
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000095 * \310 - indicates fixed 16-bit address size, i.e. optional 0x67.
96 * \311 - indicates fixed 32-bit address size, i.e. optional 0x67.
H. Peter Anvind28f07f2009-06-26 16:18:00 -070097 * \312 - (disassembler only) invalid with non-default address size.
H. Peter Anvince2b3972007-05-30 22:21:11 +000098 * \313 - indicates fixed 64-bit address size, 0x67 invalid.
H. Peter Anvin23440102007-11-12 21:02:33 -080099 * \314 - (disassembler only) invalid with REX.B
100 * \315 - (disassembler only) invalid with REX.X
101 * \316 - (disassembler only) invalid with REX.R
102 * \317 - (disassembler only) invalid with REX.W
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000103 * \320 - indicates fixed 16-bit operand size, i.e. optional 0x66.
104 * \321 - indicates fixed 32-bit operand size, i.e. optional 0x66.
105 * \322 - indicates that this instruction is only valid when the
106 * operand size is the default (instruction to disassembler,
107 * generates no code in the assembler)
H. Peter Anvince2b3972007-05-30 22:21:11 +0000108 * \323 - indicates fixed 64-bit operand size, REX on extensions only.
Keith Kaniosb7a89542007-04-12 02:40:54 +0000109 * \324 - indicates 64-bit operand size requiring REX prefix.
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400110 * \325 - instruction which always uses spl/bpl/sil/dil
Ben Rudiak-Gouldd7ab1f92013-02-20 23:25:54 +0400111 * \326 - instruction not valid with 0xF3 REP prefix. Hint for
112 disassembler only; for SSE instructions.
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000113 * \330 - a literal byte follows in the code stream, to be added
114 * to the condition code value of the instruction.
Keith Kanios48af1772007-08-17 07:37:52 +0000115 * \331 - instruction not valid with REP prefix. Hint for
H. Peter Anvinef7468f2002-04-30 20:57:59 +0000116 * disassembler only; for SSE instructions.
H. Peter Anvincb9b6902007-09-12 21:58:51 -0700117 * \332 - REP prefix (0xF2 byte) used as opcode extension.
118 * \333 - REP prefix (0xF3 byte) used as opcode extension.
H. Peter Anvin9472dab2009-06-24 21:38:29 -0700119 * \334 - LOCK prefix used as REX.R (used in non-64-bit mode)
H. Peter Anvincb9b6902007-09-12 21:58:51 -0700120 * \335 - disassemble a rep (0xF3 byte) prefix as repe not rep.
H. Peter Anvin755f5212012-02-25 11:41:34 -0800121 * \336 - force a REP(E) prefix (0xF3) even if not specified.
122 * \337 - force a REPNE prefix (0xF2) even if not specified.
H. Peter Anvin962e3052008-08-28 17:47:16 -0700123 * \336-\337 are still listed as prefixes in the disassembler.
Keith Kaniosb7a89542007-04-12 02:40:54 +0000124 * \340 - reserve <operand 0> bytes of uninitialized storage.
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000125 * Operand 0 had better be a segmentless constant.
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400126 * \341 - this instruction needs a WAIT "prefix"
H. Peter Anvinff6e12d2008-10-08 21:17:32 -0700127 * \344,\345 - the PUSH/POP (respectively) codes for CS, DS, ES, SS
128 * (POP is never used for CS) depending on operand 0
129 * \346,\347 - the second byte of PUSH/POP codes for FS, GS, depending
130 * on operand 0
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400131 * \360 - no SSE prefix (== \364\331)
H. Peter Anvinfff5a472008-05-20 09:46:24 -0700132 * \361 - 66 SSE prefix (== \366\331)
133 * \362 - F2 SSE prefix (== \364\332)
134 * \363 - F3 SSE prefix (== \364\333)
H. Peter Anvin62cb6062007-09-11 22:44:03 +0000135 * \364 - operand-size prefix (0x66) not permitted
136 * \365 - address-size prefix (0x67) not permitted
137 * \366 - operand-size prefix (0x66) used as opcode extension
138 * \367 - address-size prefix (0x67) used as opcode extension
H. Peter Anvin755f5212012-02-25 11:41:34 -0800139 * \370,\371 - match only if operand 0 meets byte jump criteria.
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400140 * 370 is used for Jcc, 371 is used for JMP.
141 * \373 - assemble 0x03 if bits==16, 0x05 if bits==32;
142 * used for conditional jump over longer jump
H. Peter Anvin3089f7e2011-06-22 18:19:28 -0700143 * \374 - this instruction takes an XMM VSIB memory EA
144 * \375 - this instruction takes an YMM VSIB memory EA
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000145 */
146
H. Peter Anvinfe501952007-10-02 21:53:51 -0700147#include "compiler.h"
148
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000149#include <stdio.h>
150#include <string.h>
Keith Kaniosb7a89542007-04-12 02:40:54 +0000151#include <inttypes.h>
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000152
153#include "nasm.h"
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000154#include "nasmlib.h"
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000155#include "assemble.h"
156#include "insns.h"
H. Peter Anvina4835d42008-05-20 14:21:29 -0700157#include "tables.h"
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000158
H. Peter Anvin65289e82009-07-25 17:25:11 -0700159enum match_result {
160 /*
161 * Matching errors. These should be sorted so that more specific
162 * errors come later in the sequence.
163 */
164 MERR_INVALOP,
165 MERR_OPSIZEMISSING,
166 MERR_OPSIZEMISMATCH,
167 MERR_BADCPU,
168 MERR_BADMODE,
H. Peter Anvinfb3f4e62012-02-25 22:22:07 -0800169 MERR_BADHLE,
H. Peter Anvin65289e82009-07-25 17:25:11 -0700170 /*
171 * Matching success; the conditional ones first
172 */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400173 MOK_JUMP, /* Matching OK but needs jmp_match() */
174 MOK_GOOD /* Matching unconditionally OK */
H. Peter Anvin65289e82009-07-25 17:25:11 -0700175};
176
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000177typedef struct {
H. Peter Anvin3089f7e2011-06-22 18:19:28 -0700178 enum ea_type type; /* what kind of EA is this? */
179 int sib_present; /* is a SIB byte necessary? */
180 int bytes; /* # of bytes of offset needed */
181 int size; /* lazy - this is sib+bytes+1 */
182 uint8_t modrm, sib, rex, rip; /* the bytes themselves */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000183} ea;
184
Cyrill Gorcunov10734c72011-08-29 00:07:17 +0400185#define GEN_SIB(scale, index, base) \
186 (((scale) << 6) | ((index) << 3) | ((base)))
187
188#define GEN_MODRM(mod, reg, rm) \
189 (((mod) << 6) | (((reg) & 7) << 3) | ((rm) & 7))
190
Keith Kaniosb7a89542007-04-12 02:40:54 +0000191static uint32_t cpu; /* cpu level received from nasm.c */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000192static efunc errfunc;
193static struct ofmt *outfmt;
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000194static ListGen *list;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000195
H. Peter Anvin8cc8a1d2012-02-25 11:11:42 -0800196static int64_t calcsize(int32_t, int64_t, int, insn *,
197 const struct itemplate *);
H. Peter Anvin833caea2008-10-04 19:02:30 -0700198static void gencode(int32_t segment, int64_t offset, int bits,
199 insn * ins, const struct itemplate *temp,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400200 int64_t insn_end);
H. Peter Anvin23595f52009-07-25 17:44:25 -0700201static enum match_result find_match(const struct itemplate **tempp,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400202 insn *instruction,
203 int32_t segment, int64_t offset, int bits);
H. Peter Anvin65289e82009-07-25 17:25:11 -0700204static enum match_result matches(const struct itemplate *, insn *, int bits);
H. Peter Anvinf8563f72009-10-13 12:28:14 -0700205static opflags_t regflag(const operand *);
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000206static int32_t regval(const operand *);
H. Peter Anvinf8563f72009-10-13 12:28:14 -0700207static int rexflags(int, opflags_t, int);
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000208static int op_rexflags(const operand *, int);
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700209static void add_asp(insn *, int);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000210
H. Peter Anvin3089f7e2011-06-22 18:19:28 -0700211static enum ea_type process_ea(operand *, ea *, int, int, int, opflags_t);
212
Cyrill Gorcunov18914e62011-11-12 11:41:51 +0400213static int has_prefix(insn * ins, enum prefix_pos pos, int prefix)
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000214{
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700215 return ins->prefixes[pos] == prefix;
216}
217
218static void assert_no_prefix(insn * ins, enum prefix_pos pos)
219{
220 if (ins->prefixes[pos])
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400221 errfunc(ERR_NONFATAL, "invalid %s prefix",
222 prefix_name(ins->prefixes[pos]));
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700223}
224
225static const char *size_name(int size)
226{
227 switch (size) {
228 case 1:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400229 return "byte";
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700230 case 2:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400231 return "word";
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700232 case 4:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400233 return "dword";
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700234 case 8:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400235 return "qword";
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700236 case 10:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400237 return "tword";
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700238 case 16:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400239 return "oword";
H. Peter Anvindfb91802008-05-20 11:43:53 -0700240 case 32:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400241 return "yword";
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700242 default:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400243 return "???";
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000244 }
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700245}
246
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +0400247static void warn_overflow(int pass, int size)
248{
249 errfunc(ERR_WARNING | pass | ERR_WARN_NOV,
250 "%s data exceeds bounds", size_name(size));
251}
252
253static void warn_overflow_const(int64_t data, int size)
254{
255 if (overflow_general(data, size))
256 warn_overflow(ERR_PASS1, size);
257}
258
259static void warn_overflow_opd(const struct operand *o, int size)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700260{
Victor van den Elzen0d268fb2010-01-24 21:24:57 +0100261 if (o->wrt == NO_SEG && o->segment == NO_SEG) {
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +0400262 if (overflow_general(o->offset, size))
263 warn_overflow(ERR_PASS2, size);
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700264 }
265}
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +0400266
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000267/*
268 * This routine wrappers the real output format's output routine,
269 * in order to pass a copy of the data off to the listing file
270 * generator at the same time.
271 */
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800272static void out(int64_t offset, int32_t segto, const void *data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800273 enum out_type type, uint64_t size,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400274 int32_t segment, int32_t wrt)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000275{
Keith Kaniosb7a89542007-04-12 02:40:54 +0000276 static int32_t lineno = 0; /* static!!! */
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000277 static char *lnfname = NULL;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800278 uint8_t p[8];
H. Peter Anvineba20a72002-04-30 20:53:55 +0000279
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800280 if (type == OUT_ADDRESS && segment == NO_SEG && wrt == NO_SEG) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400281 /*
282 * This is a non-relocated address, and we're going to
283 * convert it into RAWDATA format.
284 */
285 uint8_t *q = p;
H. Peter Anvind1fb15c2007-11-13 09:37:59 -0800286
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400287 if (size > 8) {
288 errfunc(ERR_PANIC, "OUT_ADDRESS with size > 8");
289 return;
290 }
H. Peter Anvind85d2502008-05-04 17:53:31 -0700291
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400292 WRITEADDR(q, *(int64_t *)data, size);
293 data = p;
294 type = OUT_RAWDATA;
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000295 }
296
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800297 list->output(offset, data, type, size);
298
Frank Kotlerabebb082003-09-06 04:45:37 +0000299 /*
300 * this call to src_get determines when we call the
301 * debug-format-specific "linenum" function
302 * it updates lineno and lnfname to the current values
303 * returning 0 if "same as last time", -2 if lnfname
304 * changed, and the amount by which lineno changed,
305 * if it did. thus, these variables must be static
306 */
307
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400308 if (src_get(&lineno, &lnfname))
H. Peter Anvine2c80182005-01-15 22:15:51 +0000309 outfmt->current_dfmt->linenum(lnfname, lineno, segto);
H. Peter Anvineba20a72002-04-30 20:53:55 +0000310
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800311 outfmt->output(segto, data, type, size, segment, wrt);
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000312}
313
Ben Rudiak-Gould4e8396b2013-03-01 10:28:32 +0400314static void out_imm8(int64_t offset, int32_t segment, struct operand *opx)
315{
316 if (opx->segment != NO_SEG) {
317 uint64_t data = opx->offset;
318 out(offset, segment, &data, OUT_ADDRESS, 1, opx->segment, opx->wrt);
319 } else {
320 uint8_t byte = opx->offset;
321 out(offset, segment, &byte, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
322 }
323}
324
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700325static bool jmp_match(int32_t segment, int64_t offset, int bits,
H. Peter Anvin8cc8a1d2012-02-25 11:11:42 -0800326 insn * ins, const struct itemplate *temp)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000327{
Charles Crayne5fbbc8c2007-11-07 19:03:46 -0800328 int64_t isize;
H. Peter Anvin8cc8a1d2012-02-25 11:11:42 -0800329 const uint8_t *code = temp->code;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000330 uint8_t c = code[0];
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000331
H. Peter Anvin755f5212012-02-25 11:41:34 -0800332 if (((c & ~1) != 0370) || (ins->oprs[0].type & STRICT))
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700333 return false;
334 if (!optimizing)
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400335 return false;
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700336 if (optimizing < 0 && c == 0371)
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400337 return false;
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700338
H. Peter Anvin8cc8a1d2012-02-25 11:11:42 -0800339 isize = calcsize(segment, offset, bits, ins, temp);
Victor van den Elzenccafc3c2009-02-23 04:35:00 +0100340
Victor van den Elzen154e5922009-02-25 17:32:00 +0100341 if (ins->oprs[0].opflags & OPFLAG_UNKNOWN)
Victor van den Elzenccafc3c2009-02-23 04:35:00 +0100342 /* Be optimistic in pass 1 */
343 return true;
344
H. Peter Anvine2c80182005-01-15 22:15:51 +0000345 if (ins->oprs[0].segment != segment)
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700346 return false;
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000347
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700348 isize = ins->oprs[0].offset - offset - isize; /* isize is delta */
349 return (isize >= -128 && isize <= 127); /* is it byte size? */
H. Peter Anvine2c80182005-01-15 22:15:51 +0000350}
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000351
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800352int64_t assemble(int32_t segment, int64_t offset, int bits, uint32_t cp,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400353 insn * instruction, struct ofmt *output, efunc error,
354 ListGen * listgen)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000355{
H. Peter Anvin3360d792007-09-11 04:16:57 +0000356 const struct itemplate *temp;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000357 int j;
H. Peter Anvin23595f52009-07-25 17:44:25 -0700358 enum match_result m;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800359 int64_t insn_end;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000360 int32_t itimes;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800361 int64_t start = offset;
Cyrill Gorcunovbafd8772009-10-31 20:02:14 +0300362 int64_t wsize; /* size for DB etc. */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000363
H. Peter Anvine2c80182005-01-15 22:15:51 +0000364 errfunc = error; /* to pass to other functions */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000365 cpu = cp;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000366 outfmt = output; /* likewise */
367 list = listgen; /* and again */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000368
Cyrill Gorcunovbafd8772009-10-31 20:02:14 +0300369 wsize = idata_bytes(instruction->opcode);
370 if (wsize == -1)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000371 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000372
H. Peter Anvineba20a72002-04-30 20:53:55 +0000373 if (wsize) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000374 extop *e;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000375 int32_t t = instruction->times;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000376 if (t < 0)
377 errfunc(ERR_PANIC,
378 "instruction->times < 0 (%ld) in assemble()", t);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000379
H. Peter Anvine2c80182005-01-15 22:15:51 +0000380 while (t--) { /* repeat TIMES times */
Cyrill Gorcunova92a3a52009-07-27 22:33:59 +0400381 list_for_each(e, instruction->eops) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000382 if (e->type == EOT_DB_NUMBER) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400383 if (wsize > 8) {
H. Peter Anvin3be5d852008-05-20 14:49:32 -0700384 errfunc(ERR_NONFATAL,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400385 "integer supplied to a DT, DO or DY"
Keith Kanios61ff53c2007-04-14 18:54:52 +0000386 " instruction");
H. Peter Anvin55ae1202010-05-06 15:25:43 -0700387 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000388 out(offset, segment, &e->offset,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800389 OUT_ADDRESS, wsize, e->segment, e->wrt);
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400390 offset += wsize;
391 }
H. Peter Anvin518df302008-06-14 16:53:48 -0700392 } else if (e->type == EOT_DB_STRING ||
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400393 e->type == EOT_DB_STRING_FREE) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000394 int align;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000395
H. Peter Anvine2c80182005-01-15 22:15:51 +0000396 out(offset, segment, e->stringval,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800397 OUT_RAWDATA, e->stringlen, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000398 align = e->stringlen % wsize;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000399
H. Peter Anvine2c80182005-01-15 22:15:51 +0000400 if (align) {
401 align = wsize - align;
H. Peter Anvin999868f2009-02-09 11:03:33 +0100402 out(offset, segment, zero_buffer,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800403 OUT_RAWDATA, align, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000404 }
405 offset += e->stringlen + align;
406 }
407 }
408 if (t > 0 && t == instruction->times - 1) {
409 /*
410 * Dummy call to list->output to give the offset to the
411 * listing module.
412 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800413 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000414 list->uplevel(LIST_TIMES);
415 }
416 }
417 if (instruction->times > 1)
418 list->downlevel(LIST_TIMES);
419 return offset - start;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000420 }
421
H. Peter Anvine2c80182005-01-15 22:15:51 +0000422 if (instruction->opcode == I_INCBIN) {
H. Peter Anvin518df302008-06-14 16:53:48 -0700423 const char *fname = instruction->eops->stringval;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000424 FILE *fp;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000425
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400426 fp = fopen(fname, "rb");
427 if (!fp) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000428 error(ERR_NONFATAL, "`incbin': unable to open file `%s'",
429 fname);
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400430 } else if (fseek(fp, 0L, SEEK_END) < 0) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000431 error(ERR_NONFATAL, "`incbin': unable to seek on file `%s'",
432 fname);
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400433 } else {
H. Peter Anvin518df302008-06-14 16:53:48 -0700434 static char buf[4096];
435 size_t t = instruction->times;
436 size_t base = 0;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400437 size_t len;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000438
H. Peter Anvine2c80182005-01-15 22:15:51 +0000439 len = ftell(fp);
440 if (instruction->eops->next) {
441 base = instruction->eops->next->offset;
442 len -= base;
443 if (instruction->eops->next->next &&
H. Peter Anvin518df302008-06-14 16:53:48 -0700444 len > (size_t)instruction->eops->next->next->offset)
445 len = (size_t)instruction->eops->next->next->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000446 }
447 /*
448 * Dummy call to list->output to give the offset to the
449 * listing module.
450 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800451 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000452 list->uplevel(LIST_INCBIN);
453 while (t--) {
H. Peter Anvin518df302008-06-14 16:53:48 -0700454 size_t l;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000455
H. Peter Anvine2c80182005-01-15 22:15:51 +0000456 fseek(fp, base, SEEK_SET);
457 l = len;
458 while (l > 0) {
H. Peter Anvin4a5a6df2009-06-27 16:14:18 -0700459 int32_t m;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400460 m = fread(buf, 1, l > sizeof(buf) ? sizeof(buf) : l, fp);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000461 if (!m) {
462 /*
463 * This shouldn't happen unless the file
464 * actually changes while we are reading
465 * it.
466 */
467 error(ERR_NONFATAL,
468 "`incbin': unexpected EOF while"
469 " reading file `%s'", fname);
470 t = 0; /* Try to exit cleanly */
471 break;
472 }
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800473 out(offset, segment, buf, OUT_RAWDATA, m,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000474 NO_SEG, NO_SEG);
475 l -= m;
476 }
477 }
478 list->downlevel(LIST_INCBIN);
479 if (instruction->times > 1) {
480 /*
481 * Dummy call to list->output to give the offset to the
482 * listing module.
483 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800484 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000485 list->uplevel(LIST_TIMES);
486 list->downlevel(LIST_TIMES);
487 }
488 fclose(fp);
489 return instruction->times * len;
490 }
491 return 0; /* if we're here, there's an error */
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000492 }
493
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700494 /* Check to see if we need an address-size prefix */
495 add_asp(instruction, bits);
496
H. Peter Anvin23595f52009-07-25 17:44:25 -0700497 m = find_match(&temp, instruction, segment, offset, bits);
H. Peter Anvin70653092007-10-19 14:42:29 -0700498
H. Peter Anvin23595f52009-07-25 17:44:25 -0700499 if (m == MOK_GOOD) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400500 /* Matches! */
H. Peter Anvin8cc8a1d2012-02-25 11:11:42 -0800501 int64_t insn_size = calcsize(segment, offset, bits, instruction, temp);
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400502 itimes = instruction->times;
503 if (insn_size < 0) /* shouldn't be, on pass two */
504 error(ERR_PANIC, "errors made it through from pass one");
505 else
506 while (itimes--) {
507 for (j = 0; j < MAXPREFIX; j++) {
508 uint8_t c = 0;
509 switch (instruction->prefixes[j]) {
510 case P_WAIT:
511 c = 0x9B;
512 break;
513 case P_LOCK:
514 c = 0xF0;
515 break;
516 case P_REPNE:
517 case P_REPNZ:
H. Peter Anvin4ecd5d72012-02-24 21:51:46 -0800518 case P_XACQUIRE:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400519 c = 0xF2;
520 break;
521 case P_REPE:
522 case P_REPZ:
523 case P_REP:
H. Peter Anvin4ecd5d72012-02-24 21:51:46 -0800524 case P_XRELEASE:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400525 c = 0xF3;
526 break;
527 case R_CS:
528 if (bits == 64) {
529 error(ERR_WARNING | ERR_PASS2,
530 "cs segment base generated, but will be ignored in 64-bit mode");
531 }
532 c = 0x2E;
533 break;
534 case R_DS:
535 if (bits == 64) {
536 error(ERR_WARNING | ERR_PASS2,
537 "ds segment base generated, but will be ignored in 64-bit mode");
538 }
539 c = 0x3E;
540 break;
541 case R_ES:
542 if (bits == 64) {
543 error(ERR_WARNING | ERR_PASS2,
544 "es segment base generated, but will be ignored in 64-bit mode");
545 }
546 c = 0x26;
547 break;
548 case R_FS:
549 c = 0x64;
550 break;
551 case R_GS:
552 c = 0x65;
553 break;
554 case R_SS:
555 if (bits == 64) {
556 error(ERR_WARNING | ERR_PASS2,
557 "ss segment base generated, but will be ignored in 64-bit mode");
558 }
559 c = 0x36;
560 break;
561 case R_SEGR6:
562 case R_SEGR7:
563 error(ERR_NONFATAL,
564 "segr6 and segr7 cannot be used as prefixes");
565 break;
566 case P_A16:
567 if (bits == 64) {
568 error(ERR_NONFATAL,
569 "16-bit addressing is not supported "
570 "in 64-bit mode");
571 } else if (bits != 16)
572 c = 0x67;
573 break;
574 case P_A32:
575 if (bits != 32)
576 c = 0x67;
577 break;
578 case P_A64:
579 if (bits != 64) {
580 error(ERR_NONFATAL,
581 "64-bit addressing is only supported "
582 "in 64-bit mode");
583 }
584 break;
585 case P_ASP:
586 c = 0x67;
587 break;
588 case P_O16:
589 if (bits != 16)
590 c = 0x66;
591 break;
592 case P_O32:
593 if (bits == 16)
594 c = 0x66;
595 break;
596 case P_O64:
597 /* REX.W */
598 break;
599 case P_OSP:
600 c = 0x66;
601 break;
602 case P_none:
603 break;
604 default:
605 error(ERR_PANIC, "invalid instruction prefix");
606 }
607 if (c != 0) {
608 out(offset, segment, &c, OUT_RAWDATA, 1,
609 NO_SEG, NO_SEG);
610 offset++;
611 }
612 }
613 insn_end = offset + insn_size;
614 gencode(segment, offset, bits, instruction,
615 temp, insn_end);
616 offset += insn_size;
617 if (itimes > 0 && itimes == instruction->times - 1) {
618 /*
619 * Dummy call to list->output to give the offset to the
620 * listing module.
621 */
622 list->output(offset, NULL, OUT_RAWDATA, 0);
623 list->uplevel(LIST_TIMES);
624 }
625 }
626 if (instruction->times > 1)
627 list->downlevel(LIST_TIMES);
628 return offset - start;
H. Peter Anvin23595f52009-07-25 17:44:25 -0700629 } else {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400630 /* No match */
631 switch (m) {
632 case MERR_OPSIZEMISSING:
633 error(ERR_NONFATAL, "operation size not specified");
634 break;
635 case MERR_OPSIZEMISMATCH:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000636 error(ERR_NONFATAL, "mismatch in operand sizes");
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400637 break;
638 case MERR_BADCPU:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000639 error(ERR_NONFATAL, "no instruction for this cpu level");
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400640 break;
641 case MERR_BADMODE:
H. Peter Anvin6cda4142008-12-29 20:52:28 -0800642 error(ERR_NONFATAL, "instruction not supported in %d-bit mode",
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400643 bits);
644 break;
645 default:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000646 error(ERR_NONFATAL,
647 "invalid combination of opcode and operands");
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400648 break;
649 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000650 }
651 return 0;
652}
653
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800654int64_t insn_size(int32_t segment, int64_t offset, int bits, uint32_t cp,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400655 insn * instruction, efunc error)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000656{
H. Peter Anvin3360d792007-09-11 04:16:57 +0000657 const struct itemplate *temp;
H. Peter Anvin23595f52009-07-25 17:44:25 -0700658 enum match_result m;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000659
H. Peter Anvine2c80182005-01-15 22:15:51 +0000660 errfunc = error; /* to pass to other functions */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000661 cpu = cp;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000662
Cyrill Gorcunov37575242009-08-16 12:00:01 +0400663 if (instruction->opcode == I_none)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000664 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000665
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700666 if (instruction->opcode == I_DB || instruction->opcode == I_DW ||
667 instruction->opcode == I_DD || instruction->opcode == I_DQ ||
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400668 instruction->opcode == I_DT || instruction->opcode == I_DO ||
669 instruction->opcode == I_DY) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000670 extop *e;
Cyrill Gorcunovbafd8772009-10-31 20:02:14 +0300671 int32_t isize, osize, wsize;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000672
H. Peter Anvine2c80182005-01-15 22:15:51 +0000673 isize = 0;
Cyrill Gorcunovbafd8772009-10-31 20:02:14 +0300674 wsize = idata_bytes(instruction->opcode);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000675
Cyrill Gorcunova92a3a52009-07-27 22:33:59 +0400676 list_for_each(e, instruction->eops) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000677 int32_t align;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000678
H. Peter Anvine2c80182005-01-15 22:15:51 +0000679 osize = 0;
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +0400680 if (e->type == EOT_DB_NUMBER) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000681 osize = 1;
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +0400682 warn_overflow_const(e->offset, wsize);
683 } else if (e->type == EOT_DB_STRING ||
684 e->type == EOT_DB_STRING_FREE)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000685 osize = e->stringlen;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000686
H. Peter Anvine2c80182005-01-15 22:15:51 +0000687 align = (-osize) % wsize;
688 if (align < 0)
689 align += wsize;
690 isize += osize + align;
691 }
692 return isize * instruction->times;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000693 }
694
H. Peter Anvine2c80182005-01-15 22:15:51 +0000695 if (instruction->opcode == I_INCBIN) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400696 const char *fname = instruction->eops->stringval;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000697 FILE *fp;
Cyrill Gorcunov6531d6d2009-12-05 14:04:55 +0300698 int64_t val = 0;
H. Peter Anvin518df302008-06-14 16:53:48 -0700699 size_t len;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000700
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400701 fp = fopen(fname, "rb");
702 if (!fp)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000703 error(ERR_NONFATAL, "`incbin': unable to open file `%s'",
704 fname);
705 else if (fseek(fp, 0L, SEEK_END) < 0)
706 error(ERR_NONFATAL, "`incbin': unable to seek on file `%s'",
707 fname);
708 else {
709 len = ftell(fp);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000710 if (instruction->eops->next) {
711 len -= instruction->eops->next->offset;
712 if (instruction->eops->next->next &&
H. Peter Anvin518df302008-06-14 16:53:48 -0700713 len > (size_t)instruction->eops->next->next->offset) {
714 len = (size_t)instruction->eops->next->next->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000715 }
716 }
Cyrill Gorcunov6531d6d2009-12-05 14:04:55 +0300717 val = instruction->times * len;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000718 }
Cyrill Gorcunov6531d6d2009-12-05 14:04:55 +0300719 if (fp)
720 fclose(fp);
721 return val;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000722 }
723
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700724 /* Check to see if we need an address-size prefix */
725 add_asp(instruction, bits);
726
H. Peter Anvin23595f52009-07-25 17:44:25 -0700727 m = find_match(&temp, instruction, segment, offset, bits);
728 if (m == MOK_GOOD) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400729 /* we've matched an instruction. */
730 int64_t isize;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400731 int j;
Victor van den Elzen0d268fb2010-01-24 21:24:57 +0100732
H. Peter Anvin8cc8a1d2012-02-25 11:11:42 -0800733 isize = calcsize(segment, offset, bits, instruction, temp);
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400734 if (isize < 0)
735 return -1;
736 for (j = 0; j < MAXPREFIX; j++) {
737 switch (instruction->prefixes[j]) {
738 case P_A16:
739 if (bits != 16)
740 isize++;
741 break;
742 case P_A32:
743 if (bits != 32)
744 isize++;
745 break;
746 case P_O16:
747 if (bits != 16)
748 isize++;
749 break;
750 case P_O32:
751 if (bits == 16)
752 isize++;
753 break;
754 case P_A64:
755 case P_O64:
756 case P_none:
757 break;
758 default:
759 isize++;
760 break;
761 }
762 }
763 return isize * instruction->times;
H. Peter Anvin23595f52009-07-25 17:44:25 -0700764 } else {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400765 return -1; /* didn't match any instruction */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000766 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000767}
768
H. Peter Anvin4ecd5d72012-02-24 21:51:46 -0800769static void bad_hle_warn(const insn * ins, uint8_t hleok)
770{
771 enum prefixes rep_pfx = ins->prefixes[PPS_REP];
H. Peter Anvin8cc8a1d2012-02-25 11:11:42 -0800772 enum whatwarn { w_none, w_lock, w_inval } ww;
H. Peter Anvin4ecd5d72012-02-24 21:51:46 -0800773 static const enum whatwarn warn[2][4] =
774 {
775 { w_inval, w_inval, w_none, w_lock }, /* XACQUIRE */
776 { w_inval, w_none, w_none, w_lock }, /* XRELEASE */
777 };
778 unsigned int n;
779
780 n = (unsigned int)rep_pfx - P_XACQUIRE;
781 if (n > 1)
782 return; /* Not XACQUIRE/XRELEASE */
783
H. Peter Anvin8cc8a1d2012-02-25 11:11:42 -0800784 ww = warn[n][hleok];
785 if (!is_class(MEMORY, ins->oprs[0].type))
786 ww = w_inval; /* HLE requires operand 0 to be memory */
787
788 switch (ww) {
H. Peter Anvin4ecd5d72012-02-24 21:51:46 -0800789 case w_none:
790 break;
791
792 case w_lock:
793 if (ins->prefixes[PPS_LOCK] != P_LOCK) {
H. Peter Anvin5a24fdd2012-02-25 15:10:04 -0800794 errfunc(ERR_WARNING | ERR_WARN_HLE | ERR_PASS2,
H. Peter Anvin4ecd5d72012-02-24 21:51:46 -0800795 "%s with this instruction requires lock",
796 prefix_name(rep_pfx));
797 }
798 break;
799
800 case w_inval:
H. Peter Anvin5a24fdd2012-02-25 15:10:04 -0800801 errfunc(ERR_WARNING | ERR_WARN_HLE | ERR_PASS2,
H. Peter Anvin4ecd5d72012-02-24 21:51:46 -0800802 "%s invalid with this instruction",
803 prefix_name(rep_pfx));
804 break;
805 }
806}
807
H. Peter Anvin507ae032008-10-09 15:37:10 -0700808/* Common construct */
809#define case4(x) case (x): case (x)+1: case (x)+2: case (x)+3
810
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800811static int64_t calcsize(int32_t segment, int64_t offset, int bits,
H. Peter Anvin8cc8a1d2012-02-25 11:11:42 -0800812 insn * ins, const struct itemplate *temp)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000813{
H. Peter Anvin8cc8a1d2012-02-25 11:11:42 -0800814 const uint8_t *codes = temp->code;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800815 int64_t length = 0;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000816 uint8_t c;
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000817 int rex_mask = ~0;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -0700818 int op1, op2;
H. Peter Anvin839eca22007-10-29 23:12:47 -0700819 struct operand *opx;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -0700820 uint8_t opex = 0;
H. Peter Anvin3089f7e2011-06-22 18:19:28 -0700821 enum ea_type eat;
H. Peter Anvin4ecd5d72012-02-24 21:51:46 -0800822 uint8_t hleok = 0;
H. Peter Anvin8cc8a1d2012-02-25 11:11:42 -0800823 bool lockcheck = true;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000824
H. Peter Anvine3917fc2007-11-01 14:53:32 -0700825 ins->rex = 0; /* Ensure REX is reset */
H. Peter Anvin3089f7e2011-06-22 18:19:28 -0700826 eat = EA_SCALAR; /* Expect a scalar EA */
H. Peter Anvine3917fc2007-11-01 14:53:32 -0700827
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700828 if (ins->prefixes[PPS_OSIZE] == P_O64)
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400829 ins->rex |= REX_W;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700830
H. Peter Anvine2c80182005-01-15 22:15:51 +0000831 (void)segment; /* Don't warn that this parameter is unused */
832 (void)offset; /* Don't warn that this parameter is unused */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000833
H. Peter Anvin839eca22007-10-29 23:12:47 -0700834 while (*codes) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400835 c = *codes++;
836 op1 = (c & 3) + ((opex & 1) << 2);
837 op2 = ((c >> 3) & 3) + ((opex & 2) << 1);
838 opx = &ins->oprs[op1];
839 opex = 0; /* For the next iteration */
H. Peter Anvindcffe4b2008-10-10 22:10:31 -0700840
H. Peter Anvin839eca22007-10-29 23:12:47 -0700841 switch (c) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000842 case 01:
843 case 02:
844 case 03:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400845 case 04:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000846 codes += c, length += c;
847 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700848
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400849 case 05:
850 case 06:
851 case 07:
852 opex = c;
853 break;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -0700854
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400855 case4(010):
856 ins->rex |=
857 op_rexflags(opx, REX_B|REX_H|REX_P|REX_W);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000858 codes++, length++;
859 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700860
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400861 case4(020):
862 case4(024):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000863 length++;
864 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700865
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400866 case4(030):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000867 length += 2;
868 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700869
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400870 case4(034):
H. Peter Anvin839eca22007-10-29 23:12:47 -0700871 if (opx->type & (BITS16 | BITS32 | BITS64))
872 length += (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000873 else
874 length += (bits == 16) ? 2 : 4;
875 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700876
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400877 case4(040):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000878 length += 4;
879 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700880
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400881 case4(044):
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700882 length += ins->addr_size >> 3;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000883 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700884
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400885 case4(050):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000886 length++;
887 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700888
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400889 case4(054):
Keith Kaniosb7a89542007-04-12 02:40:54 +0000890 length += 8; /* MOV reg64/imm */
891 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700892
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400893 case4(060):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000894 length += 2;
895 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700896
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400897 case4(064):
H. Peter Anvin839eca22007-10-29 23:12:47 -0700898 if (opx->type & (BITS16 | BITS32 | BITS64))
899 length += (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000900 else
901 length += (bits == 16) ? 2 : 4;
902 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700903
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400904 case4(070):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000905 length += 4;
906 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700907
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400908 case4(074):
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700909 length += 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000910 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700911
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400912 case 0172:
913 case 0173:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400914 codes++;
H. Peter Anvinc1377e92008-10-06 23:40:31 -0700915 length++;
916 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700917
H. Peter Anvincffe61e2011-07-07 17:21:24 -0700918 case4(0174):
919 length++;
920 break;
921
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400922 case4(0254):
923 length += 4;
924 break;
925
926 case4(0260):
927 ins->rex |= REX_V;
H. Peter Anvinfc561202011-07-07 16:58:22 -0700928 ins->vexreg = regval(opx);
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400929 ins->vex_cm = *codes++;
930 ins->vex_wlp = *codes++;
931 break;
932
933 case 0270:
934 ins->rex |= REX_V;
H. Peter Anvinfc561202011-07-07 16:58:22 -0700935 ins->vexreg = 0;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400936 ins->vex_cm = *codes++;
937 ins->vex_wlp = *codes++;
938 break;
939
H. Peter Anvin574784d2012-02-25 22:33:46 -0800940 case 0271:
941 case 0272:
942 case 0273:
943 hleok = c & 3;
944 break;
945
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400946 case4(0274):
947 length++;
948 break;
949
950 case4(0300):
H. Peter Anvine2c80182005-01-15 22:15:51 +0000951 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700952
H. Peter Anvine2c80182005-01-15 22:15:51 +0000953 case 0310:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400954 if (bits == 64)
955 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700956 length += (bits != 16) && !has_prefix(ins, PPS_ASIZE, P_A16);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000957 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700958
H. Peter Anvine2c80182005-01-15 22:15:51 +0000959 case 0311:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700960 length += (bits != 32) && !has_prefix(ins, PPS_ASIZE, P_A32);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000961 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700962
H. Peter Anvine2c80182005-01-15 22:15:51 +0000963 case 0312:
H. Peter Anvin70653092007-10-19 14:42:29 -0700964 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700965
Keith Kaniosb7a89542007-04-12 02:40:54 +0000966 case 0313:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400967 if (bits != 64 || has_prefix(ins, PPS_ASIZE, P_A16) ||
968 has_prefix(ins, PPS_ASIZE, P_A32))
969 return -1;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000970 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700971
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +0400972 case4(0314):
973 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -0700974
H. Peter Anvine2c80182005-01-15 22:15:51 +0000975 case 0320:
Victor van den Elzen6dfbddb2010-12-29 17:13:38 +0000976 {
977 enum prefixes pfx = ins->prefixes[PPS_OSIZE];
978 if (pfx == P_O16)
979 break;
980 if (pfx != P_none)
981 errfunc(ERR_WARNING | ERR_PASS2, "invalid operand size prefix");
982 else
983 ins->prefixes[PPS_OSIZE] = P_O16;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000984 break;
Victor van den Elzen6dfbddb2010-12-29 17:13:38 +0000985 }
H. Peter Anvin507ae032008-10-09 15:37:10 -0700986
H. Peter Anvine2c80182005-01-15 22:15:51 +0000987 case 0321:
Victor van den Elzen6dfbddb2010-12-29 17:13:38 +0000988 {
989 enum prefixes pfx = ins->prefixes[PPS_OSIZE];
990 if (pfx == P_O32)
991 break;
992 if (pfx != P_none)
993 errfunc(ERR_WARNING | ERR_PASS2, "invalid operand size prefix");
994 else
995 ins->prefixes[PPS_OSIZE] = P_O32;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000996 break;
Victor van den Elzen6dfbddb2010-12-29 17:13:38 +0000997 }
H. Peter Anvin507ae032008-10-09 15:37:10 -0700998
H. Peter Anvine2c80182005-01-15 22:15:51 +0000999 case 0322:
1000 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001001
Keith Kaniosb7a89542007-04-12 02:40:54 +00001002 case 0323:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001003 rex_mask &= ~REX_W;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001004 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001005
Keith Kaniosb7a89542007-04-12 02:40:54 +00001006 case 0324:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001007 ins->rex |= REX_W;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001008 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001009
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001010 case 0325:
1011 ins->rex |= REX_NH;
1012 break;
H. Peter Anvin9472dab2009-06-24 21:38:29 -07001013
Ben Rudiak-Gouldd7ab1f92013-02-20 23:25:54 +04001014 case 0326:
1015 break;
1016
H. Peter Anvine2c80182005-01-15 22:15:51 +00001017 case 0330:
1018 codes++, length++;
1019 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001020
H. Peter Anvine2c80182005-01-15 22:15:51 +00001021 case 0331:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001022 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001023
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001024 case 0332:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001025 case 0333:
1026 length++;
1027 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001028
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001029 case 0334:
1030 ins->rex |= REX_L;
1031 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001032
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001033 case 0335:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001034 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001035
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001036 case 0336:
H. Peter Anvin10da41e2012-02-24 20:57:04 -08001037 if (!ins->prefixes[PPS_REP])
1038 ins->prefixes[PPS_REP] = P_REP;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001039 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001040
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001041 case 0337:
H. Peter Anvin10da41e2012-02-24 20:57:04 -08001042 if (!ins->prefixes[PPS_REP])
1043 ins->prefixes[PPS_REP] = P_REPNE;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001044 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001045
H. Peter Anvine2c80182005-01-15 22:15:51 +00001046 case 0340:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001047 if (ins->oprs[0].segment != NO_SEG)
1048 errfunc(ERR_NONFATAL, "attempt to reserve non-constant"
1049 " quantity of BSS space");
1050 else
H. Peter Anvin428fd672007-11-15 10:25:52 -08001051 length += ins->oprs[0].offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001052 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001053
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001054 case 0341:
1055 if (!ins->prefixes[PPS_WAIT])
1056 ins->prefixes[PPS_WAIT] = P_WAIT;
1057 break;
H. Peter Anvinc2acf7b2009-02-21 18:22:56 -08001058
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001059 case4(0344):
H. Peter Anvinff6e12d2008-10-08 21:17:32 -07001060 length++;
1061 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001062
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001063 case 0360:
1064 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001065
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001066 case 0361:
1067 case 0362:
1068 case 0363:
1069 length++;
1070 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001071
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001072 case 0364:
1073 case 0365:
1074 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001075
Keith Kanios48af1772007-08-17 07:37:52 +00001076 case 0366:
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001077 case 0367:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001078 length++;
1079 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001080
H. Peter Anvine2c80182005-01-15 22:15:51 +00001081 case 0370:
1082 case 0371:
1083 case 0372:
1084 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001085
H. Peter Anvine2c80182005-01-15 22:15:51 +00001086 case 0373:
1087 length++;
1088 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001089
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07001090 case 0374:
1091 eat = EA_XMMVSIB;
1092 break;
1093
1094 case 0375:
1095 eat = EA_YMMVSIB;
1096 break;
1097
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001098 case4(0100):
1099 case4(0110):
1100 case4(0120):
1101 case4(0130):
1102 case4(0200):
1103 case4(0204):
1104 case4(0210):
1105 case4(0214):
1106 case4(0220):
1107 case4(0224):
1108 case4(0230):
1109 case4(0234):
1110 {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001111 ea ea_data;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001112 int rfield;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001113 opflags_t rflags;
1114 struct operand *opy = &ins->oprs[op2];
H. Peter Anvinae64c9d2008-10-25 00:41:00 -07001115
Keith Kaniosb7a89542007-04-12 02:40:54 +00001116 ea_data.rex = 0; /* Ensure ea.REX is initially 0 */
H. Peter Anvin70653092007-10-19 14:42:29 -07001117
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001118 if (c <= 0177) {
1119 /* pick rfield from operand b (opx) */
1120 rflags = regflag(opx);
1121 rfield = nasm_regvals[opx->basereg];
1122 } else {
1123 rflags = 0;
1124 rfield = c & 7;
1125 }
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07001126 if (process_ea(opy, &ea_data, bits,ins->addr_size,
1127 rfield, rflags) != eat) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001128 errfunc(ERR_NONFATAL, "invalid effective address");
1129 return -1;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001130 } else {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001131 ins->rex |= ea_data.rex;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001132 length += ea_data.size;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001133 }
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001134 }
1135 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001136
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001137 default:
1138 errfunc(ERR_PANIC, "internal instruction table corrupt"
1139 ": instruction code \\%o (0x%02X) given", c, c);
1140 break;
1141 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001142 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001143
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001144 ins->rex &= rex_mask;
H. Peter Anvin70653092007-10-19 14:42:29 -07001145
H. Peter Anvin9472dab2009-06-24 21:38:29 -07001146 if (ins->rex & REX_NH) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001147 if (ins->rex & REX_H) {
1148 errfunc(ERR_NONFATAL, "instruction cannot use high registers");
1149 return -1;
1150 }
1151 ins->rex &= ~REX_P; /* Don't force REX prefix due to high reg */
H. Peter Anvin9472dab2009-06-24 21:38:29 -07001152 }
1153
H. Peter Anvind85d2502008-05-04 17:53:31 -07001154 if (ins->rex & REX_V) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001155 int bad32 = REX_R|REX_W|REX_X|REX_B;
H. Peter Anvind85d2502008-05-04 17:53:31 -07001156
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001157 if (ins->rex & REX_H) {
1158 errfunc(ERR_NONFATAL, "cannot use high register in vex instruction");
1159 return -1;
1160 }
H. Peter Anvin421059c2010-08-16 14:56:33 -07001161 switch (ins->vex_wlp & 060) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001162 case 000:
H. Peter Anvin229fa6c2010-08-16 15:21:48 -07001163 case 040:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001164 ins->rex &= ~REX_W;
1165 break;
H. Peter Anvin229fa6c2010-08-16 15:21:48 -07001166 case 020:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001167 ins->rex |= REX_W;
1168 bad32 &= ~REX_W;
1169 break;
H. Peter Anvin421059c2010-08-16 14:56:33 -07001170 case 060:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001171 /* Follow REX_W */
1172 break;
1173 }
H. Peter Anvind85d2502008-05-04 17:53:31 -07001174
H. Peter Anvinfc561202011-07-07 16:58:22 -07001175 if (bits != 64 && ((ins->rex & bad32) || ins->vexreg > 7)) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001176 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1177 return -1;
1178 }
H. Peter Anvin3cb0e8c2010-11-16 09:36:58 -08001179 if (ins->vex_cm != 1 || (ins->rex & (REX_W|REX_X|REX_B)))
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001180 length += 3;
1181 else
1182 length += 2;
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001183 } else if (ins->rex & REX_REAL) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001184 if (ins->rex & REX_H) {
1185 errfunc(ERR_NONFATAL, "cannot use high register in rex instruction");
1186 return -1;
1187 } else if (bits == 64) {
1188 length++;
1189 } else if ((ins->rex & REX_L) &&
1190 !(ins->rex & (REX_P|REX_W|REX_X|REX_B)) &&
1191 cpu >= IF_X86_64) {
1192 /* LOCK-as-REX.R */
H. Peter Anvin10da41e2012-02-24 20:57:04 -08001193 assert_no_prefix(ins, PPS_LOCK);
H. Peter Anvin8cc8a1d2012-02-25 11:11:42 -08001194 lockcheck = false; /* Already errored, no need for warning */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001195 length++;
1196 } else {
1197 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1198 return -1;
1199 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00001200 }
H. Peter Anvin8cc8a1d2012-02-25 11:11:42 -08001201
1202 if (has_prefix(ins, PPS_LOCK, P_LOCK) && lockcheck &&
1203 (!(temp->flags & IF_LOCK) || !is_class(MEMORY, ins->oprs[0].type))) {
H. Peter Anvin5a24fdd2012-02-25 15:10:04 -08001204 errfunc(ERR_WARNING | ERR_WARN_LOCK | ERR_PASS2 ,
H. Peter Anvin8cc8a1d2012-02-25 11:11:42 -08001205 "instruction is not lockable");
1206 }
1207
H. Peter Anvin4ecd5d72012-02-24 21:51:46 -08001208 bad_hle_warn(ins, hleok);
Keith Kaniosb7a89542007-04-12 02:40:54 +00001209
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001210 return length;
1211}
Keith Kaniosb7a89542007-04-12 02:40:54 +00001212
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001213#define EMIT_REX() \
H. Peter Anvinfc561202011-07-07 16:58:22 -07001214 if (!(ins->rex & REX_V) && (ins->rex & REX_REAL) && (bits == 64)) { \
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001215 ins->rex = (ins->rex & REX_REAL)|REX_P; \
1216 out(offset, segment, &ins->rex, OUT_RAWDATA, 1, NO_SEG, NO_SEG); \
1217 ins->rex = 0; \
1218 offset += 1; \
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001219 }
1220
Charles Crayne1f8bc4c2007-11-06 18:27:23 -08001221static void gencode(int32_t segment, int64_t offset, int bits,
H. Peter Anvin833caea2008-10-04 19:02:30 -07001222 insn * ins, const struct itemplate *temp,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001223 int64_t insn_end)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001224{
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07001225 static const char condval[] = { /* conditional opcodes */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001226 0x7, 0x3, 0x2, 0x6, 0x2, 0x4, 0xF, 0xD, 0xC, 0xE, 0x6, 0x2,
1227 0x3, 0x7, 0x3, 0x5, 0xE, 0xC, 0xD, 0xF, 0x1, 0xB, 0x9, 0x5,
1228 0x0, 0xA, 0xA, 0xB, 0x8, 0x4
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001229 };
Keith Kaniosb7a89542007-04-12 02:40:54 +00001230 uint8_t c;
1231 uint8_t bytes[4];
Charles Crayne1f8bc4c2007-11-06 18:27:23 -08001232 int64_t size;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001233 int64_t data;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001234 int op1, op2;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001235 struct operand *opx;
H. Peter Anvin833caea2008-10-04 19:02:30 -07001236 const uint8_t *codes = temp->code;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001237 uint8_t opex = 0;
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07001238 enum ea_type eat = EA_SCALAR;
H. Peter Anvin70653092007-10-19 14:42:29 -07001239
H. Peter Anvin839eca22007-10-29 23:12:47 -07001240 while (*codes) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001241 c = *codes++;
1242 op1 = (c & 3) + ((opex & 1) << 2);
1243 op2 = ((c >> 3) & 3) + ((opex & 2) << 1);
1244 opx = &ins->oprs[op1];
1245 opex = 0; /* For the next iteration */
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001246
H. Peter Anvin839eca22007-10-29 23:12:47 -07001247 switch (c) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001248 case 01:
1249 case 02:
1250 case 03:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001251 case 04:
1252 EMIT_REX();
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001253 out(offset, segment, codes, OUT_RAWDATA, c, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001254 codes += c;
1255 offset += c;
1256 break;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001257
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001258 case 05:
1259 case 06:
1260 case 07:
1261 opex = c;
1262 break;
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001263
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001264 case4(010):
1265 EMIT_REX();
H. Peter Anvindcffe4b2008-10-10 22:10:31 -07001266 bytes[0] = *codes++ + (regval(opx) & 7);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001267 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001268 offset += 1;
1269 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001270
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001271 case4(020):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001272 if (opx->offset < -256 || opx->offset > 255) {
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001273 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001274 "byte value exceeds bounds");
H. Peter Anvine2c80182005-01-15 22:15:51 +00001275 }
Ben Rudiak-Gould4e8396b2013-03-01 10:28:32 +04001276 out_imm8(offset, segment, opx);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001277 offset += 1;
1278 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001279
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001280 case4(024):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001281 if (opx->offset < 0 || opx->offset > 255)
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001282 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001283 "unsigned byte value exceeds bounds");
Ben Rudiak-Gould4e8396b2013-03-01 10:28:32 +04001284 out_imm8(offset, segment, opx);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001285 offset += 1;
1286 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001287
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001288 case4(030):
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +04001289 warn_overflow_opd(opx, 2);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001290 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001291 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001292 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001293 offset += 2;
1294 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001295
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001296 case4(034):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001297 if (opx->type & (BITS16 | BITS32))
1298 size = (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001299 else
1300 size = (bits == 16) ? 2 : 4;
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +04001301 warn_overflow_opd(opx, size);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001302 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001303 out(offset, segment, &data, OUT_ADDRESS, size,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001304 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001305 offset += size;
1306 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001307
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001308 case4(040):
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +04001309 warn_overflow_opd(opx, 4);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001310 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001311 out(offset, segment, &data, OUT_ADDRESS, 4,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001312 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001313 offset += 4;
1314 break;
H. Peter Anvin3ba46772002-05-27 23:19:35 +00001315
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001316 case4(044):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001317 data = opx->offset;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001318 size = ins->addr_size >> 3;
Cyrill Gorcunov9ccabd22009-09-21 00:56:20 +04001319 warn_overflow_opd(opx, size);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001320 out(offset, segment, &data, OUT_ADDRESS, size,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001321 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001322 offset += size;
1323 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001324
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001325 case4(050):
H. Peter Anvinfea84d72010-05-06 15:32:20 -07001326 if (opx->segment != segment) {
1327 data = opx->offset;
1328 out(offset, segment, &data,
1329 OUT_REL1ADR, insn_end - offset,
1330 opx->segment, opx->wrt);
1331 } else {
1332 data = opx->offset - insn_end;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001333 if (data > 127 || data < -128)
1334 errfunc(ERR_NONFATAL, "short jump is out of range");
H. Peter Anvinfea84d72010-05-06 15:32:20 -07001335 out(offset, segment, &data,
1336 OUT_ADDRESS, 1, NO_SEG, NO_SEG);
1337 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001338 offset += 1;
1339 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001340
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001341 case4(054):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001342 data = (int64_t)opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001343 out(offset, segment, &data, OUT_ADDRESS, 8,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001344 opx->segment, opx->wrt);
Keith Kaniosb7a89542007-04-12 02:40:54 +00001345 offset += 8;
1346 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001347
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001348 case4(060):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001349 if (opx->segment != segment) {
1350 data = opx->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001351 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001352 OUT_REL2ADR, insn_end - offset,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001353 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001354 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001355 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001356 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001357 OUT_ADDRESS, 2, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001358 }
1359 offset += 2;
1360 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001361
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001362 case4(064):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001363 if (opx->type & (BITS16 | BITS32 | BITS64))
1364 size = (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001365 else
1366 size = (bits == 16) ? 2 : 4;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001367 if (opx->segment != segment) {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001368 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001369 out(offset, segment, &data,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001370 size == 2 ? OUT_REL2ADR : OUT_REL4ADR,
1371 insn_end - offset, opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001372 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001373 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001374 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001375 OUT_ADDRESS, size, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001376 }
1377 offset += size;
1378 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001379
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001380 case4(070):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001381 if (opx->segment != segment) {
1382 data = opx->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001383 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001384 OUT_REL4ADR, insn_end - offset,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001385 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001386 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001387 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001388 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001389 OUT_ADDRESS, 4, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001390 }
1391 offset += 4;
1392 break;
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001393
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001394 case4(074):
H. Peter Anvin839eca22007-10-29 23:12:47 -07001395 if (opx->segment == NO_SEG)
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001396 errfunc(ERR_NONFATAL, "value referenced by FAR is not"
1397 " relocatable");
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001398 data = 0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001399 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001400 outfmt->segbase(1 + opx->segment),
1401 opx->wrt);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001402 offset += 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001403 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001404
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001405 case 0172:
1406 c = *codes++;
1407 opx = &ins->oprs[c >> 3];
1408 bytes[0] = nasm_regvals[opx->basereg] << 4;
1409 opx = &ins->oprs[c & 7];
1410 if (opx->segment != NO_SEG || opx->wrt != NO_SEG) {
1411 errfunc(ERR_NONFATAL,
1412 "non-absolute expression not permitted as argument %d",
1413 c & 7);
1414 } else {
1415 if (opx->offset & ~15) {
1416 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
1417 "four-bit argument exceeds bounds");
1418 }
1419 bytes[0] |= opx->offset & 15;
1420 }
1421 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1422 offset++;
1423 break;
H. Peter Anvind85d2502008-05-04 17:53:31 -07001424
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001425 case 0173:
1426 c = *codes++;
1427 opx = &ins->oprs[c >> 4];
1428 bytes[0] = nasm_regvals[opx->basereg] << 4;
1429 bytes[0] |= c & 15;
1430 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1431 offset++;
1432 break;
H. Peter Anvind58656f2008-05-06 20:11:14 -07001433
H. Peter Anvincffe61e2011-07-07 17:21:24 -07001434 case4(0174):
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001435 bytes[0] = nasm_regvals[opx->basereg] << 4;
1436 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1437 offset++;
1438 break;
H. Peter Anvin52dc3532008-05-20 19:29:04 -07001439
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001440 case4(0254):
H. Peter Anvin588df782008-10-07 10:05:10 -07001441 data = opx->offset;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001442 if (opx->wrt == NO_SEG && opx->segment == NO_SEG &&
1443 (int32_t)data != (int64_t)data) {
1444 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
1445 "signed dword immediate exceeds bounds");
1446 }
1447 out(offset, segment, &data, OUT_ADDRESS, 4,
1448 opx->segment, opx->wrt);
1449 offset += 4;
H. Peter Anvin588df782008-10-07 10:05:10 -07001450 break;
1451
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001452 case4(0260):
1453 case 0270:
1454 codes += 2;
1455 if (ins->vex_cm != 1 || (ins->rex & (REX_W|REX_X|REX_B))) {
1456 bytes[0] = (ins->vex_cm >> 6) ? 0x8f : 0xc4;
1457 bytes[1] = (ins->vex_cm & 31) | ((~ins->rex & 7) << 5);
1458 bytes[2] = ((ins->rex & REX_W) << (7-3)) |
H. Peter Anvinfc561202011-07-07 16:58:22 -07001459 ((~ins->vexreg & 15)<< 3) | (ins->vex_wlp & 07);
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001460 out(offset, segment, &bytes, OUT_RAWDATA, 3, NO_SEG, NO_SEG);
1461 offset += 3;
1462 } else {
1463 bytes[0] = 0xc5;
1464 bytes[1] = ((~ins->rex & REX_R) << (7-2)) |
H. Peter Anvinfc561202011-07-07 16:58:22 -07001465 ((~ins->vexreg & 15) << 3) | (ins->vex_wlp & 07);
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001466 out(offset, segment, &bytes, OUT_RAWDATA, 2, NO_SEG, NO_SEG);
1467 offset += 2;
1468 }
1469 break;
H. Peter Anvind85d2502008-05-04 17:53:31 -07001470
H. Peter Anvine014f352012-02-25 22:35:19 -08001471 case 0271:
1472 case 0272:
1473 case 0273:
H. Peter Anvin8ea22002012-02-25 10:24:24 -08001474 break;
1475
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001476 case4(0274):
1477 {
1478 uint64_t uv, um;
1479 int s;
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001480
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001481 if (ins->rex & REX_W)
1482 s = 64;
1483 else if (ins->prefixes[PPS_OSIZE] == P_O16)
1484 s = 16;
1485 else if (ins->prefixes[PPS_OSIZE] == P_O32)
1486 s = 32;
1487 else
1488 s = bits;
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001489
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001490 um = (uint64_t)2 << (s-1);
1491 uv = opx->offset;
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001492
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001493 if (uv > 127 && uv < (uint64_t)-128 &&
1494 (uv < um-128 || uv > um-1)) {
Ben Rudiak-Gould4e8396b2013-03-01 10:28:32 +04001495 /* If this wasn't explicitly byte-sized, warn as though we
1496 * had fallen through to the imm16/32/64 case.
1497 */
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001498 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
Ben Rudiak-Gould4e8396b2013-03-01 10:28:32 +04001499 "%s value exceeds bounds",
1500 (opx->type & BITS8) ? "signed byte" :
1501 s == 16 ? "word" :
1502 s == 32 ? "dword" :
1503 "signed dword");
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001504 }
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001505 if (opx->segment != NO_SEG) {
H. Peter Anvin779ed8b2008-10-16 13:01:43 -07001506 data = uv;
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001507 out(offset, segment, &data, OUT_ADDRESS, 1,
1508 opx->segment, opx->wrt);
1509 } else {
H. Peter Anvin779ed8b2008-10-16 13:01:43 -07001510 bytes[0] = uv;
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001511 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
1512 NO_SEG);
1513 }
1514 offset += 1;
1515 break;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001516 }
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001517
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001518 case4(0300):
H. Peter Anvine2c80182005-01-15 22:15:51 +00001519 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001520
H. Peter Anvine2c80182005-01-15 22:15:51 +00001521 case 0310:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001522 if (bits == 32 && !has_prefix(ins, PPS_ASIZE, P_A16)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001523 *bytes = 0x67;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001524 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001525 offset += 1;
1526 } else
1527 offset += 0;
1528 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001529
H. Peter Anvine2c80182005-01-15 22:15:51 +00001530 case 0311:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001531 if (bits != 32 && !has_prefix(ins, PPS_ASIZE, P_A32)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001532 *bytes = 0x67;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001533 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001534 offset += 1;
1535 } else
1536 offset += 0;
1537 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001538
H. Peter Anvine2c80182005-01-15 22:15:51 +00001539 case 0312:
1540 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001541
Keith Kaniosb7a89542007-04-12 02:40:54 +00001542 case 0313:
1543 ins->rex = 0;
1544 break;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07001545
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001546 case4(0314):
1547 break;
H. Peter Anvin23440102007-11-12 21:02:33 -08001548
H. Peter Anvine2c80182005-01-15 22:15:51 +00001549 case 0320:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001550 case 0321:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001551 break;
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001552
H. Peter Anvine2c80182005-01-15 22:15:51 +00001553 case 0322:
H. Peter Anvin70653092007-10-19 14:42:29 -07001554 case 0323:
1555 break;
1556
Keith Kaniosb7a89542007-04-12 02:40:54 +00001557 case 0324:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001558 ins->rex |= REX_W;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001559 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001560
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001561 case 0325:
1562 break;
H. Peter Anvin9472dab2009-06-24 21:38:29 -07001563
Ben Rudiak-Gouldd7ab1f92013-02-20 23:25:54 +04001564 case 0326:
1565 break;
1566
H. Peter Anvine2c80182005-01-15 22:15:51 +00001567 case 0330:
1568 *bytes = *codes++ ^ condval[ins->condition];
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001569 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001570 offset += 1;
1571 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001572
H. Peter Anvine2c80182005-01-15 22:15:51 +00001573 case 0331:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001574 break;
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001575
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001576 case 0332:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001577 case 0333:
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001578 *bytes = c - 0332 + 0xF2;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001579 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001580 offset += 1;
1581 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001582
Keith Kanios48af1772007-08-17 07:37:52 +00001583 case 0334:
1584 if (ins->rex & REX_R) {
1585 *bytes = 0xF0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001586 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
Keith Kanios48af1772007-08-17 07:37:52 +00001587 offset += 1;
1588 }
1589 ins->rex &= ~(REX_L|REX_R);
1590 break;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001591
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001592 case 0335:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001593 break;
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001594
H. Peter Anvin962e3052008-08-28 17:47:16 -07001595 case 0336:
1596 case 0337:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001597 break;
H. Peter Anvin962e3052008-08-28 17:47:16 -07001598
H. Peter Anvine2c80182005-01-15 22:15:51 +00001599 case 0340:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001600 if (ins->oprs[0].segment != NO_SEG)
1601 errfunc(ERR_PANIC, "non-constant BSS size in pass two");
1602 else {
H. Peter Anvin428fd672007-11-15 10:25:52 -08001603 int64_t size = ins->oprs[0].offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001604 if (size > 0)
1605 out(offset, segment, NULL,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001606 OUT_RESERVE, size, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001607 offset += size;
1608 }
1609 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001610
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001611 case 0341:
1612 break;
H. Peter Anvinc2acf7b2009-02-21 18:22:56 -08001613
H. Peter Anvinff6e12d2008-10-08 21:17:32 -07001614 case 0344:
1615 case 0345:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001616 bytes[0] = c & 1;
H. Peter Anvinff6e12d2008-10-08 21:17:32 -07001617 switch (ins->oprs[0].basereg) {
1618 case R_CS:
1619 bytes[0] += 0x0E;
1620 break;
1621 case R_DS:
1622 bytes[0] += 0x1E;
1623 break;
1624 case R_ES:
1625 bytes[0] += 0x06;
1626 break;
1627 case R_SS:
1628 bytes[0] += 0x16;
1629 break;
1630 default:
1631 errfunc(ERR_PANIC,
1632 "bizarre 8086 segment register received");
1633 }
1634 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1635 offset++;
1636 break;
1637
1638 case 0346:
1639 case 0347:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001640 bytes[0] = c & 1;
H. Peter Anvinff6e12d2008-10-08 21:17:32 -07001641 switch (ins->oprs[0].basereg) {
1642 case R_FS:
1643 bytes[0] += 0xA0;
1644 break;
1645 case R_GS:
1646 bytes[0] += 0xA8;
1647 break;
1648 default:
1649 errfunc(ERR_PANIC,
1650 "bizarre 386 segment register received");
1651 }
1652 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1653 offset++;
1654 break;
1655
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001656 case 0360:
1657 break;
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001658
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001659 case 0361:
1660 bytes[0] = 0x66;
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001661 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1662 offset += 1;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001663 break;
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001664
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001665 case 0362:
1666 case 0363:
1667 bytes[0] = c - 0362 + 0xf2;
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001668 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1669 offset += 1;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001670 break;
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001671
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001672 case 0364:
1673 case 0365:
1674 break;
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001675
Keith Kanios48af1772007-08-17 07:37:52 +00001676 case 0366:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001677 case 0367:
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001678 *bytes = c - 0366 + 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001679 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
Keith Kanios48af1772007-08-17 07:37:52 +00001680 offset += 1;
1681 break;
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001682
H. Peter Anvine2c80182005-01-15 22:15:51 +00001683 case 0370:
1684 case 0371:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001685 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001686
H. Peter Anvine2c80182005-01-15 22:15:51 +00001687 case 0373:
1688 *bytes = bits == 16 ? 3 : 5;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001689 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001690 offset += 1;
1691 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001692
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07001693 case 0374:
1694 eat = EA_XMMVSIB;
1695 break;
1696
1697 case 0375:
1698 eat = EA_YMMVSIB;
1699 break;
1700
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001701 case4(0100):
1702 case4(0110):
1703 case4(0120):
1704 case4(0130):
1705 case4(0200):
1706 case4(0204):
1707 case4(0210):
1708 case4(0214):
1709 case4(0220):
1710 case4(0224):
1711 case4(0230):
1712 case4(0234):
1713 {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001714 ea ea_data;
1715 int rfield;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001716 opflags_t rflags;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001717 uint8_t *p;
1718 int32_t s;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001719 struct operand *opy = &ins->oprs[op2];
H. Peter Anvin70653092007-10-19 14:42:29 -07001720
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001721 if (c <= 0177) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001722 /* pick rfield from operand b (opx) */
1723 rflags = regflag(opx);
H. Peter Anvin33d5fc02008-10-23 23:07:53 -07001724 rfield = nasm_regvals[opx->basereg];
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001725 } else {
1726 /* rfield is constant */
1727 rflags = 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001728 rfield = c & 7;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001729 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001730
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07001731 if (process_ea(opy, &ea_data, bits, ins->addr_size,
Cyrill Gorcunovcdb8cd72011-08-28 16:33:39 +04001732 rfield, rflags) != eat)
H. Peter Anvine2c80182005-01-15 22:15:51 +00001733 errfunc(ERR_NONFATAL, "invalid effective address");
Charles Crayne7e975552007-11-03 22:06:13 -07001734
H. Peter Anvine2c80182005-01-15 22:15:51 +00001735 p = bytes;
1736 *p++ = ea_data.modrm;
1737 if (ea_data.sib_present)
1738 *p++ = ea_data.sib;
1739
1740 s = p - bytes;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001741 out(offset, segment, bytes, OUT_RAWDATA, s, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001742
Victor van den Elzencf9332c2008-10-01 12:18:28 +02001743 /*
1744 * Make sure the address gets the right offset in case
1745 * the line breaks in the .lst file (BR 1197827)
1746 */
1747 offset += s;
1748 s = 0;
1749
H. Peter Anvine2c80182005-01-15 22:15:51 +00001750 switch (ea_data.bytes) {
1751 case 0:
1752 break;
1753 case 1:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001754 case 2:
1755 case 4:
Victor van den Elzen352fe062008-12-10 13:04:58 +01001756 case 8:
H. Peter Anvin33d5fc02008-10-23 23:07:53 -07001757 data = opy->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001758 s += ea_data.bytes;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001759 if (ea_data.rip) {
1760 if (opy->segment == segment) {
1761 data -= insn_end;
Victor van den Elzen0d268fb2010-01-24 21:24:57 +01001762 if (overflow_signed(data, ea_data.bytes))
1763 warn_overflow(ERR_PASS2, ea_data.bytes);
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001764 out(offset, segment, &data, OUT_ADDRESS,
1765 ea_data.bytes, NO_SEG, NO_SEG);
1766 } else {
Victor van den Elzen0d268fb2010-01-24 21:24:57 +01001767 /* overflow check in output/linker? */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001768 out(offset, segment, &data, OUT_REL4ADR,
1769 insn_end - offset, opy->segment, opy->wrt);
1770 }
1771 } else {
Victor van den Elzen0d268fb2010-01-24 21:24:57 +01001772 if (overflow_general(opy->offset, ins->addr_size >> 3) ||
1773 signed_bits(opy->offset, ins->addr_size) !=
1774 signed_bits(opy->offset, ea_data.bytes * 8))
1775 warn_overflow(ERR_PASS2, ea_data.bytes);
1776
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001777 out(offset, segment, &data, OUT_ADDRESS,
1778 ea_data.bytes, opy->segment, opy->wrt);
1779 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001780 break;
Victor van den Elzen352fe062008-12-10 13:04:58 +01001781 default:
1782 /* Impossible! */
1783 errfunc(ERR_PANIC,
1784 "Invalid amount of bytes (%d) for offset?!",
1785 ea_data.bytes);
1786 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001787 }
1788 offset += s;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001789 }
1790 break;
H. Peter Anvin507ae032008-10-09 15:37:10 -07001791
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001792 default:
1793 errfunc(ERR_PANIC, "internal instruction table corrupt"
1794 ": instruction code \\%o (0x%02X) given", c, c);
1795 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001796 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001797 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001798}
1799
H. Peter Anvinf8563f72009-10-13 12:28:14 -07001800static opflags_t regflag(const operand * o)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001801{
Cyrill Gorcunov2124b7b2010-07-25 01:16:33 +04001802 if (!is_register(o->basereg))
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001803 errfunc(ERR_PANIC, "invalid operand passed to regflag()");
H. Peter Anvina4835d42008-05-20 14:21:29 -07001804 return nasm_reg_flags[o->basereg];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001805}
1806
H. Peter Anvin5b0e3ec2007-07-07 02:01:08 +00001807static int32_t regval(const operand * o)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001808{
Cyrill Gorcunov2124b7b2010-07-25 01:16:33 +04001809 if (!is_register(o->basereg))
H. Peter Anvine2c80182005-01-15 22:15:51 +00001810 errfunc(ERR_PANIC, "invalid operand passed to regval()");
H. Peter Anvina4835d42008-05-20 14:21:29 -07001811 return nasm_regvals[o->basereg];
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001812}
1813
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001814static int op_rexflags(const operand * o, int mask)
1815{
H. Peter Anvinf8563f72009-10-13 12:28:14 -07001816 opflags_t flags;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001817 int val;
1818
Cyrill Gorcunov2124b7b2010-07-25 01:16:33 +04001819 if (!is_register(o->basereg))
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001820 errfunc(ERR_PANIC, "invalid operand passed to op_rexflags()");
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001821
H. Peter Anvina4835d42008-05-20 14:21:29 -07001822 flags = nasm_reg_flags[o->basereg];
1823 val = nasm_regvals[o->basereg];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001824
1825 return rexflags(val, flags, mask);
1826}
1827
H. Peter Anvinf8563f72009-10-13 12:28:14 -07001828static int rexflags(int val, opflags_t flags, int mask)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001829{
1830 int rex = 0;
1831
1832 if (val >= 8)
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001833 rex |= REX_B|REX_X|REX_R;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001834 if (flags & BITS64)
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001835 rex |= REX_W;
1836 if (!(REG_HIGH & ~flags)) /* AH, CH, DH, BH */
1837 rex |= REX_H;
1838 else if (!(REG8 & ~flags) && val >= 4) /* SPL, BPL, SIL, DIL */
1839 rex |= REX_P;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001840
1841 return rex & mask;
1842}
1843
H. Peter Anvin23595f52009-07-25 17:44:25 -07001844static enum match_result find_match(const struct itemplate **tempp,
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001845 insn *instruction,
1846 int32_t segment, int64_t offset, int bits)
H. Peter Anvin23595f52009-07-25 17:44:25 -07001847{
1848 const struct itemplate *temp;
1849 enum match_result m, merr;
H. Peter Anvina7643f42009-10-13 12:32:20 -07001850 opflags_t xsizeflags[MAX_OPERANDS];
H. Peter Anvina81655b2009-07-25 18:15:28 -07001851 bool opsizemissing = false;
1852 int i;
1853
1854 for (i = 0; i < instruction->operands; i++)
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001855 xsizeflags[i] = instruction->oprs[i].type & SIZE_MASK;
H. Peter Anvin23595f52009-07-25 17:44:25 -07001856
1857 merr = MERR_INVALOP;
1858
1859 for (temp = nasm_instructions[instruction->opcode];
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001860 temp->opcode != I_none; temp++) {
1861 m = matches(temp, instruction, bits);
1862 if (m == MOK_JUMP) {
H. Peter Anvin8cc8a1d2012-02-25 11:11:42 -08001863 if (jmp_match(segment, offset, bits, instruction, temp))
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001864 m = MOK_GOOD;
1865 else
1866 m = MERR_INVALOP;
1867 } else if (m == MERR_OPSIZEMISSING &&
1868 (temp->flags & IF_SMASK) != IF_SX) {
1869 /*
1870 * Missing operand size and a candidate for fuzzy matching...
1871 */
1872 for (i = 0; i < temp->operands; i++) {
1873 if ((temp->opd[i] & SAME_AS) == 0)
1874 xsizeflags[i] |= temp->opd[i] & SIZE_MASK;
1875 }
1876 opsizemissing = true;
1877 }
1878 if (m > merr)
1879 merr = m;
1880 if (merr == MOK_GOOD)
1881 goto done;
H. Peter Anvina81655b2009-07-25 18:15:28 -07001882 }
1883
1884 /* No match, but see if we can get a fuzzy operand size match... */
1885 if (!opsizemissing)
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001886 goto done;
H. Peter Anvina81655b2009-07-25 18:15:28 -07001887
1888 for (i = 0; i < instruction->operands; i++) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001889 /*
1890 * We ignore extrinsic operand sizes on registers, so we should
1891 * never try to fuzzy-match on them. This also resolves the case
1892 * when we have e.g. "xmmrm128" in two different positions.
1893 */
1894 if (is_class(REGISTER, instruction->oprs[i].type))
1895 continue;
H. Peter Anvinff5d6562009-10-05 14:08:05 -07001896
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001897 /* This tests if xsizeflags[i] has more than one bit set */
1898 if ((xsizeflags[i] & (xsizeflags[i]-1)))
1899 goto done; /* No luck */
H. Peter Anvina81655b2009-07-25 18:15:28 -07001900
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001901 instruction->oprs[i].type |= xsizeflags[i]; /* Set the size */
H. Peter Anvina81655b2009-07-25 18:15:28 -07001902 }
1903
1904 /* Try matching again... */
1905 for (temp = nasm_instructions[instruction->opcode];
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001906 temp->opcode != I_none; temp++) {
1907 m = matches(temp, instruction, bits);
1908 if (m == MOK_JUMP) {
H. Peter Anvin8cc8a1d2012-02-25 11:11:42 -08001909 if (jmp_match(segment, offset, bits, instruction, temp))
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04001910 m = MOK_GOOD;
1911 else
1912 m = MERR_INVALOP;
1913 }
1914 if (m > merr)
1915 merr = m;
1916 if (merr == MOK_GOOD)
1917 goto done;
H. Peter Anvin23595f52009-07-25 17:44:25 -07001918 }
1919
H. Peter Anvina81655b2009-07-25 18:15:28 -07001920done:
H. Peter Anvin23595f52009-07-25 17:44:25 -07001921 *tempp = temp;
1922 return merr;
1923}
1924
H. Peter Anvin65289e82009-07-25 17:25:11 -07001925static enum match_result matches(const struct itemplate *itemp,
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03001926 insn *instruction, int bits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001927{
Cyrill Gorcunov167917a2012-09-10 00:19:12 +04001928 opflags_t size[MAX_OPERANDS], asize;
H. Peter Anvin3fb86f22009-07-25 19:12:10 -07001929 bool opsizemissing = false;
Cyrill Gorcunov167917a2012-09-10 00:19:12 +04001930 int i, oprs;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001931
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001932 /*
1933 * Check the opcode
1934 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001935 if (itemp->opcode != instruction->opcode)
H. Peter Anvin65289e82009-07-25 17:25:11 -07001936 return MERR_INVALOP;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001937
1938 /*
1939 * Count the operands
1940 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001941 if (itemp->operands != instruction->operands)
H. Peter Anvin65289e82009-07-25 17:25:11 -07001942 return MERR_INVALOP;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001943
1944 /*
H. Peter Anvin47fb7bc2010-08-24 13:53:22 -07001945 * Is it legal?
1946 */
1947 if (!(optimizing > 0) && (itemp->flags & IF_OPT))
1948 return MERR_INVALOP;
1949
1950 /*
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001951 * Check that no spurious colons or TOs are present
1952 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001953 for (i = 0; i < itemp->operands; i++)
1954 if (instruction->oprs[i].type & ~itemp->opd[i] & (COLON | TO))
H. Peter Anvin65289e82009-07-25 17:25:11 -07001955 return MERR_INVALOP;
H. Peter Anvin70653092007-10-19 14:42:29 -07001956
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001957 /*
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001958 * Process size flags
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001959 */
H. Peter Anvin60926242009-07-26 16:25:38 -07001960 switch (itemp->flags & IF_SMASK) {
1961 case IF_SB:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03001962 asize = BITS8;
1963 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07001964 case IF_SW:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03001965 asize = BITS16;
1966 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07001967 case IF_SD:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03001968 asize = BITS32;
1969 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07001970 case IF_SQ:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03001971 asize = BITS64;
1972 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07001973 case IF_SO:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03001974 asize = BITS128;
1975 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07001976 case IF_SY:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03001977 asize = BITS256;
1978 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07001979 case IF_SZ:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03001980 switch (bits) {
1981 case 16:
1982 asize = BITS16;
1983 break;
1984 case 32:
1985 asize = BITS32;
1986 break;
1987 case 64:
1988 asize = BITS64;
1989 break;
1990 default:
1991 asize = 0;
1992 break;
1993 }
1994 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07001995 default:
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03001996 asize = 0;
1997 break;
H. Peter Anvin60926242009-07-26 16:25:38 -07001998 }
1999
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002000 if (itemp->flags & IF_ARMASK) {
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002001 /* S- flags only apply to a specific operand */
2002 i = ((itemp->flags & IF_ARMASK) >> IF_ARSHFT) - 1;
2003 memset(size, 0, sizeof size);
2004 size[i] = asize;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002005 } else {
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002006 /* S- flags apply to all operands */
2007 for (i = 0; i < MAX_OPERANDS; i++)
2008 size[i] = asize;
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002009 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002010
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002011 /*
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002012 * Check that the operand flags all match up,
2013 * it's a bit tricky so lets be verbose:
2014 *
2015 * 1) Find out the size of operand. If instruction
2016 * doesn't have one specified -- we're trying to
2017 * guess it either from template (IF_S* flag) or
2018 * from code bits.
2019 *
2020 * 2) If template operand (i) has SAME_AS flag [used for registers only]
2021 * (ie the same operand as was specified somewhere in template, and
2022 * this referred operand index is being achieved via ~SAME_AS)
2023 * we are to be sure that both registers (in template and instruction)
2024 * do exactly match.
2025 *
2026 * 3) If template operand do not match the instruction OR
2027 * template has an operand size specified AND this size differ
2028 * from which instruction has (perhaps we got it from code bits)
2029 * we are:
2030 * a) Check that only size of instruction and operand is differ
2031 * other characteristics do match
2032 * b) Perhaps it's a register specified in instruction so
2033 * for such a case we just mark that operand as "size
2034 * missing" and this will turn on fuzzy operand size
2035 * logic facility (handled by a caller)
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002036 */
2037 for (i = 0; i < itemp->operands; i++) {
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002038 opflags_t type = instruction->oprs[i].type;
2039 if (!(type & SIZE_MASK))
2040 type |= size[i];
H. Peter Anvind85d2502008-05-04 17:53:31 -07002041
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002042 if (itemp->opd[i] & SAME_AS) {
2043 int j = itemp->opd[i] & ~SAME_AS;
2044 if (type != instruction->oprs[j].type ||
2045 instruction->oprs[i].basereg != instruction->oprs[j].basereg)
2046 return MERR_INVALOP;
Ben Rudiak-Gould4e8396b2013-03-01 10:28:32 +04002047 } else if (itemp->opd[i] & ~type & ~SIZE_MASK) {
2048 return MERR_INVALOP;
2049 } else if ((itemp->opd[i] & SIZE_MASK) &&
2050 (itemp->opd[i] & SIZE_MASK) != (type & SIZE_MASK)) {
2051 if (type & SIZE_MASK) {
H. Peter Anvin65289e82009-07-25 17:25:11 -07002052 return MERR_INVALOP;
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002053 } else if (!is_class(REGISTER, type)) {
2054 /*
2055 * Note: we don't honor extrinsic operand sizes for registers,
2056 * so "missing operand size" for a register should be
2057 * considered a wildcard match rather than an error.
2058 */
2059 opsizemissing = true;
2060 }
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002061 }
2062 }
2063
H. Peter Anvin3fb86f22009-07-25 19:12:10 -07002064 if (opsizemissing)
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002065 return MERR_OPSIZEMISSING;
H. Peter Anvin3fb86f22009-07-25 19:12:10 -07002066
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002067 /*
2068 * Check operand sizes
2069 */
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002070 if (itemp->flags & (IF_SM | IF_SM2)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002071 oprs = (itemp->flags & IF_SM2 ? 2 : itemp->operands);
H. Peter Anvine2c80182005-01-15 22:15:51 +00002072 for (i = 0; i < oprs; i++) {
Cyrill Gorcunovbc31bee2009-11-01 23:16:01 +03002073 asize = itemp->opd[i] & SIZE_MASK;
2074 if (asize) {
2075 for (i = 0; i < oprs; i++)
2076 size[i] = asize;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002077 break;
2078 }
2079 }
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002080 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002081 oprs = itemp->operands;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002082 }
2083
Keith Kaniosb7a89542007-04-12 02:40:54 +00002084 for (i = 0; i < itemp->operands; i++) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002085 if (!(itemp->opd[i] & SIZE_MASK) &&
2086 (instruction->oprs[i].type & SIZE_MASK & ~size[i]))
H. Peter Anvin65289e82009-07-25 17:25:11 -07002087 return MERR_OPSIZEMISMATCH;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002088 }
2089
H. Peter Anvinaf535c12002-04-30 20:59:21 +00002090 /*
2091 * Check template is okay at the set cpu level
2092 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002093 if (((itemp->flags & IF_PLEVEL) > cpu))
H. Peter Anvin65289e82009-07-25 17:25:11 -07002094 return MERR_BADCPU;
H. Peter Anvin70653092007-10-19 14:42:29 -07002095
Keith Kaniosb7a89542007-04-12 02:40:54 +00002096 /*
H. Peter Anvin6cda4142008-12-29 20:52:28 -08002097 * Verify the appropriate long mode flag.
Keith Kaniosb7a89542007-04-12 02:40:54 +00002098 */
H. Peter Anvin6cda4142008-12-29 20:52:28 -08002099 if ((itemp->flags & (bits == 64 ? IF_NOLONG : IF_LONG)))
H. Peter Anvin65289e82009-07-25 17:25:11 -07002100 return MERR_BADMODE;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002101
H. Peter Anvinaf535c12002-04-30 20:59:21 +00002102 /*
H. Peter Anvinfb3f4e62012-02-25 22:22:07 -08002103 * If we have a HLE prefix, look for the NOHLE flag
2104 */
2105 if ((itemp->flags & IF_NOHLE) &&
2106 (has_prefix(instruction, PPS_REP, P_XACQUIRE) ||
2107 has_prefix(instruction, PPS_REP, P_XRELEASE)))
2108 return MERR_BADHLE;
2109
2110 /*
H. Peter Anvinaf535c12002-04-30 20:59:21 +00002111 * Check if special handling needed for Jumps
2112 */
H. Peter Anvin755f5212012-02-25 11:41:34 -08002113 if ((itemp->code[0] & ~1) == 0370)
Cyrill Gorcunov1de95002009-11-06 00:08:38 +03002114 return MOK_JUMP;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002115
H. Peter Anvin60926242009-07-26 16:25:38 -07002116 return MOK_GOOD;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002117}
2118
Cyrill Gorcunov10734c72011-08-29 00:07:17 +04002119static enum ea_type process_ea(operand *input, ea *output, int bits,
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002120 int addrbits, int rfield, opflags_t rflags)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002121{
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002122 bool forw_ref = !!(input->opflags & OPFLAG_UNKNOWN);
H. Peter Anvin1c3277b2008-07-19 21:38:56 -07002123
Cyrill Gorcunov10734c72011-08-29 00:07:17 +04002124 output->type = EA_SCALAR;
2125 output->rip = false;
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00002126
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002127 /* REX flags for the rfield operand */
Cyrill Gorcunov10734c72011-08-29 00:07:17 +04002128 output->rex |= rexflags(rfield, rflags, REX_R | REX_P | REX_W | REX_H);
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002129
Cyrill Gorcunov10734c72011-08-29 00:07:17 +04002130 if (is_class(REGISTER, input->type)) {
2131 /*
2132 * It's a direct register.
2133 */
Cyrill Gorcunov2124b7b2010-07-25 01:16:33 +04002134 if (!is_register(input->basereg))
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002135 goto err;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002136
Cyrill Gorcunovc7ce6a42012-12-01 19:38:47 +04002137 if (!is_class(REG_EA, regflag(input)))
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002138 goto err;
H. Peter Anvin70653092007-10-19 14:42:29 -07002139
Cyrill Gorcunov10734c72011-08-29 00:07:17 +04002140 output->rex |= op_rexflags(input, REX_B | REX_P | REX_W | REX_H);
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002141 output->sib_present = false; /* no SIB necessary */
Cyrill Gorcunov10734c72011-08-29 00:07:17 +04002142 output->bytes = 0; /* no offset necessary either */
2143 output->modrm = GEN_MODRM(3, rfield, nasm_regvals[input->basereg]);
2144 } else {
2145 /*
2146 * It's a memory reference.
2147 */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002148 if (input->basereg == -1 &&
2149 (input->indexreg == -1 || input->scale == 0)) {
Cyrill Gorcunov10734c72011-08-29 00:07:17 +04002150 /*
2151 * It's a pure offset.
2152 */
Victor van den Elzen0d268fb2010-01-24 21:24:57 +01002153 if (bits == 64 && ((input->type & IP_REL) == IP_REL) &&
2154 input->segment == NO_SEG) {
2155 nasm_error(ERR_WARNING | ERR_PASS1, "absolute address can not be RIP-relative");
2156 input->type &= ~IP_REL;
2157 input->type |= MEMORY;
2158 }
2159
2160 if (input->eaflags & EAF_BYTEOFFS ||
2161 (input->eaflags & EAF_WORDOFFS &&
2162 input->disp_size != (addrbits != 16 ? 32 : 16))) {
2163 nasm_error(ERR_WARNING | ERR_PASS1, "displacement size ignored on absolute address");
2164 }
2165
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002166 if (bits == 64 && (~input->type & IP_REL)) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002167 output->sib_present = true;
Cyrill Gorcunov10734c72011-08-29 00:07:17 +04002168 output->sib = GEN_SIB(0, 4, 5);
2169 output->bytes = 4;
2170 output->modrm = GEN_MODRM(0, rfield, 4);
2171 output->rip = false;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002172 } else {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002173 output->sib_present = false;
Cyrill Gorcunov10734c72011-08-29 00:07:17 +04002174 output->bytes = (addrbits != 16 ? 4 : 2);
2175 output->modrm = GEN_MODRM(0, rfield, (addrbits != 16 ? 5 : 6));
2176 output->rip = bits == 64;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002177 }
Cyrill Gorcunov10734c72011-08-29 00:07:17 +04002178 } else {
2179 /*
2180 * It's an indirection.
2181 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002182 int i = input->indexreg, b = input->basereg, s = input->scale;
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002183 int32_t seg = input->segment;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002184 int hb = input->hintbase, ht = input->hinttype;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002185 int t, it, bt; /* register numbers */
2186 opflags_t x, ix, bx; /* register flags */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002187
H. Peter Anvine2c80182005-01-15 22:15:51 +00002188 if (s == 0)
2189 i = -1; /* make this easy, at least */
H. Peter Anvin70653092007-10-19 14:42:29 -07002190
Cyrill Gorcunov2124b7b2010-07-25 01:16:33 +04002191 if (is_register(i)) {
H. Peter Anvina4835d42008-05-20 14:21:29 -07002192 it = nasm_regvals[i];
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002193 ix = nasm_reg_flags[i];
2194 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002195 it = -1;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002196 ix = 0;
2197 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002198
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002199 if (is_register(b)) {
H. Peter Anvina4835d42008-05-20 14:21:29 -07002200 bt = nasm_regvals[b];
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002201 bx = nasm_reg_flags[b];
2202 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002203 bt = -1;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002204 bx = 0;
2205 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002206
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002207 /* if either one are a vector register... */
2208 if ((ix|bx) & (XMMREG|YMMREG) & ~REG_EA) {
Cyrill Gorcunov167917a2012-09-10 00:19:12 +04002209 opflags_t sok = BITS32 | BITS64;
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002210 int32_t o = input->offset;
2211 int mod, scale, index, base;
2212
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002213 /*
2214 * For a vector SIB, one has to be a vector and the other,
2215 * if present, a GPR. The vector must be the index operand.
2216 */
2217 if (it == -1 || (bx & (XMMREG|YMMREG) & ~REG_EA)) {
2218 if (s == 0)
2219 s = 1;
2220 else if (s != 1)
2221 goto err;
2222
2223 t = bt, bt = it, it = t;
2224 x = bx, bx = ix, ix = x;
2225 }
2226
2227 if (bt != -1) {
2228 if (REG_GPR & ~bx)
2229 goto err;
2230 if (!(REG64 & ~bx) || !(REG32 & ~bx))
2231 sok &= bx;
2232 else
2233 goto err;
2234 }
2235
2236 /*
2237 * While we're here, ensure the user didn't specify
2238 * WORD or QWORD
2239 */
2240 if (input->disp_size == 16 || input->disp_size == 64)
2241 goto err;
2242
2243 if (addrbits == 16 ||
2244 (addrbits == 32 && !(sok & BITS32)) ||
2245 (addrbits == 64 && !(sok & BITS64)))
2246 goto err;
2247
2248 output->type = (ix & YMMREG & ~REG_EA)
2249 ? EA_YMMVSIB : EA_XMMVSIB;
2250
2251 output->rex |= rexflags(it, ix, REX_X);
2252 output->rex |= rexflags(bt, bx, REX_B);
2253
2254 index = it & 7; /* it is known to be != -1 */
2255
2256 switch (s) {
2257 case 1:
2258 scale = 0;
2259 break;
2260 case 2:
2261 scale = 1;
2262 break;
2263 case 4:
2264 scale = 2;
2265 break;
2266 case 8:
2267 scale = 3;
2268 break;
2269 default: /* then what the smeg is it? */
2270 goto err; /* panic */
2271 }
2272
2273 if (bt == -1) {
2274 base = 5;
2275 mod = 0;
2276 } else {
2277 base = (bt & 7);
2278 if (base != REG_NUM_EBP && o == 0 &&
2279 seg == NO_SEG && !forw_ref &&
2280 !(input->eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS)))
2281 mod = 0;
2282 else if (input->eaflags & EAF_BYTEOFFS ||
2283 (o >= -128 && o <= 127 &&
2284 seg == NO_SEG && !forw_ref &&
2285 !(input->eaflags & EAF_WORDOFFS)))
2286 mod = 1;
2287 else
2288 mod = 2;
2289 }
2290
2291 output->sib_present = true;
Cyrill Gorcunov10734c72011-08-29 00:07:17 +04002292 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2293 output->modrm = GEN_MODRM(mod, rfield, 4);
2294 output->sib = GEN_SIB(scale, index, base);
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002295 } else if ((ix|bx) & (BITS32|BITS64)) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002296 /*
2297 * it must be a 32/64-bit memory reference. Firstly we have
2298 * to check that all registers involved are type E/Rxx.
2299 */
Cyrill Gorcunov167917a2012-09-10 00:19:12 +04002300 opflags_t sok = BITS32 | BITS64;
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002301 int32_t o = input->offset;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002302
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002303 if (it != -1) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002304 if (!(REG64 & ~ix) || !(REG32 & ~ix))
2305 sok &= ix;
2306 else
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002307 goto err;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002308 }
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002309
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002310 if (bt != -1) {
2311 if (REG_GPR & ~bx)
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002312 goto err; /* Invalid register */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002313 if (~sok & bx & SIZE_MASK)
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002314 goto err; /* Invalid size */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002315 sok &= bx;
2316 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002317
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002318 /*
2319 * While we're here, ensure the user didn't specify
2320 * WORD or QWORD
2321 */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002322 if (input->disp_size == 16 || input->disp_size == 64)
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002323 goto err;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002324
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002325 if (addrbits == 16 ||
2326 (addrbits == 32 && !(sok & BITS32)) ||
2327 (addrbits == 64 && !(sok & BITS64)))
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002328 goto err;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002329
Keith Kaniosb7a89542007-04-12 02:40:54 +00002330 /* now reorganize base/index */
2331 if (s == 1 && bt != it && bt != -1 && it != -1 &&
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002332 ((hb == b && ht == EAH_NOTBASE) ||
2333 (hb == i && ht == EAH_MAKEBASE))) {
2334 /* swap if hints say so */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002335 t = bt, bt = it, it = t;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002336 x = bx, bx = ix, ix = x;
2337 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00002338 if (bt == it) /* convert EAX+2*EAX to 3*EAX */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002339 bt = -1, bx = 0, s++;
2340 if (bt == -1 && s == 1 && !(hb == it && ht == EAH_NOTBASE)) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002341 /* make single reg base, unless hint */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002342 bt = it, bx = ix, it = -1, ix = 0;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002343 }
2344 if (((s == 2 && it != REG_NUM_ESP && !(input->eaflags & EAF_TIMESTWO)) ||
2345 s == 3 || s == 5 || s == 9) && bt == -1)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002346 bt = it, bx = ix, s--; /* convert 3*EAX to EAX+2*EAX */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002347 if (it == -1 && (bt & 7) != REG_NUM_ESP &&
2348 (input->eaflags & EAF_TIMESTWO))
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002349 it = bt, ix = bx, bt = -1, bx = 0, s = 1;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002350 /* convert [NOSPLIT EAX] to sib format with 0x0 displacement */
Keith Kanios48af1772007-08-17 07:37:52 +00002351 if (s == 1 && it == REG_NUM_ESP) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002352 /* swap ESP into base if scale is 1 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002353 t = it, it = bt, bt = t;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002354 x = ix, ix = bx, bx = x;
2355 }
2356 if (it == REG_NUM_ESP ||
2357 (s != 1 && s != 2 && s != 4 && s != 8 && it != -1))
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002358 goto err; /* wrong, for various reasons */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002359
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002360 output->rex |= rexflags(it, ix, REX_X);
2361 output->rex |= rexflags(bt, bx, REX_B);
Keith Kaniosb7a89542007-04-12 02:40:54 +00002362
Keith Kanios48af1772007-08-17 07:37:52 +00002363 if (it == -1 && (bt & 7) != REG_NUM_ESP) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002364 /* no SIB needed */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002365 int mod, rm;
H. Peter Anvin70653092007-10-19 14:42:29 -07002366
Keith Kaniosb7a89542007-04-12 02:40:54 +00002367 if (bt == -1) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002368 rm = 5;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002369 mod = 0;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002370 } else {
2371 rm = (bt & 7);
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002372 if (rm != REG_NUM_EBP && o == 0 &&
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002373 seg == NO_SEG && !forw_ref &&
2374 !(input->eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS)))
Keith Kaniosb7a89542007-04-12 02:40:54 +00002375 mod = 0;
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002376 else if (input->eaflags & EAF_BYTEOFFS ||
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002377 (o >= -128 && o <= 127 &&
2378 seg == NO_SEG && !forw_ref &&
2379 !(input->eaflags & EAF_WORDOFFS)))
Keith Kaniosb7a89542007-04-12 02:40:54 +00002380 mod = 1;
2381 else
2382 mod = 2;
2383 }
H. Peter Anvinea838272002-04-30 20:51:53 +00002384
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002385 output->sib_present = false;
Cyrill Gorcunov10734c72011-08-29 00:07:17 +04002386 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2387 output->modrm = GEN_MODRM(mod, rfield, rm);
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002388 } else {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002389 /* we need a SIB */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002390 int mod, scale, index, base;
H. Peter Anvin70653092007-10-19 14:42:29 -07002391
Keith Kaniosb7a89542007-04-12 02:40:54 +00002392 if (it == -1)
2393 index = 4, s = 1;
2394 else
2395 index = (it & 7);
H. Peter Anvin70653092007-10-19 14:42:29 -07002396
H. Peter Anvine2c80182005-01-15 22:15:51 +00002397 switch (s) {
2398 case 1:
2399 scale = 0;
2400 break;
2401 case 2:
2402 scale = 1;
2403 break;
2404 case 4:
2405 scale = 2;
2406 break;
2407 case 8:
2408 scale = 3;
2409 break;
2410 default: /* then what the smeg is it? */
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002411 goto err; /* panic */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002412 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002413
Keith Kaniosb7a89542007-04-12 02:40:54 +00002414 if (bt == -1) {
2415 base = 5;
2416 mod = 0;
2417 } else {
2418 base = (bt & 7);
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002419 if (base != REG_NUM_EBP && o == 0 &&
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002420 seg == NO_SEG && !forw_ref &&
2421 !(input->eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS)))
Keith Kaniosb7a89542007-04-12 02:40:54 +00002422 mod = 0;
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002423 else if (input->eaflags & EAF_BYTEOFFS ||
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002424 (o >= -128 && o <= 127 &&
2425 seg == NO_SEG && !forw_ref &&
2426 !(input->eaflags & EAF_WORDOFFS)))
Keith Kaniosb7a89542007-04-12 02:40:54 +00002427 mod = 1;
2428 else
2429 mod = 2;
2430 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002431
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002432 output->sib_present = true;
Cyrill Gorcunov10734c72011-08-29 00:07:17 +04002433 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2434 output->modrm = GEN_MODRM(mod, rfield, 4);
2435 output->sib = GEN_SIB(scale, index, base);
H. Peter Anvine2c80182005-01-15 22:15:51 +00002436 }
2437 } else { /* it's 16-bit */
2438 int mod, rm;
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002439 int16_t o = input->offset;
H. Peter Anvin70653092007-10-19 14:42:29 -07002440
Keith Kaniosb7a89542007-04-12 02:40:54 +00002441 /* check for 64-bit long mode */
2442 if (addrbits == 64)
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002443 goto err;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002444
H. Peter Anvine2c80182005-01-15 22:15:51 +00002445 /* check all registers are BX, BP, SI or DI */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002446 if ((b != -1 && b != R_BP && b != R_BX && b != R_SI && b != R_DI) ||
2447 (i != -1 && i != R_BP && i != R_BX && i != R_SI && i != R_DI))
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002448 goto err;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002449
Keith Kaniosb7a89542007-04-12 02:40:54 +00002450 /* ensure the user didn't specify DWORD/QWORD */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002451 if (input->disp_size == 32 || input->disp_size == 64)
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002452 goto err;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002453
H. Peter Anvine2c80182005-01-15 22:15:51 +00002454 if (s != 1 && i != -1)
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002455 goto err; /* no can do, in 16-bit EA */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002456 if (b == -1 && i != -1) {
2457 int tmp = b;
2458 b = i;
2459 i = tmp;
2460 } /* swap */
2461 if ((b == R_SI || b == R_DI) && i != -1) {
2462 int tmp = b;
2463 b = i;
2464 i = tmp;
2465 }
2466 /* have BX/BP as base, SI/DI index */
2467 if (b == i)
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002468 goto err; /* shouldn't ever happen, in theory */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002469 if (i != -1 && b != -1 &&
2470 (i == R_BP || i == R_BX || b == R_SI || b == R_DI))
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002471 goto err; /* invalid combinations */
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002472 if (b == -1) /* pure offset: handled above */
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002473 goto err; /* so if it gets to here, panic! */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002474
H. Peter Anvine2c80182005-01-15 22:15:51 +00002475 rm = -1;
2476 if (i != -1)
2477 switch (i * 256 + b) {
2478 case R_SI * 256 + R_BX:
2479 rm = 0;
2480 break;
2481 case R_DI * 256 + R_BX:
2482 rm = 1;
2483 break;
2484 case R_SI * 256 + R_BP:
2485 rm = 2;
2486 break;
2487 case R_DI * 256 + R_BP:
2488 rm = 3;
2489 break;
2490 } else
2491 switch (b) {
2492 case R_SI:
2493 rm = 4;
2494 break;
2495 case R_DI:
2496 rm = 5;
2497 break;
2498 case R_BP:
2499 rm = 6;
2500 break;
2501 case R_BX:
2502 rm = 7;
2503 break;
2504 }
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002505 if (rm == -1) /* can't happen, in theory */
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002506 goto err; /* so panic if it does */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002507
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002508 if (o == 0 && seg == NO_SEG && !forw_ref && rm != 6 &&
2509 !(input->eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS)))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002510 mod = 0;
H. Peter Anvinab5bd052010-07-25 12:43:30 -07002511 else if (input->eaflags & EAF_BYTEOFFS ||
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002512 (o >= -128 && o <= 127 && seg == NO_SEG &&
2513 !forw_ref && !(input->eaflags & EAF_WORDOFFS)))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002514 mod = 1;
2515 else
2516 mod = 2;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002517
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002518 output->sib_present = false; /* no SIB - it's 16-bit */
Cyrill Gorcunov10734c72011-08-29 00:07:17 +04002519 output->bytes = mod; /* bytes of offset needed */
2520 output->modrm = GEN_MODRM(mod, rfield, rm);
H. Peter Anvine2c80182005-01-15 22:15:51 +00002521 }
2522 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002523 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002524
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002525 output->size = 1 + output->sib_present + output->bytes;
H. Peter Anvin3089f7e2011-06-22 18:19:28 -07002526 return output->type;
2527
2528err:
2529 return output->type = EA_INVALID;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002530}
2531
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002532static void add_asp(insn *ins, int addrbits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002533{
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002534 int j, valid;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002535 int defdisp;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002536
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002537 valid = (addrbits == 64) ? 64|32 : 32|16;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002538
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002539 switch (ins->prefixes[PPS_ASIZE]) {
2540 case P_A16:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002541 valid &= 16;
2542 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002543 case P_A32:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002544 valid &= 32;
2545 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002546 case P_A64:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002547 valid &= 64;
2548 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002549 case P_ASP:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002550 valid &= (addrbits == 32) ? 16 : 32;
2551 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002552 default:
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002553 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002554 }
2555
2556 for (j = 0; j < ins->operands; j++) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002557 if (is_class(MEMORY, ins->oprs[j].type)) {
2558 opflags_t i, b;
H. Peter Anvin70653092007-10-19 14:42:29 -07002559
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002560 /* Verify as Register */
Cyrill Gorcunov2124b7b2010-07-25 01:16:33 +04002561 if (!is_register(ins->oprs[j].indexreg))
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002562 i = 0;
2563 else
2564 i = nasm_reg_flags[ins->oprs[j].indexreg];
H. Peter Anvin70653092007-10-19 14:42:29 -07002565
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002566 /* Verify as Register */
Cyrill Gorcunov2124b7b2010-07-25 01:16:33 +04002567 if (!is_register(ins->oprs[j].basereg))
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002568 b = 0;
2569 else
2570 b = nasm_reg_flags[ins->oprs[j].basereg];
H. Peter Anvin70653092007-10-19 14:42:29 -07002571
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002572 if (ins->oprs[j].scale == 0)
2573 i = 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002574
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002575 if (!i && !b) {
2576 int ds = ins->oprs[j].disp_size;
2577 if ((addrbits != 64 && ds > 8) ||
2578 (addrbits == 64 && ds == 16))
2579 valid &= ds;
2580 } else {
2581 if (!(REG16 & ~b))
2582 valid &= 16;
2583 if (!(REG32 & ~b))
2584 valid &= 32;
2585 if (!(REG64 & ~b))
2586 valid &= 64;
H. Peter Anvin70653092007-10-19 14:42:29 -07002587
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002588 if (!(REG16 & ~i))
2589 valid &= 16;
2590 if (!(REG32 & ~i))
2591 valid &= 32;
2592 if (!(REG64 & ~i))
2593 valid &= 64;
2594 }
2595 }
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002596 }
2597
2598 if (valid & addrbits) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002599 ins->addr_size = addrbits;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002600 } else if (valid & ((addrbits == 32) ? 16 : 32)) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002601 /* Add an address size prefix */
Cyrill Gorcunovd6851d42011-09-25 18:01:45 +04002602 ins->prefixes[PPS_ASIZE] = (addrbits == 32) ? P_A16 : P_A32;;
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002603 ins->addr_size = (addrbits == 32) ? 16 : 32;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002604 } else {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002605 /* Impossible... */
2606 errfunc(ERR_NONFATAL, "impossible combination of address sizes");
2607 ins->addr_size = addrbits; /* Error recovery */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002608 }
2609
2610 defdisp = ins->addr_size == 16 ? 16 : 32;
2611
2612 for (j = 0; j < ins->operands; j++) {
Cyrill Gorcunovd6f31242010-07-26 23:14:40 +04002613 if (!(MEM_OFFS & ~ins->oprs[j].type) &&
2614 (ins->oprs[j].disp_size ? ins->oprs[j].disp_size : defdisp) != ins->addr_size) {
2615 /*
2616 * mem_offs sizes must match the address size; if not,
2617 * strip the MEM_OFFS bit and match only EA instructions
2618 */
2619 ins->oprs[j].type &= ~(MEM_OFFS & ~MEMORY);
2620 }
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002621 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002622}